/* TCP-based server example of socket programming. */ /* The server receives an input word (e.g., "ABBA") */ /* and figures out whether it is a palindrome or not. */ /* */ /* Usage: cc -o mypal-server mypal-server.c */ /* ./mypal-server */ /* */ /* Written by Carey Williamson January 4, 2022 */ /* Include files for C socket programming and stuff */ #include #include #include #include #include #include /* Global manifest constants */ #define MAX_MESSAGE_LENGTH 100 #define MYPORTNUM 44144 /* you can change this if you want! */ #define NO 0 #define YES 1 /* Optional verbose debugging output */ /* #define DEBUG 1 */ /* Global variable */ int childsockfd; /* This is a signal handler to do graceful exit if needed */ void catcher( int sig ) { close(childsockfd); exit(0); } /* Main program for server */ int main() { struct sockaddr_in server; static struct sigaction act; char messagein[MAX_MESSAGE_LENGTH]; char messageout[MAX_MESSAGE_LENGTH]; int parentsockfd; int i, len, bytes, answer; pid_t pid; /* Set up a signal handler to catch some weird termination conditions. */ act.sa_handler = catcher; sigfillset(&(act.sa_mask)); sigaction(SIGPIPE, &act, NULL); /* Initialize server sockaddr structure */ memset(&server, 0, sizeof(server)); server.sin_family = AF_INET; server.sin_port = htons(MYPORTNUM); server.sin_addr.s_addr = htonl(INADDR_ANY); /* create a transport-level endpoint using TCP */ parentsockfd = socket(PF_INET, SOCK_STREAM, 0); if( parentsockfd == -1 ) { fprintf(stderr, "mypal-server: socket() call failed!\n"); exit(1); } /* bind a specific address and port to the end point */ if( bind(parentsockfd, (struct sockaddr *)&server, sizeof(struct sockaddr_in) ) == -1 ) { fprintf(stderr, "mypal-server: bind() call failed!\n"); exit(1); } /* start listening for incoming connections from clients */ if( listen(parentsockfd, 5) == -1 ) { fprintf(stderr, "mypal-server: listen() call failed!\n"); exit(1); } /* initialize message strings just to be safe (null-terminated) */ bzero(messagein, MAX_MESSAGE_LENGTH); bzero(messageout, MAX_MESSAGE_LENGTH); fprintf(stderr, "Hello there! I am a server for palindrome testing!!\n"); fprintf(stderr, "I am running on TCP port %d for you...\n\n", MYPORTNUM); /* Main loop: server loops forever listening for requests */ for( ; ; ) { /* accept a connection */ childsockfd = accept(parentsockfd, NULL, NULL); if( childsockfd == -1 ) { fprintf(stderr, "mypal-server: accept() call failed!\n"); exit(1); } /* try to create a child process to deal with this new client */ pid = fork(); /* use process id (pid) returned by fork to decide what to do next */ if( pid < 0 ) { fprintf(stderr, "mypal-server: fork() call failed! OMG!!\n"); exit(1); } else if( pid == 0 ) { /* this is the child process doing this part */ /* don't need the parent listener socket that was inherited */ close(parentsockfd); /* obtain the message from this client */ bytes = recv(childsockfd, messagein, MAX_MESSAGE_LENGTH, 0); while( bytes > 0 ) { #ifdef DEBUG /* print out the received message */ printf("Server's child process received %d bytes: '%s'\n", bytes, messagein); #endif /* HACK! check for newline characters at the end from telnet clients */ if( (bytes > 0) && ((messagein[bytes-1] == '\n') || (messagein[bytes-1] == '\r')) ) { messagein[bytes-1] = '\0'; bytes--; } /* do it a second time just to be sure! */ if( (bytes > 0) && ((messagein[bytes-1] == '\n') || (messagein[bytes-1] == '\r')) ) { messagein[bytes-1] = '\0'; bytes--; } /* determine the length of the null-terminated ASCII text message */ len = strlen(messagein); #ifdef DEBUG printf("That message '%s' has %d letters!\n", messagein, len); #endif /* check for special case "EXIT" message */ if( strcmp(messagein, "EXIT") == 0 ) { fprintf(stderr, "Client process is all done now. Goodbye world!\n"); close(childsockfd); exit(0); } /* check to see if the message is a palindrome */ #ifdef DEBUG printf("Checking for palindrome property now...\n"); #endif answer = YES; for( i = 0; i < len; i++, len-- ) { if( messagein[i] != messagein[len-1] ) { answer = NO; #ifdef DEBUG printf("Nope! messagein[%d]='%c' != messagein[%d]='%c'\n", i, messagein[i], len-1, messagein[len-1]); #endif break; } else { #ifdef DEBUG printf(" messagein[%d]='%c' == messagein[%d]='%c'\n", i, messagein[i], len-1, messagein[len-1]); #endif } } /* create the outgoing message (as an ASCII string) */ if( answer == YES ) sprintf(messageout, "Yes, that is a palindrome. Well done!\n"); else sprintf(messageout, "Sorry, but that is NOT a palindrome. Please try again.\n"); #ifdef DEBUG printf("Server's child process about to send message: %s\n", messageout); #endif /* send the result message back to the client */ bytes = send(childsockfd, messageout, strlen(messageout), 0); if( bytes < 0 ) { fprintf(stderr, "mypal-server: send() failed! OMG!!\n"); } /* clear out message strings again to be safe */ bzero(messagein, MAX_MESSAGE_LENGTH); bzero(messageout, MAX_MESSAGE_LENGTH); /* check for the next message from this client */ bytes = recv(childsockfd, messagein, MAX_MESSAGE_LENGTH, 0); } /* when client is no longer sending information to us, */ /* the socket can be closed and the child process terminated */ fprintf(stderr, "Child process received nothing, so it is exiting now\n"); close(childsockfd); exit(0); } /* end of then part for child */ else { /* the parent process is the one doing this part */ fprintf(stderr, "Server created child process %d to handle that client\n", pid); fprintf(stderr, "Main server process going back to listening for new clients now...\n\n"); /* parent doesn't need the childsockfd */ close(childsockfd); } } }