/* PEOPLE_TCP_Server.c */ /* Assignment 3 */ /* Modified by Lou Guzik IS2550 Summer 1997 */ /* http://www.pitt.edu/~lggst/ */ /* provides a people service using TCP */ #define MOD_DATE "6-15-97" #define SERVICE "cs11" /* 5011 */ #define DATA_FILE "data.tmp" #define NCONTACTS "ncontacts.tmp" #include #include #include #include #include #include #include /* for kill, signal, and kill #defines */ #include /* for wait #defines */ #include #include /* for fstat function and macros*/ #include /* for the lockf function and macros */ #include /* for open function macros */ #include #include "myprotocol.h" #define QLEN 5 #define UNIXEPOCH 2208988800 int DEBUG = FALSE; extern int errno; extern char *sys_errlist[]; int main( int, char*[] ); int TCPPeople( int ); void help( void ); void cleanup( int ); void trap( int ); /*****************************/ /* Signal Handling Functions: Brian Antonishek (antonis@ctc.com) November 5, 1995 /*****************************/ void setSignalHandlers ( ); void handleSegViol ( ); void handleBusError ( ); void handleTrap ( ); void handleInterrupt ( ); void handleSignal ( ); /* GOBAL VARS */ FILE *handle; /* DATA FILE */ FILE *contactFP; /* DATA FILE */ int msock, ssock; /* server sockets */ /*---------------------------------------------- * main - Iterative TCP server for people service *---------------------------------------------- */ int main( int argc, char *argv[] ) { int alen, i; /* from address length */ char service[SHORT_STRING] = SERVICE; /* service name or port number */ char buf[MAX_STRING]; /* "input buffer; any size */ struct sockaddr_in fsin; /* from address of client */ time_t now; /* current time */ int params = 1; /* Command Line arguments */ int Count = 0; /* Used in DEBUG Display Info Number */ int Pid; setSignalHandlers (); /**** AUTOMATICALLY PUT WHOLE PROGRAM IN BACK GROUND AS QUICKLY AS POSSIBLE, SO IF ALOT OF PROCESSES ARE STARTING AT BOOTUP, SYSTEM WILL NOT BLOCK AT THIS PROCESS! Comer page 436 ****/ if( (i = fork()) < 0 ) /* LESS THAN ONE MEANS ERROR OCCURRED */ { fprintf(stderr,"\nERROR: %d \n\t When Startup fork()\n\n", errno ); exit( 1 ); } if( i ) /* NONZERO IS PARENT */ exit( 0 ); /* NORMAL PROCESS EXIT */ /* OVERRIDE SIGNAL SIGCHLD TO POINT TO FUNCTION CLEANUP() */ signal( SIGCHLD, cleanup ); /* FIRST SPAWNED CHILD IS NOW RUNNING */ printf("\n %s -i for Instructions. \n", argv[0] ); printf("\nargc=%d", argc); for (i=0; i%d %d %s<=\n", outmsg.mode, outmsg.len, outmsg.data ); /* SEND REPLY TO CLIENT */ write(fd, &outmsg, sizeof(outmsg.mode)+sizeof(outmsg.len)+outmsg.len ); /* RECEIVE RESPONCE TO REPLY FROM CLIENT, ASSUME THAT 2 BYTES WILL BE READ */ n = read( fd, &inmsg, sizeof(inmsg)+sizeof(inmsg.len) ); if( inmsg.mode == (OK+BRIEF+FULL) ) { if( DEBUG ) printf( "TCPPeople(b/f-4) recieved OK \n" ); } else if( inmsg.mode == TERMINATE ) { printf("\n\t Server(b/f) recieved a Terminate from Client in middle Operation, returning to main()\n" ); lockf( contactFP, F_ULOCK, 0 ); lockf( handle, F_ULOCK, 0 ); return( 1 ); } else { printf("\n\t Server(b/f) recieved a Unknown Operation from Client in middle of operation, returning to main()\n" ); lockf( contactFP, F_ULOCK, 0 ); lockf( handle, F_ULOCK, 0 ); return( 1 ); } } /* while( fgets(inbuf, MAX_STRING, handle) != NULL) */ /* CLOSE THE DATA FILE */ fclose( handle ); lockf( contactFP, F_ULOCK, 0 ); lockf( handle, F_ULOCK, 0 ); /* FINISH LOADING PACKET WITH DATA TOTALS */ sprintf(inbuf, "\nTotal Contacts = %d\n", ncontacts); outmsg.mode = REPLY+BRIEF+FULL; outmsg.len = strlen(inbuf); strcpy(outmsg.data, inbuf ); if( DEBUG ) { printf( "TCPPeople(b/f-5) outbuf=>%s<=\n", outbuf ); printf( "TCPPeople(b/f-5) outmsg=>%d %d %s<=\n", outmsg.mode, outmsg.len, outmsg.data ); } /* XMIT THE COMPLETE PACKET */ write(fd, &outmsg, sizeof(outmsg.mode)+sizeof(outmsg.len)+outmsg.len ); /* STOP AND WAIT */ /* RECEIVE RESPONCE TO REPLY FROM CLIENT, ASSUME THAT 2 BYTES WILL BE READ */ n = read( fd, &inmsg, sizeof(inmsg)+sizeof(inmsg.len) ); if( inmsg.mode == (OK+BRIEF+FULL) ) { if( DEBUG ) printf( "TCPPeople(b/f-6) recieved OK \n" ); } else if( inmsg.mode == TERMINATE ) { printf("\n\t Server(b/f) recieved a Terminate from Client in middle Operation, returning to main()\n" ); return( 1 ); } else { printf("\n\t Server(b/f) recieved a Unknown Operation from Client in middle of operation, returning to main()\n" ); return( 1 ); } /* INFORM CLIENT WE ARE DONE SENDING DATA */ outmsg.mode = END_DATA+BRIEF+FULL; outmsg.len = 0; outmsg.data[0] = 0; write(fd, &outmsg, sizeof(outmsg.mode)+sizeof(outmsg.len) ); break; /* End of case BRIEF: case FULL: */ case FIND: /* OPEN THE DATA FILE */ if ( (contactFP = fopen( NCONTACTS, "r" )) == NULL) { printf( "\nError Opening TCPeople() %s file !\n", NCONTACTS ); return 2; } lockf( contactFP, F_LOCK, 0 ); fgets( inbuf, sizeof(int), contactFP ); fclose( contactFP ); ncontacts = atoi( inbuf ); if( DEBUG ) printf( "TCPPeople(find-1) ncontacts=%d\n",ncontacts ); /* START BUILDING PACKET THE XMIT */ outmsg.mode = REPLY+FIND; /* PACK NCONTACTS INTO THE LENTH FIELD */ outmsg.len = ncontacts; outmsg.data[0] = 0; if( DEBUG ) printf( "TCPPeople(find-2) outmsg=>%d %d %s<=\n", outmsg.mode, outmsg.len, outmsg.data ); /* SEND REPLY TO CLIENT */ write(fd, &outmsg, sizeof(outmsg.mode)+sizeof(outmsg.len) ); /* RECEIVE RESPONCE TO REPLY FROM CLIENT, ASSUME THAT 2 BYTES WILL BE READ */ n = read( fd, &inmsg, sizeof(inmsg)+sizeof(inmsg.len) ); if( DEBUG ) printf( "TCPPeople(find-3) n=%d inmsg=>%d %d<=\n", n, inmsg.mode, inmsg.len ); if( inmsg.mode == FIND+OK ) { if ( (handle = fopen( DATA_FILE, "r" )) == NULL) { printf( "\nError Opening TCPeople() %s file !\n", DATA_FILE ); return 2; } lockf( handle, F_LOCK, 0 ); sprintf( outbuf, "Contact # %d", inmsg.len ); if( DEBUG ) printf("TCPPeople(find-4) outbuf=%s\n", outbuf ); /* START READING DATA FROM FILE */ fgets(inbuf, MAX_STRING, handle); /* SEARCH FOR THE RECORD REQUESTED */ while( (inbuf != NULL) && (strncmp(inbuf, outbuf, strlen(outbuf)) != 0) ) { fgets(inbuf, MAX_STRING, handle); if( DEBUG) printf("TCPPeople(find-5) inbuf=%s\n", inbuf ); } if( inbuf ) { for( i=0; i<4; i++ ) { /* BUILD PACKET TO XMIT */ outmsg.mode = REPLY+FIND; outmsg.len = strlen( inbuf ); strcpy( outmsg.data, inbuf ); if( DEBUG ) printf( "TCPPeople(find-6) outmsg=>%d %d %s<=\n", outmsg.mode, outmsg.len, outmsg.data ); /* SEND REPLY TO CLIENT */ write(fd, &outmsg, sizeof(outmsg.mode)+sizeof(outmsg.len)+outmsg.len ); /* RECEIVE RESPONCE TO REPLY FROM CLIENT, ASSUME THAT 2 BYTES WILL BE READ */ n = read( fd, &inmsg, sizeof(inmsg)+sizeof(inmsg.len) ); if( inmsg.mode == OK+FIND ) { if( DEBUG ) printf( "TCPPeople(find-7) recieved OK \n" ); } else if( inmsg.mode == TERMINATE ) { printf("\n\t Server(find) recieved a Terminate from Client in middle Operation, returning to main()\n" ); lockf( handle, F_ULOCK, 0 ); return( 1 ); } else { printf("\n\t Server(find) recieved a Unknown Operation from Client in middle of operation, returning to main()\n" ); lockf( handle, F_ULOCK, 0 ); return( 1 ); } fgets(inbuf, MAX_STRING, handle); } /* for( i=0; i<4; i++ ) */ /* CLOSE THE DATA FILE */ fclose( handle ); lockf( handle, F_ULOCK, 0 ); } /* if( inbuf ) */ } /* if( inmsg.mode == FIND ) */ else if( inmsg.mode == END_DATA+FIND ) { fclose( handle ); break; } else if( inmsg.mode == TERMINATE ) { fclose( handle ); return(1); } else { fclose( handle ); printf("\n\t Server(b/f) recieved a Unknown Operation from Client in middle of operation, returning to main()\n" ); return( 1 ); } break; /* End of case FIND: */ case ADD: if ( (handle = fopen( DATA_FILE, "a+" )) == NULL) { outmsg.mode = TERMINATE; outmsg.len = 0; write(fd, &outmsg, sizeof(outmsg.mode)+sizeof(outmsg.len) ); printf( "\nError Opening TCPeople() %s file !\n", DATA_FILE ); return 4; } lockf( handle, F_LOCK, 0 ); if ( (contactFP = fopen( NCONTACTS, "r+" )) == NULL) { outmsg.mode = TERMINATE; outmsg.len = 0; write(fd, &outmsg, sizeof(outmsg.mode)+sizeof(outmsg.len) ); lockf( handle, F_ULOCK, 0 ); printf( "\nError Opening TCPeople() %s file !\n", NCONTACTS ); return 4; } lockf( contactFP, F_LOCK, 0 ); fgets( outbuf, sizeof(int), contactFP ); ncontacts = atoi( outbuf ); fseek( contactFP, 0L, SEEK_SET ); fprintf( contactFP, "%d", ++ncontacts ); fclose( contactFP ); i = 0; while( i < inmsg.len ) { n = read( fd, inbuf+i, MAX_STRING ); if( DEBUG ) { inbuf[ n+i ] = 0; printf( "TCPpeople(add-1) read of s=>%d<= i=%d n=%d buf=>%s<= \n", fd, i, n, inbuf ); /* pause(); */ } if(n < 0) errexit("socket read failed: %s\n",sys_errlist[errno]); i += n; } inbuf[ i ] = 0; fprintf( handle, "\nContact # %d: %s", ncontacts, inbuf ); fclose( handle ); lockf( contactFP, F_ULOCK, 0 ); lockf( handle, F_ULOCK, 0 ); break; /* End of case ADD */ /* CLIENT REQUEST'S SOCKET TO BE CLOSED */ case TERMINATE: return( 0 ); break; /* UNKNOWN OPERATION, CLEAN-OUT SOCKET AND CLOSE */ default: strcpy(outbuf, "\n\r Greetings, you have reached Lou Guzik's People Server"); strcat(outbuf, "\n\r Run my Client executable found at \n\r /home3/icarus.lis/misc/mbsclass/i2550/Students/guzik/assignment3 \n\r\n\r"); strcat(outbuf, "\n\r Press to disconnect \n\r\n\r"); write(fd,outbuf,strlen(outbuf)); read( fd, &inmsg, sizeof(inmsg.mode) ); return( 1 ); } /* switch( inmsg.mode ) */ } /* while( TRUE ) */ } /* int TCPPeople( int fd ) */ /*-------------------------------------------------------------------- * HELP() *-------------------------------------------------------------------- */ void help( void ) { char mod_date[ SHORT_STRING ]; strcpy( mod_date, MOD_DATE ); printf( "\n" ); printf( "\n Assignment #2 A Better Server - As of %s\n", mod_date ); printf( "Program by Lou Guzik IS2550 Summer 1997 Instructor: Dr. M. Spring \n\n" ); printf( "Command Line Arguments: \n" ); printf( " -i Shows this Screen \n" ); printf( " -d Debugging mode on \n" ); printf( " -s ? Change Default Service Port to ? \n" ); printf( "End.\n" ); } /*-------------------------------------------------------------------- * CLEANUP() /home3/icarus.lis/misc/mbsclass/i2550/Resources/Unix/fork_sig.c *-------------------------------------------------------------------- */ void cleanup(int signal) { int status; while( wait3(&status, WNOHANG, (struct rusage *)0) >= 0); } /**********************************************/ /* setSignalHandlers() - /**********************************************/ void setSignalHandlers() { /* SIGs from /usr/include/sys/signal.h */ /* Handle someone interrupting */ signal(SIGINT,handleInterrupt); /* interrupt (rubout) */ /* * Handle New Programming * Features... :-) */ signal (SIGSEGV, handleSegViol); /* segmentation violation */ signal (SIGBUS, handleBusError); /* bus error */ signal (SIGTRAP, handleTrap); /* trace trap (not reset when caught) */ /* Handle Misc. Signals */ signal(SIGHUP,handleSignal); /* hangup */ signal(SIGQUIT,handleSignal); /* quit (ASCII FS) */ signal(SIGTERM,handleSignal); /* software termination signal from kill */ } /**********************************************/ /* handleSegViol() - segmentation violation /**********************************************/ void handleSegViol() { fprintf(stderr, "\n\nGot a signal Segmentation Violation.... "); fprintf(stderr, "\nWill try to Close data file & Clean up \n\n"); /* Close Log file & Clean up */ /* DEALLOCATE SOCKET AS SOON AS POSSIBLE */ close( ssock ); close( msock ); /* DEALLOCATE FILE RESOURCE */ lockf( contactFP, F_ULOCK, 0 ); fclose( contactFP ); lockf( handle, F_ULOCK, 0 ); fclose( handle ); /* Signal will be considered 'handled' so * set default signal handler and raise another signal */ signal (SIGSEGV, SIG_DFL); /* set default seg. viol. handler */ kill (getpid (), SIGSEGV); return; } /**********************************************/ /* handleBusError() - /**********************************************/ void handleBusError() { fprintf(stderr, "\n\nGot a signal Bus Error...."); fprintf(stderr, "\nWill try to Close data file & Clean up \n\n"); /* Close Log file & Clean up */ /* DEALLOCATE SOCKET AS SOON AS POSSIBLE */ close( ssock ); close( msock ); /* DEALLOCATE FILE RESOURCE */ lockf( contactFP, F_ULOCK, 0 ); fclose( contactFP ); lockf( handle, F_ULOCK, 0 ); fclose( handle ); /* Signal will be considered 'handled' so * set default signal handler and raise another signal */ signal (SIGBUS, SIG_DFL); /* set default bus error handler */ kill (getpid (), SIGBUS); return; } /**********************************************/ /* handleTrap() - trace trap /**********************************************/ void handleTrap() { fprintf(stderr, "\n\nServer got a signal trace trap.... "); fprintf(stderr, "\nWill try to Close data file & Clean up \n\n"); /* Close Log file & Clean up */ /* DEALLOCATE SOCKET AS SOON AS POSSIBLE */ close( ssock ); close( msock ); /* DEALLOCATE FILE RESOURCE */ lockf( contactFP, F_ULOCK, 0 ); fclose( contactFP ); lockf( handle, F_ULOCK, 0 ); fclose( handle ); /* System doesn't unset this signal after we handle it * so let system handle it with its normal process, * no need to raise it again. */ signal (SIGTRAP, SIG_DFL); /* set default trace trap handler */ return; } /**********************************************/ /* handleInterrupt() - /**********************************************/ void handleInterrupt() { fprintf(stderr, "\n\n You can NOT out of server program! \n\n Press to continue."); } /**********************************************/ /* handleSignal() - /**********************************************/ void handleSignal() { fprintf(stderr, "\n\nServer got a signal to exit.... "); fprintf(stderr, "\nWill try to Close data files & Clean up sockets\n\n"); /* Close Log file & Clean up */ /* DEALLOCATE SOCKET AS SOON AS POSSIBLE */ close( ssock ); close( msock ); /* DEALLOCATE FILE RESOURCE */ lockf( contactFP, F_ULOCK, 0 ); fclose( contactFP ); lockf( handle, F_ULOCK, 0 ); fclose( handle ); /* Now exit. */ exit(0); }