#include #include #include #include #include /* Variable parameter stuff. */ #include #include #include #include #include #include #include #include #include #include #include #include "echo.h" #include #ifdef _AIX #include extern void bcopy(const void *, void *, size_t); extern void bzero(void*, size_t); /*/extern int setitimer(int,struct itimerval*,struct itimerval*);*/ extern int setitimer(int, const struct itimerval *, struct itimerval *); #endif /* _AIX */ #include #include #define MAXNAMELEN (int)255 #define SAFE_STRCPY(to, from) \ do {strncpy(to, from, sizeof(to)); to[sizeof(to) - 1] = '\0'; if (1) break;} while (0) void HangUp(sd) int sd; { /* * shutdown closes sockets and close shuts file descriptor */ (void)shutdown(sd,2); (void)close(sd); return; } /* * send a string over a socket descriptor * * -- times out after CLIENT_TIMEOUT seconds * -- returns -1 on failure, strlen of string set on success */ int SendString(int sd, char *string, int data_size) { int sent; int bytes; char *buf; struct itimerval itout; int i, j = 0; int msg_size; int tmp; /* * assume data is 0 terminated */ /*cjk - let the user decide this.*/ /*data_size = strlen(string)+1;*/ /* * sanity check -- send a max of 256K bytes */ if(data_size > (1024*256)) { fprintf(stderr,"SendString: %d must be less than 256K\n",data_size); fflush(stderr); return(-1); } if(data_size < MSGSIZE) { msg_size = data_size; } else { msg_size = MSGSIZE; } sent = 0; buf = string; for (i=0; i < data_size; i += j) { for (j=0; j < msg_size; j+=bytes) { itout.it_interval.tv_sec = 0; itout.it_interval.tv_usec = 0; itout.it_value.tv_sec = CLIENT_TIMEOUT; itout.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&itout,NULL); if ((sent > 0) && ((sent+(msg_size-j)) > data_size)) { tmp = (sent+(msg_size-j))-data_size; bytes = send(sd,buf,(msg_size-tmp),0); if(bytes <= 0) return(-1); sent+=bytes; i = data_size; break; } else { bytes = send(sd,buf,(msg_size - j),0); } itout.it_interval.tv_sec = 0; itout.it_interval.tv_usec = 0; itout.it_value.tv_sec = 0; itout.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&itout,NULL); if(bytes <= 0) { return(-1); } buf += bytes; sent += bytes; if (sent >= data_size) { i = data_size; break; } } } return(sent); } /* * send a string over a socket descriptor * * -- assumes that the caller has allocated the space and that * string size is the size of the recv buffer * -- times out after CLIENT_TIMEOUT seconds * -- returns -1 on failure, strlen of string set on success */ int RecvString(int sd, char *string, int string_size) { int recvd = 0; int bytes; struct itimerval itout; char *buf = string; int i; int j = 0; int msg_size; if (string_size < MSGSIZE) { msg_size = string_size; } else { msg_size = MSGSIZE; } /* * read until there is no more space or until a byte * containing 0 (end of string) is read */ for(i=0; i < string_size; i+= j){ for(j=0; j < msg_size; j+= bytes) { itout.it_interval.tv_sec = 0; itout.it_interval.tv_usec = 0; itout.it_value.tv_sec = CLIENT_TIMEOUT; itout.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&itout,NULL); bytes = recv(sd,buf,(msg_size - j),0); itout.it_interval.tv_sec = 0; itout.it_interval.tv_usec = 0; itout.it_value.tv_sec = 0; itout.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&itout,NULL); if(bytes <= 0) { fprintf(stderr, "RecvString: recv failed after %d\n",recvd); fflush(stderr); return(-1); } recvd += bytes; /* * if we the last byte we received contained a 0, * it is the end of the string */ if(buf[bytes-1] == 0) { i = string_size; break; } buf += bytes; } } return(recvd); } char *ARGS = "p:\n"; int CreateServerSocket(short port) { struct sockaddr_in server; int server_sock; int err; int one,sock_opt_len; server.sin_port = htons(port); server.sin_addr.s_addr = INADDR_ANY; server.sin_family = AF_INET; server_sock = socket (AF_INET,SOCK_STREAM,0); if(server_sock < 0) { fprintf(stderr,"CreateServerSocket: socket call failed\n"); fflush(stderr); exit(1); } /* * bind the socket to the local IP address at the port specified */ err = bind(server_sock, (struct sockaddr *)&server, sizeof(struct sockaddr_in)); if(err < 0) { fprintf(stderr, "CreateSocketServer: bind failed\n"); fflush(stderr); close(server_sock); return(-1); } /* * tell kernel how many connections to queue (max 5) */ err = listen(server_sock,5); if(err < 0) { fprintf(stderr,"CreateSocketServer: listen failed\n"); fflush(stderr); close(server_sock); return(-1); } return(server_sock); } int WaitForClient(int server_sock, char *outaddr, int outlen) { struct sockaddr_in peeraddr; int peeraddr_len = sizeof(peeraddr); int sd; struct itimerval itout; int one,sock_opt_len; sd = -1; /* * signal will cause timeout */ itout.it_interval.tv_sec = 0; itout.it_interval.tv_usec = 0; itout.it_value.tv_sec = SERVER_TIMEOUT; itout.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&itout,NULL); sd = accept(server_sock, (struct sockaddr *)&peeraddr, &peeraddr_len); itout.it_interval.tv_sec = 0; itout.it_interval.tv_usec = 0; itout.it_value.tv_sec = 0; itout.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&itout,NULL); if(sd < 0) { fprintf(stderr, "accept failed\n"); fflush(stderr); return(-1); } strncpy(outaddr,inet_ntoa(peeraddr.sin_addr),outlen); outaddr[outlen] = 0; /* * notice that server_sock is not the socket on * which the client now speaks -- accept returns a different * socket */ return(sd); } int main(int argc,char *argv[]){ int status; int c, pid = -1; char recv_buf[SMALLSIZE]; char *send_buf; int len = 0; int server_sock; int incoming_sock; MSGSIZE = (32*1024); while((c = getopt(argc,argv,ARGS)) != EOF) { switch(c) { case 'p': Server_port = atoi(optarg); break; default: fprintf(stderr, "echo server unrecognized argument: %c\n",c); fflush(stderr); exit(1); argc = -1; break; } } if(argc < 0) { fprintf(stderr, "usage: server -p server port\n"); fflush(stderr); exit(1); } server_sock = CreateServerSocket(Server_port); if(server_sock < 0) { fprintf(stderr,"failed.\n"); fflush(stderr); exit(1); } fprintf(stderr,"created.\n"); fflush(stderr); while(1) { fprintf(stderr,"waiting for client... \n"); fflush(stderr); /*collect up exited children*/ while((child = waitpid(-1, &status, WNOHANG)) > 0); /*get the next client request*/ incoming_sock = WaitForClient(server_sock, peerip, sizeof(peerip)); /*collect up exited children*/ while((child = waitpid(-1, &status, WNOHANG)) > 0); if(incoming_sock < 0) { fprintf(stderr,"accept of incoming socket failed.\n"); fflush(stderr); HangUp(server_sock); exit(1); } fprintf(stderr,"received client connection: %s\n", peerip); fflush(stderr); pid = fork(); if (pid == -1) { /*error*/ fprintf(stderr,"fork failed.\n"); fflush(stderr); close(incoming_sock); HangUp(server_sock); exit(1); } if (pid != 0) { /*parent*/ close(incoming_sock); continue; } /*child*/ close(server_sock); fprintf(stderr,"connected.\nwaiting for bytes ...\n"); fflush(stderr); /* receive an ok from the client */ bzero(recv_buf,sizeof(recv_buf)); recvd = RecvString(incoming_sock,recv_buf,sizeof(recv_buf)); if(recvd < 0 || (recv_buf[0] != CLIENT_OK && recv_buf[0] != CLIENT_UPDATE)) { fprintf(stderr,"failed0.\n"); fflush(stderr); HangUp(incoming_sock); HangUp(server_sock); exit(1); } /*send back the size of the list buffer */ send_buf = (char *)malloc(MEDSIZE); bzero(send_buf,MEDSIZE); len = strlen(send_buf)+1; /*+1 to include the null*/ sprintf(send_buf,"%d", len); if (len >= MEDSIZE) { fprintf(stderr,"ERROR: increase MEDSIZE!\n"); fflush(stderr); HangUp(server_sock); HangUp(incoming_sock); exit(1); } sent = SendString(incoming_sock,send_buf,len); if(sent < 0) { fprintf(stderr,"failed1\n"); fflush(stderr); HangUp(server_sock); HangUp(incoming_sock); exit(1); } free send_buf; /* receive an ok from the client */ bzero(recv_buf,sizeof(recv_buf)); recvd = RecvString(incoming_sock,recv_buf,sizeof(recv_buf)); if(recvd < 0 || recv_buf[0] != CLIENT_OK) { fprintf(stderr,"failed2.\n"); fflush(stderr); HangUp(incoming_sock); HangUp(server_sock); exit(1); } /* send the buffer */ sent = SendString(incoming_sock,buffer,len); if(sent < 0) { fprintf(stderr,"failed3\n"); fflush(stderr); HangUp(server_sock); HangUp(incoming_sock); exit(1); } close(incoming_sock); /*exit the child*/ exit(OK); } HangUp(server_sock); return(0); }