/****************************************************************************** * this program is developed by bhavani prasad sangannagari * * standard routines for socket interface are copied from comer * * * concept of reader writer problem is followed i.e. when writer writes when no* * reader is reading and also writer waits till reader reads * * concept of bouded waiting is not implemented since no of clients r atmost 3 * * server uploads a file into structure and reloads into file while quiting * * 1.Lists all books available to check out with the no copies still available * * 2. searches book a).by ISBN b).by book title c). checks for multiple * * books for same title * * 3. server verifies if no of still available is > than checked out * * 4. server asks to quit if last client is about to quit * * 5. allows user to modify default port * * * ****************************************************************************/ /**************************************************************************** * main threads () * master socket waits for incoming connection and assigns client to slave socket * * by starting a new thread, TCPlib routine performs the remaining task except * * error routines * * tried to handle concurrency with help of global variable gcon * *********************************************************************************/ #include #include #include #include #include #include #include #include #define QLEN 5 #define STKSIZE 16536 #define BUFSIZE 100 #define WSVERS MAKEWORD(2,0) SOCKET msock, ssock; u_short portbase = 0; void TCPlib(SOCKET); void errexit(const char *, ...); SOCKET passivesock(const char *, const char *,int); // globalstructure to upload a file struct libdatbase { char booktitle[20]; char lname[20]; char fname[20]; char ISBN[15]; int available; int checkedout; int stillavail; }; struct libdatbase lib[30]; // structure to hold the records int grecno=0,nothread=0; // grecno shows no of records in file // nothread shows no of active threads at present int gcon = 0; // global variable to control concurrency // gcon = 0 structure not being accessed by any client // gcon = 1 structure being accessed by some client // HANDLE hmutex[2]; int main(int argc, char *argv[]) { char *service = "2003"; char *transport = "tcp"; struct sockaddr_in fsin; WSADATA wsadata; int alen; char lrecord[64]; char *token; FILE *fp; // hmutex[0] = CreateMutex(NULL,FALSE,TEXT("Mutex1")); // hmutex[1] = CreateMutex(NULL,FALSE,TEXT("Mutex2")); // if (hmutex[0] == NULL) // { // Check for error. // cout << "Couldn't create mutex" << endl; // exit(1); // } if (argc == 2) { // check if user mentions the port service = argv[1]; } fp=fopen("lib_dat.csv","r"); if (fp == NULL) { printf("cannot open file"); exit(1); } // while loop uploads a file in to structure while(!feof(fp)) { fgets(lrecord,100,fp); //retrive one line from file token = strtok( lrecord, "," ); while( token != NULL ) { strcpy(lib[grecno].booktitle,token); token=strtok(NULL,","); strcpy(lib[grecno].lname,token); token=strtok(NULL,","); strcpy(lib[grecno].fname,token); token=strtok(NULL,","); strcpy(lib[grecno].ISBN,token); token=strtok(NULL,","); lib[grecno].available = atoi(token); token=strtok(NULL,","); lib[grecno].checkedout = atoi(token); token=strtok(NULL,","); if (lib[grecno].available > lib[grecno].checkedout) lib[grecno].stillavail = lib[grecno].available - lib[grecno].checkedout; else lib[grecno].stillavail = 0; grecno ++; } } // end while (!feof(fp)) fclose(fp); if (WSAStartup(WSVERS, &wsadata) != 0) errexit("WSAStartup failed\n"); msock = passivesock(service, transport, QLEN); //this loop blocks self(at master socket) in listen mode until a client request arrives while (1) { alen = sizeof(fsin); // master socket assigning client to slave socket ssock = accept(msock, (struct sockaddr *) &fsin, &alen); if (ssock == INVALID_SOCKET) errexit("accept: error number \n", GetLastError()); // beginning a new thread for the client if (_beginthread((void (*) (void *) ) TCPlib, STKSIZE, (void *)ssock) < 0) errexit("_beginthread: %s\n", strerror(errno)); nothread++; printf("\n client %d request recieved",nothread); } return 1; } /********************************************************************************** TCPlib () : * this routine performes the basic fuctions of the server as mentions in comments * * except 5. which is done by main() i.e. of port * * depending on the nature of clients requests particular option in switch is done * ************************************************************************************ */ void TCPlib(SOCKET fd) { char recvbuf[BUFSIZE]; char sendbuf[BUFSIZE]; char c,temp[4]="",string1[20]=""; int rc,i,sleep=0; FILE *fp; memset(recvbuf,'0',BUFSIZE); memset(sendbuf,0,sizeof sendbuf); printf("\n waiting to recieve "); rc= recv(ssock,recvbuf,BUFSIZE,0); if (rc<0) { fprintf(stderr, "recv() failed\n %d\n", GetLastError()); closesocket(ssock); exit(1); } //declaring 2 one mutex is used by reader and other by writer // since when one reader is reading other can also read but not for writer // hmutex[0] = OpenMutex(MUTEX_ALL_ACCESS, 0, "Mutex1"); // hmutex[1] = OpenMutex(MUTEX_ALL_ACCESS, 0, "Mutex2"); while(1) { c = recvbuf[0]; switch(c) { case '1': /************************************************************** * checks global and then sends data to client each iteration * **************************************************************/ for(i = 1; i 0) { int x; printf(" YOU CAN EXAMINE CONCURRENCY BY RUNNING OTHER CLIENT"); for(x = 0; x<20;x++){ printf("this should print two lines from server"); Sleep(1000); } lib[i].checkedout = lib[i].checkedout + 1; lib[i].stillavail = lib[i].stillavail - 1; _itoa(lib[i].checkedout,temp,10); strcat(sendbuf,temp); strcat(sendbuf,","); _itoa(lib[i].stillavail,temp,10); gcon = 0; // ReleaseMutex(hmutex[1]); strcat(sendbuf,temp); strcat(sendbuf,","); strcat(sendbuf,"BOOK CHECKOUT SUCCESSFUL"); strcat(sendbuf,"\n"); } else { _itoa(lib[i].checkedout,temp,10); strcat(sendbuf,temp); strcat(sendbuf,","); _itoa(lib[i].stillavail,temp,10); gcon = 0; // ReleaseMutex(hmutex[1]); strcat(sendbuf,temp); strcat(sendbuf,","); strcat(sendbuf,"NO MORE COPIES AVAILABLE CANNOT CHECKOUT"); strcat(sendbuf,"\n"); } printf("\nThe record found is:-\n\n %s",sendbuf); rc=send(ssock,sendbuf,BUFSIZE,0); if (rc<0) { fprintf(stderr, "Error in sending message to the client %d\n", GetLastError()); closesocket(ssock); exit(1); } break; } gcon = 0; // ReleaseMutex(hmutex[1]); }// end for rc=send(ssock,"1",1,0); if (rc<0) { fprintf(stderr, "Error in sending message to the client %d\n", GetLastError()); closesocket(ssock); exit(1); } break; case '4': /************************************************************************* * if last thread running on server ends this asks user if to discontinue* * the server if y is pressed terminates the server by writing the file * * on to the disk * *************************************************************************/ printf("\nServer Quited for this client......"); nothread--; if (nothread == 0) { char c; printf("\nThere are no clients running on server press 'y' to quit server :"); flushall(); c = getchar(); flushall(); if (c == 'y') { fp=fopen("lib_dat.csv","r+"); if (fp == NULL) { printf("cannot update file"); exit(1); } fgets(sendbuf,100,fp); for(i = 1; is_port) + portbase); else if ( (sin.sin_port = htons((u_short) atoi(service))) == 0) errexit("can't get \"%s\" service entry\n", service); /*map protocol name to protocol number */ if ((ppe = getprotobyname(transport)) == 0) errexit("can't get \"%s\" protocol entry\n", transport); /*use protocol to choose a sockect type */ if (strcmp(transport, "udp") == 0) type = SOCK_DGRAM; else type = SOCK_STREAM; /*allocate a socket */ s = socket(PF_INET, type, ppe->p_proto); if ( s == INVALID_SOCKET) errexit("cant create socket : %d\n", GetLastError()); /*bind the socket */ if (bind(s, (struct sockaddr *)&sin, sizeof(sin)) == SOCKET_ERROR) errexit("cant bind to %s port: %d\n", service, GetLastError()); if (type == SOCK_STREAM && listen(s, qlen) == SOCKET_ERROR) errexit(" cant listen on %s port: %d\n", service, GetLastError()); return s; } /******************************************************************************* * Errexit takes variable number of arguments, passes on to vprintf for output * and finally calls WSACleanup to release system socket resources. * this follows the printf conventions for the formatted output. ********************************************************************************/ void errexit(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); WSACleanup(); exit(1); }