/* ******************************************************************************* ** FILE: TCP_socket_server.C -- example program demonstrating usage of ** network programming library using UNIX-like stream sockets. ** ** PRODUCT: TCPware for VMS ** ** VERSION: V5.3 ** ** Copyright (c) 1997 by ** Process Software Corporation ** Framingham, Massachusetts ** ** This software is furnished under a license for use on a ** single computer system and may be copied only with the ** inclusion of the above copyright notice. This software, or ** any other copies thereof, may not be provided or otherwise ** made available to any other person except for use on such ** system and to one who agrees to these license terms. Title ** to and ownership of the software shall at all times remain ** in Process Software Corporation's name. ** ** The information in this document is subject to change ** without notice and should not be construed as a commitment ** by Process Software Corporation. Process Software ** Corporation assumes no responsibility for any errors that ** may appear in this document. ** ** ** ABSTRACT: ** ** TCP_socket_client.c and TCP_socket_server.c are a pair of example programs ** illustrating the use of UNIX-like stream sockets. ** ** ** ** SERVER SEQUENCE OF OPERATIONS: ** 1. Create a socket: socket() ** 2. Bind socket to IP address: bind() ** 3. Set the socket to listen: listen() ** 5. Accept client connect: accept() ** 6. Exchange data: send()/recv() or read()/write() ** 7. Close the accept socket: close() ** 7. Close the listen socket: close() ** ** ** BUILDING EXECUTABLES: ** ** 1. on VAX : ** with VAXC: ** $ CC TCP_SOCKET_SERVER.C ** $ LINK TCP_SOCKET_SERVER, TCPWARE:UCX$IPC/LIB, SYS$INPUT/OPTIONS ** SYS$SHARE:VAXCRTL/SHARE ** ** Instead of UCX's BG devices, TCpware's ** socket library with TCP devices can be used. ** ("/DEFINE=TCPWARE" allows read() etc. to be redefined to a socket function.): ** ** $ CC TCP_SOCKET_SERVER.C /DEFINE=TCPWARE ** $ LINK TCP_SOCKET_SERVER, SYS$INPUT/OPTIONS ** SYS$SHARE:TCPWARE_SOCKLIB_SHR/SHARE ** SYS$SHARE:VAXCRTL/SHARE ** ** with DECC: ** $ CC/DECC/PREFIX_LIBRARY_ENTRIES=ALL TCP_SOCKET_SERVER.C ** $ LINK TCP_SOCKET_SERVER ** ** 2. on ALPHA: ** $ CC/DECC/PREFIX_LIBRARY_ENTRIES=ALL TCP_SOCKET_SERVER.C ** $ LINK TCP_SOCKET_SERVER ** ******************************************************************************* ** REQUEST: If you have comments, please send them to "support@process.com" ******************************************************************************* */ #include /* Standard C i/o */ #include #include #include #include #include #include #include #include /* comes after in.h */ /* ** Service information */ #define SERVER_PORT 2048 /* if getservbyname fails, use this port number */ #define SERVICE "test_echo" #define PROTO "tcp" /* ** Net header needed since TCP function may not transmit entire message. ** If using this, it needs to be in both server and client. */ struct net_msg_hdr_struct { long msg_len; long seq_num; /* useful incase of resends */ }; #ifdef VAXC #ifdef TCPWARE # define read socket_read # define write socket_write # define close socket_close # define perror pneterror #endif /* TCPWARE */ /* function prototypes */ int socket_read( int s, char * buffer, int buflen); int socket_write( int s, char * buffer, int buflen); int socket_close( int s); #endif /* VAXC */ main() { int status; /* For return status */ int cont; /* boolean continue status */ int io_OK; /* boolean IO status */ int listen_socket; int accept_socket; int addrlen; int bytes; char server_name[200]; int bytes_left; /* count of bytes read */ char buffer[1024]; struct net_msg_hdr_struct *net_msg_hdr_P; char *c_P; char cont_str[80]; struct hostent *hostent_P; /* internet host address structure */ struct servent *servent_P; /* service port structure */ struct sockaddr_in server_adr; /* server socket address structure */ struct sockaddr_in client_adr; /* client socket address structure */ /* ** Setup server family and internet address. ** INADDR_ANY specifies accepting connects to any local IP address ** for this node. */ memset( &server_adr, 0, sizeof( server_adr) ); server_adr.sin_family = AF_INET; server_adr.sin_addr.s_addr = INADDR_ANY; /* ** Get server port number for named service. ** If unknown ( == 0 or = -1), use default define. */ if ( (int)(servent_P = getservbyname( SERVICE, PROTO)) > 0) server_adr.sin_port = servent_P->s_port; else server_adr.sin_port = htons(SERVER_PORT); status = SERVER_PORT; printf("Will receive on server port #: %d\n\n", ntohs(server_adr.sin_port)); /* Create TCP listening socket */ if ( ( listen_socket = socket(AF_INET, SOCK_STREAM, 0) ) < 0) { perror("socket"); exit(1); } /* Bind listening socket to server address */ addrlen = sizeof(server_adr); if ( bind( listen_socket, (struct sockaddr *)&server_adr, addrlen) < 0) { perror("bind"); exit(1); } /* Listen on the socket */ if (listen(listen_socket, 5) < 0) { perror("listen"); exit(1); } /* ** Keep handing another client connection - synchronously. */ net_msg_hdr_P = (struct net_msg_hdr_struct *)&buffer; for (cont = TRUE; cont; ) { printf("\nServer is accepting on port %d and awaits client connects.\n", ntohs(server_adr.sin_port) ); /* Accept connection request */ addrlen = sizeof( client_adr); if ( (accept_socket = accept(listen_socket, (struct sockaddr *)&client_adr, &addrlen) ) < 0 ) { perror("accept"); exit(1); } /* ** Use remote IP address to query DNS for host name. ** If unknown, just show remote IP address. */ hostent_P = gethostbyaddr( (char *) &client_adr.sin_addr,4, AF_INET); if (hostent_P) printf("Client connect accepted from %s = %s\n", inet_ntoa( client_adr.sin_addr), hostent_P->h_name); else printf(" Client connect accepted from [%s]\n", inet_ntoa( client_adr.sin_addr) ); /* ** Keep receiving and echoing messages till client closes connection or ** IO error. */ for (io_OK = TRUE; io_OK; ) { /* ** Receive message: ** Read to find total message length. ** Error if bytes = -1 or if too small. */ bytes = read( accept_socket, net_msg_hdr_P, sizeof( *net_msg_hdr_P) ); if ( bytes < sizeof( *net_msg_hdr_P) ) { perror( "Error reading net_msg_hdr."); break; } /* Keep reading till entire message read or IO error. */ for (c_P = &buffer[0] + sizeof( *net_msg_hdr_P), bytes_left = net_msg_hdr_P->msg_len; io_OK == TRUE && bytes_left > 0; bytes_left -= bytes, c_P += bytes) { bytes = read( accept_socket, c_P, bytes_left); /* If OK, print message received in this read */ if ( bytes > 0 ) { *(c_P + bytes) = '\0'; /* terminate for printf() */ printf("Read %02d characters:\n%s\n\n", bytes, c_P); } else { io_OK = FALSE; perror( "Error reading message."); break; } } /* ** If entire message received, then send it back: ** Keep writing till full message is sent, including header. */ if ( io_OK && 0 == bytes_left) { for (c_P = &buffer[0], bytes_left = net_msg_hdr_P->msg_len + sizeof(* net_msg_hdr_P); io_OK == TRUE && bytes_left > 0; bytes_left -= bytes, c_P += bytes) { bytes = write( accept_socket, c_P, bytes_left); if (bytes < 0) { perror( "Error sending message."); io_OK = FALSE; } } } } /* Close connection. Then the server loops back to accept new connect */ status = close(accept_socket); /* check if server should accept new client */ printf( "Accept new client (Y/N) ? "); gets( cont_str); if (cont_str[0] == 'Y' || cont_str[0] == 'y') cont = TRUE; else cont = FALSE; } /* ** Close the listening socket. */ status = close( listen_socket); }