Ok i need some serious help here. I have to make a TCP Server Client. When the Client connects to server using a three stage handshake. AFterwards... while the Client is running in the terminal, the user enters linux shell commands like xinput list, ls -1, ect... something that uses standard output. The server accepts the commands and uses system() (in a fork() in an infinite loop) to run the commands and the standard output is redirected to the client, where the client prints out each line.
Afterward the server sends a completion signal of "\377\n". In which the client goes back to the command prompt asking for a new command and closes its connection and exit()'s when inputting "quit".
I know that you have to dup2() both the STDOUT_FILENO and STDERR_FILENO to the clients file descriptor {dup2(client_FD, STDOUT_FILENO). Everything works except when it comes for the client to retrieve system()'s stdout and printing it out... all i get is a blank line with a blinking cursor (client waiting on stdin). I tried all kinds of different routes and extensively scoured the internet with no avail... If anyone can point me in the right direction i would greatly appreciate it
TCP SERVER CODE
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
//Prototype
void handle_client(int connect_fd);
int main()
{
int server_sockfd, client_sockfd;
socklen_t server_len, client_len;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
server_address.sin_port = htons(9734);
server_len = sizeof(server_address);
bind(server_sockfd, (struct sockaddr *)&server_address, server_len);
/* Create a connection queue, ignore child exit details and wait for clients. */
listen(server_sockfd, 10);
signal(SIGCHLD, SIG_IGN);
while(1) {
printf("server waiting\n");
client_len = sizeof(client_address);
client_sockfd = accept(server_sockfd,
(struct sockaddr *)&client_address, &client_len);
if(fork() == 0)
handle_client(client_sockfd);
else
close(client_sockfd);
}
}
void handle_client(int connect_fd) {
const char* remsh = "<remsh>\n";
const char* ready = "<ready>\n";
const char* ok = "<ok>\n";
const char* command = "<command>\n";
const char* complete = "<\377\n";
const char* shared_secret = "<shapoopi>\n";
static char server_msg[201];
static char client_msg[201];
static char commands[201];
int sys_return;
//memset client_msg, server_msg, commands
memset(&client_msg, 0, sizeof(client_msg));
memset(&server_msg, 0, sizeof(client_msg));
memset(&commands, 0, sizeof(commands));
//read remsh from client
read(connect_fd, &client_msg, 200);
//check remsh validity from client
if(strcmp(client_msg, remsh) != 0) {
errno++;
perror("Error Establishing Handshake");
close(connect_fd);
exit(1);
}
//memset client_msg
memset(&client_msg, 0, sizeof(client_msg));
//write remsh to client
write(connect_fd, remsh, strlen(remsh));
//read shared_secret from client
read(connect_fd, &client_msg, 200);
//check shared_secret validity from client
if(strcmp(client_msg, shared_secret) != 0) {
errno++;
perror("Invalid Security Passphrase");
write(connect_fd, "no", 2);
close(connect_fd);
exit(1);
}
//memset client_msg
memset(&client_msg, 0, sizeof(client_msg));
//write ok to client
write(connect_fd, ok, strlen(ok));
// dup2 STDOUT_FILENO <= client fd, STDERR_FILENO <= client fd
dup2(connect_fd, STDOUT_FILENO);
dup2(connect_fd, STDERR_FILENO);
//begin while... while read (client_msg) from server and >0
while(read(connect_fd, &client_msg, 200) > 0) {
//check command validity from client
if(strcmp(client_msg, command) != 0) {
errno++;
perror("Error, unable to retrieve data");
close(connect_fd);
exit(1);
}
//memset client_msg
memset(&client_msg, 0, sizeof(client_msg));
//write ready to client
write(connect_fd, ready, strlen(ready));
//read commands from client
read(connect_fd, &commands, 200);
//run commands using system( )
sys_return = system(commands);
//check success of system( )
if(sys_return < 0) {
perror("Invalid Commands");
errno++;
}
//memset commands
memset(commands, 0, sizeof(commands));
//write complete to client
write(connect_fd, complete, sizeof(complete));
}
}
TCP CLIENT CODE
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include "readline.c"
int main(int argc, char *argv[])
{
int sockfd;
int len;
struct sockaddr_in address;
int result;
const char* remsh = "<remsh>\n";
const char* ready = "<ready>\n";
const char* ok = "<ok>\n";
const char* command = "<command>\n";
const char* complete = "<\377\n";
const char* shared_secret = "<shapoopi>\n";
static char server_msg[201];
static char client_msg[201];
memset(&client_msg, 0, sizeof(client_msg));
memset(&server_msg, 0, sizeof(server_msg));
/* Create a socket for the client. */
sockfd = socket(AF_INET, SOCK_STREAM, 0);
/* Name the socket, as agreed with the server. */
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr(argv[1]);
address.sin_port = htons(9734);
len = sizeof(address);
/* Now connect our socket to the server's socket. */
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1) {
perror("ACCESS DENIED");
exit(1);
}
//write remsh to server
write(sockfd, remsh, strlen(remsh));
//read remsh from server
read(sockfd, &server_msg, 200);
//check remsh validity from server
if(strcmp(server_msg, remsh) != 0) {
errno++;
perror("Error Establishing Initial Handshake");
close(sockfd);
exit(1);
}
//memset server_msg
memset(&server_msg, 0, sizeof(server_msg));
//write shared secret text to server
write(sockfd, shared_secret, strlen(shared_secret));
//read ok from server
read(sockfd, &server_msg, 200);
//check ok velidity from server
if(strcmp(server_msg, ok) != 0 ) {
errno++;
perror("Incorrect security phrase");
close(sockfd);
exit(1);
}
//? dup2 STDIN_FILENO = server socket fd?
//dup2(sockfd, STDIN_FILENO);
//begin while(1)///////////////////////////////////////
while(1){
//memset both msg arrays
memset(&client_msg, 0, sizeof(client_msg));
memset(&server_msg, 0, sizeof(server_msg));
//print Enter Command, scan input, fflush to stdout
printf("<<Enter Command>> ");
scanf("%s", client_msg);
fflush(stdout);
//check quit input, if true close and exit successfully
if(strcmp(client_msg, "quit") == 0) {
printf("Exiting\n");
close(sockfd);
exit(EXIT_SUCCESS);
}
//write command to server
write(sockfd, command, strlen(command));
//read ready from server
read(sockfd, &server_msg, 200);
//check ready validity from server
if(strcmp(server_msg, ready) != 0) {
errno++;
perror("Failed Server Communications");
close(sockfd);
exit(1);
}
//memset server_msg
memset(&server_msg, 0, sizeof(server_msg));
//begin looping and retrieving from stdin,
//break loop at EOF or complete
while((read(sockfd, server_msg, 200) != 0) && (strcmp(server_msg, complete) != 0)) {
//while((fgets(server_msg, 4096, stdin) != EOF) || (strcmp(server_msg, complete) == 0)) {
printf("%s", server_msg);
memset(&server_msg, 0, sizeof(server_msg));
}
}
}
I was going through the code and tried it out on my Ubuntu machine I got the same results as described by Vincent Czubatiuk. I then decided to review the code and debug it a bit. I found two corrections were required to get it to work as expected.
1) The TCP client code has a missing line after memset server_msg where the command input through scanf is not sent to the server i.e.:
//memset server_msg
write(sockfd, client_msg, strlen(client_msg));
memset(&server_msg, 0, sizeof(server_msg));
2) With the first correction the command gets executed on the server side and the output is sent back to the client. However it is not able to proceed because system returns an error. The solution is available here C++: system(0) Returns 0. This requires the following changes:
listen(server_sockfd, 10);
//signal(SIGCHLD, SIG_IGN);
Hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With