/* Andrea James (aaj8) CS35010 Assignment 26 March 1998 Drink Server Code for sockets taken from class notes */ #include #include #include #include #include #include #include #include #include #include #include /* Port number for aaj8*/ #define PORT 4265 /* A function to establish a socket */ int establish (unsigned short port); /* A function to accept connections on a socket */ int get_connection (int s); /* A structure to hold information about a drink from the database */ typedef struct drinkstruct {char name [80]; /*Name of drink*/ char firsting [80]; /*First liquid ingredient*/ char secing [80]; /*Second liquid ingredient*/ char decoration [80]; /*Drink decoration*/ char mystery [80]; /*Mystery ingredient*/} drink; /* A linked list structure that stores the contents of the drink database */ typedef struct liststruct {char number [5]; /*An identifier for the drink*/ drink this_drink; /*Information on the drink */ struct liststruct *next; /*Pointer to next drink in the list*/} drink_list; /*Creates a new node in the linked list*/ drink_list *CreateDrink (char number [], char text1[], char text2[], char text3[], char text4[], char text5[], drink_list *next); /*Builds a linked list of drinks based on a text file database*/ drink_list *BuildList (FILE *drinkdb); /*Searches the list, matching key to the drink's identifier*/ drink_list *SearchList (drink_list *list, char key[]); /*A small function which returns true if the strings are the same *(Note: strcmp() did not seem to work well in this program.) */ int IsMatch (char x[], char y[]); /*A function that returns a value from the list of drinks based on a command given *the server from the client*/ char * ExecuteCommand (char message[], drink_list *list); /*Reads a line of text from the text file*/ void ReadLine (FILE *somefile, char *text); /*Converts an integer (up to 4 digits) into a character string which displays *the same value as the integer. For use with passing messages from server to client*/ void ConvertIntToChar (char *the_string, int number); /*An inverse function for ConvertIntToChar() */ int ConvertCharToInt (char *the_string); /*A global variable that points to the last node in the linked list*/ drink_list *last; /*MAIN PROGRAM*/ void main () { int s, t, x, y; /*s and t are used for sockets. x and y are used for messaging*/ char input[5], buffer[40]; /*used to manipulate the messaging character strings*/ char *output; /*same as above*/ drink_list *the_drinks; /*the linked list to hold the drinks information*/ FILE *drinks_info; /*a file variable for loading the database*/ /*load in db of drinks and store in a linked list*/ drinks_info = fopen ("drinks.txt", "r"); the_drinks=BuildList (drinks_info); fclose (drinks_info); /*get initial contact*/ if ( (s=establish(PORT)) < 0 ) {perror("Establish failed"); exit(1);} printf("Control socket is %d\n", s); /*infinite loop*/ while (1) { /*call get_connection to wait for a call from a client*/ if ( (t=get_connection(s)) < 0 ) {if (errno == EINTR) continue; perror("Accept failed"); exit(1);} printf ("Incoming on socket %d\n", t); /*read in message from client*/ read (t, input, 5); printf ("Data <%s> read from client.\n", input); /*determine command in the message and output appropriate reply*/ output = ExecuteCommand (input, the_drinks); strcpy (buffer, output); printf ("Returning value <%s> to client.\n", buffer); y=strlen(buffer); x=write (t, buffer, y); /*close socket*/ close(t); } } int establish (unsigned short port) { struct utsname uts_struct; int s; struct sockaddr_in sa; struct hostent *hp; /*find name of the host machine*/ uname(&uts_struct); printf ("Hostname %s\n", uts_struct.nodename); /*get address information for the host machine*/ hp=gethostbyname(uts_struct.nodename); if ( hp == NULL ) return (-1); /*clear address structure*/ memset ( &sa, 0, sizeof(struct sockaddr_in) ); /*copy IP address of host to sockaddr_in structure*/ memcpy ( &sa.sin_addr, *hp->h_addr_list, sizeof(sa.sin_addr) ); /*put address type into sockaddr_in structure*/ sa.sin_family = hp->h_addrtype; /*put port number into sockaddr_in structure*/ sa.sin_port = htons(port); /*create socket*/ if ( (s=socket(AF_INET, SOCK_STREAM, 0)) < 0 ) return (-1); /*bind socket to address*/ if ( (bind(s, (struct sockaddr *)&sa, sizeof(sa))) < 0 ) return (-1); /*define number of connections and return socket*/ listen (s, 1); return (s); } int get_connection (int s) { struct sockaddr_in sa; int i, t; /*Wait for and accept a connection over the socket*/ i=sizeof(sa); if ( (t=accept(s, (struct sockaddr *)&sa, &i)) < 0 ) return (-1); return (t); } drink_list *CreateDrink (char number [], char text1[], char text2[], char text3[], char text4[], char text5[], drink_list *next) { drink_list *temp; /*temporary pointer*/ /*Allocate space in memory for the node*/ temp = (drink_list *)malloc(sizeof(drink_list)); /*copy information into the structure*/ strcpy (temp->number, number); strcpy (temp->this_drink.name, text1); strcpy (temp->this_drink.firsting, text2); strcpy (temp->this_drink.secing, text3); strcpy (temp->this_drink.decoration, text4); strcpy (temp->this_drink.mystery, text5); temp->next=next; /*return a pointer to the new node*/ return temp; } drink_list *SearchList (drink_list *list, char key[]) { drink_list *temp=NULL; /*set up a temporary pointer*/ /*If the key matches, set pointer to current node*/ if (IsMatch (list->number, key)) temp=list; /*Otherwise, look through the rest of the list*/ else if (list->next != NULL) temp=(SearchList (list->next, key)); /*return the pointer (is NULL if no match is found)*/ return temp; } drink_list *BuildList (FILE *drinkdb) { drink_list *start=NULL; /*a points to the beginning of the list*/ char test; /*a variable to check for the start of a new record*/ /*temporary storage for information from the text file*/ char text1[5], text2[80], text3[80], text4[80], text5[80], text6[80]; do { test=getc(drinkdb); /*If there is a new record in the file, read in the information and copy it *into a new list node*/ if (test=='*') {ReadLine (drinkdb, text1); ReadLine (drinkdb, text2); ReadLine (drinkdb, text3); ReadLine (drinkdb, text4); ReadLine (drinkdb, text5); ReadLine (drinkdb, text6); start=CreateDrink (text1, text2, text3, text4, text5, text6, NULL); /*sets global variable last to point to last node in the list*/ last=start; /*build the rest of the list*/ start->next=BuildList(drinkdb);} } while (!feof(drinkdb)); /*returns pointer to start of the list (is NULL if the file was empty)*/ return start; } int IsMatch (char x[], char y[]) /*to determine matches between identifiers stored in struct liststruct->number*/ { int i, matches=0; /*i is a loop variable. matches holds the number of matches *between the 2 keys*/ /*loop through the strings and compare each character; count number of matches*/ for (i=0; i < 3; i++) {if (x[i]==y[i]) matches++; } /*returns TRUE (1) if all characters matched. Returns FALSE (0) otherwise*/ return (matches==3); } char *ExecuteCommand (char message[], drink_list *list) /*char message[] is a parameter which passes a message from the client to the *server requesting information about the drinks available. *drink_list *list is a pointer to the current list of drinks*/ { drink_list *temp; /*A temporary pointer*/ char *return_value; /*holds a message which is output to a client*/ char result[50]; /*holds a part of the message, the number of characters *the rest of the message*/ /*find the record asked for by the client*/ temp=SearchList (list, message+1); /*determines the appropriate response to the message sent by the client.*/ switch (message[0]) { case 'N' : case 'n' : if (temp==NULL) {ConvertIntToChar(result, 19); return_value= strcat(result, "Bad Record Number\n\0");} else { ConvertIntToChar(result, strlen(temp->this_drink.name)); return_value = strcat(result, temp->this_drink.name);} break; case 'I' : case 'i' : if (temp==NULL) {ConvertIntToChar(result, 19); return_value= strcat(result, "Bad Record Number\n\0");} else { ConvertIntToChar(result, strlen(temp->this_drink.firsting)); return_value = strcat(result, temp->this_drink.firsting);} break; case 'B' : case 'b' : if (temp==NULL) {ConvertIntToChar(result, 19); return_value= strcat(result, "Bad Record Number\n\0");} else { ConvertIntToChar(result, strlen(temp->this_drink.secing)); return_value = strcat(result, temp->this_drink.secing);} break; case 'D' : case 'd' : if (temp==NULL) {ConvertIntToChar(result, 19); return_value= strcat(result, "Bad Record Number\n\0");} else {ConvertIntToChar(result, strlen(temp->this_drink.decoration)); return_value = strcat(result, temp->this_drink.decoration);} break; case 'M' : case 'm' : if (temp==NULL) {ConvertIntToChar(result, 19); return_value= strcat(result, "Bad Record Number\n\0");} else { ConvertIntToChar(result, strlen(temp->this_drink.mystery)); return_value = strcat(result, temp->this_drink.mystery);} break; case 'R' : case 'r' : ConvertIntToChar(result, 5); return_value = strcat(result, last->number); break; default : ConvertIntToChar(result, 12); return_value= strcat(result, "Bad Selector\n\0"); } /*test code printf ("Testing ExecuteCommand function.\nreturn_value=%s", return_value); */ /*return the message to the client*/ return (return_value); } void ReadLine (FILE *somefile, char *text) /*read in a line of text until a linefeed character is hit*/ { int i=0; char current; do { current=getc (somefile); text[i]=current; i++; } while ((current != '\n') && (!feof(somefile))); text[i]='\0'; } void ConvertIntToChar (char *the_string, int number) /*convert an integer (up to 4 digits) into a character equivalent. *Based on ASCII codes.*/ { int temp; temp=number/1000; the_string[0]=(char)(temp+48); temp=(number/100)-(number/1000*10); the_string[1]=(char)(temp+48); temp=(number/10)-(number/100*10); the_string[2]=(char)(temp+48); temp=number-(number/10*10); the_string[3]=(char)(temp+48); the_string[4]='\0'; } int ConvertCharToInt (char *the_string) /*convert a string of characters representing a 4-digit number *into an integer equivalent. Based on ASCII codes.*/ { int temp=0; temp = ( ((int)the_string[0]) - 48)*1000; temp += ( ((int)the_string[1]) - 48)*100; temp += ( ((int)the_string[2]) - 48)*10; temp += ( ((int)the_string[3]) - 48); return temp; }