#include #include #include #include #include #include #include #include #include #include #include #include #ifdef _AIX #include #endif /* _AIX */ #include "socket_signal.h" #include #define CLIENT_TIMEOUT (5) /* 30 seconds for client */ #define SERVER_TIMEOUT (300) /* 5 minutes for server */ extern char *optarg; char Server_name[255]; short Server_port = 8008; int Server_size = 5; /* * connects to server_name at port * * -- server_name can either be DNS name or ascii rep. of ip address * -- returns -1 on failure, socket desc on success */ int CallServer(server_name,server_port) char *server_name; short server_port; { struct sockaddr_in server; /* remote host address */ struct hostent *hp; /* host entity */ int sd; int err; int temp_addr; /* * first, check to see if the server_name is specified as * and IP address */ temp_addr = inet_addr(server_name); /* * if -1, then server name must be a DNS name and not an * ip address */ if(temp_addr == -1) { hp = gethostbyname(server_name); if (hp == NULL) { fprintf(stderr,"Call Server: unknown server name %s\n", server_name); fflush(stderr); return(-1); } } else { hp = gethostbyaddr((char *)&temp_addr, sizeof(temp_addr), AF_INET); if(hp == NULL) { fprintf(stderr, "Call Server: unknown ip address %s\n", server_name); fflush(stderr); return(-1); } } memset(&server,0,sizeof(server)); // bzero((char *)&server, sizeof(server)); memcpy(&server.sin_addr, hp->h_addr_list[0], hp->h_length); // bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length); server.sin_family = hp->h_addrtype; server.sin_port = htons(server_port); sd = socket(hp->h_addrtype, SOCK_STREAM, 0); if(sd < 0) { fprintf(stderr,"Call Server: cannot create socket to server\n"); fflush(stderr); return(-1); } err = Connect(sd, (struct sockaddr *)&server, sizeof(server), CLIENT_TIMEOUT); if(err <= 0) { fprintf(stderr,"CallServer: connect failed\n"); fflush(stderr); return(-1); } return(sd); } void HangUp(sd) int sd; { /* * shutdown closes sockets and close shuts file descriptor */ (void)shutdown(sd,2); (void)close(sd); return; } int CreateServerSocket(short port) { struct sockaddr_in server; int one = 1; int sock_opt_len = sizeof(int); int server_sock; int err; 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); } /* * optional -- allows reopen of socket immediately */ err = setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sock_opt_len); if(err < 0) { fprintf(stderr, "CreateSocketServer: set sock opt REUSE failed\n"); fflush(stderr); } /* * 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) { struct sockaddr_in peeraddr; int peeraddr_len; int sd; sd = -1; peeraddr_len = sizeof(peeraddr_len); sd = Accept(server_sock, (struct sockaddr *)&peeraddr, &peeraddr_len, SERVER_TIMEOUT); if(sd <= 0) { fprintf(stderr, "accept failed\n"); fflush(stderr); return(-1); } /* * notice that server_sock is not the socket on * which the client now speaks -- accept returns a different * socket */ return(sd); } /* * 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; /* * assume data is 0 terminated */ data_size = strlen(string)+1; /* * sanity check -- send a max of 255 bytes */ if(data_size > 255) { fprintf(stderr,"SendString: %s too big\n",string); fflush(stderr); return(-1); } sent = 0; buf = string; while(sent < data_size) { bytes = Send(sd,buf,(data_size - sent),0, CLIENT_TIMEOUT); if(bytes <= 0) { fprintf(stderr, "SendString failed after sending %d bytes\n", sent); fflush(stderr); return(-1); } buf += bytes; sent += bytes; } return(data_size); } /* * 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; char *buf; buf = string; /* * read until there is noo more space or until a byte * containing 0 (end of string) is read */ while(recvd < string_size) { bytes = Recv(sd,buf,(string_size - recvd),0, CLIENT_TIMEOUT); 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) { break; } buf += bytes; } return(recvd); } #ifdef CLIENT char *ARGS = "h:p:\n"; int main(int argc,char *argv[]) { int c; int socket; char send_buf[255]; char recv_buf[255]; int sent; int recvd; strcpy(Server_name,"localhost"); while((c = getopt(argc,argv,ARGS)) != EOF) { switch(c) { case 'p': Server_port = atoi(optarg); break; case 'h': strncpy(Server_name,optarg,sizeof(Server_name)); break; default: fprintf(stderr, "echo client unrecognized argument: %c\n",c); fflush(stderr); exit(1); argc = -1; break; } } if(argc < 3) { fprintf(stderr, "usage: client -h server name, -p server port\n"); fflush(stderr); exit(1); } fprintf(stdout,"client connecting to %s at port %d...", Server_name,Server_port); socket = CallServer(Server_name,Server_port); if(socket < 0) { fprintf(stdout,"failed.\n"); fflush(stdout); exit(1); } fprintf(stdout,"connected.\n"); fflush(stdout); memset(send_buf,0,sizeof(send_buf)); // bzero(send_buf,sizeof(send_buf)); memset(recv_buf,0,sizeof(recv_buf)); // bzero(recv_buf,sizeof(recv_buf)); /* * VERY IMPORTANT to use strncpy with sockets so that incoming * data can't overwrite stack */ strncpy(send_buf,"Blimps are God's party balloons!",sizeof(send_buf)); fprintf(stdout,"sending string:\n\n\t%s\n\n",send_buf); fflush(stdout); sent = SendString(socket,send_buf); if(sent < 0) { fprintf(stdout,",failed\n"); fflush(stdout); HangUp(socket); exit(1); } fprintf(stdout,"receiving string..."); fflush(stdout); /* * VERY IMPORTANT that RecvString won't exceed the size of the * input buffer. Otherwise, someone could overwrite our * stack through the socket */ recvd = RecvString(socket,recv_buf,sizeof(recv_buf)); if(recvd < 0) { fprintf(stdout,"failed\n"); fflush(stdout); HangUp(socket); exit(1); } fprintf(stdout,"got:\n\n\t%s\n\nfrom server\n",recv_buf); fflush(stdout); HangUp(socket); exit(0); return(0); } #endif #ifdef SERVER char *ARGS = "p:\n"; void *ServerThread(void *arg) { int incoming_sock = (int)arg; char send_buf[255]; char recv_buf[255]; int recvd; int sent; memset(send_buf,0,sizeof(send_buf)); memset(recv_buf,0,sizeof(send_buf)); fprintf(stdout,"connected.\n"); fflush(stdout); fprintf(stdout,"waiting for string..."); fflush(stdout); recvd = RecvString(incoming_sock,recv_buf,sizeof(recv_buf)); if(recvd < 0) { fprintf(stdout,"failed in server thread.\n"); fflush(stdout); HangUp(incoming_sock); return(NULL); } fprintf(stdout,"got:\n\n\t%s\n\nfrom client\n",recv_buf); fflush(stdout); fprintf(stdout,"echoing..."); fflush(stdout); sent = SendString(incoming_sock,recv_buf); if(sent < 0) { fprintf(stdout,",failed\n"); fflush(stdout); HangUp(incoming_sock); return(NULL); } fprintf(stdout,"successfully\n"); /* * do not do a HangUp -- the other side MAY think the * socket is dead before the data gets there */ close(incoming_sock); /* * throw away the server socket, though */ return(NULL); } int main(int argc,char *argv[]) { int c; int server_sock; int incoming_sock; pthread_t tid; pthread_attr_t attr; 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 < 1) { fprintf(stderr, "usage: server -p server port\n"); fflush(stderr); exit(1); } fprintf(stdout,"server creating port %d...", Server_port); server_sock = CreateServerSocket(Server_port); if(server_sock < 0) { fprintf(stdout,"failed.\n"); fflush(stdout); exit(1); } fprintf(stdout,"created.\n"); fflush(stdout); /* * VERY IMPORTANT to use strncpy with sockets so that incoming * data can't overwrite stack */ fprintf(stdout,"waiting for client..."); fflush(stdout); while(1) { incoming_sock = WaitForClient(server_sock); if(incoming_sock < 0) { fprintf(stdout,"failed, looping back.\n"); fflush(stdout); continue; } pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED); pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); pthread_create(&tid, &attr, ServerThread, (void *)incoming_sock); fprintf(stdout,"server looping back after spawn\n"); fflush(stdout); } HangUp(server_sock); return(0); } #endif