#pragma module tcpip$echo_server_plus \ "V5.4-00" /* * © Copyright 1976, 2003 Hewlett-Packard Development Company, L.P. * * Confidential computer software. Valid license from HP and/or its * subsidiaries required for possession, use, or copying. * * Consistent with FAR 12.211 and 12.212, Commercial Computer Software, * Computer Software Documentation, and Technical Data for Commercial * Items are licensed to the U.S. Government under vendor's standard * commercial license. * * Neither HP nor any of its subsidiaries shall be liable for technical * or editorial errors or omissions contained herein. The information * in this document is provided "as is" without warranty of any kind * and is subject to change without notice. The warranties for HP * products are set forth in the express limited warranty statements * accompanying such products. Nothing herein should be construed as * constituting an additional warranty. * * ++ * FACILITY: * * EXAMPLES * * ABSTRACT: * * This example shows a multi-threaded TCP and UDP server * implementing the ECHO and DAYTIME protocols, as specified * in RFC 862 and RFC 867. * * Refer to 'Build, Configuration, and Run Instructions' for * details on how to build, configure, and run this program. * * ENVIRONMENT: * * OpenVMS Alpha/VAX V7.1 * TCP/IP Services V5.0 or higher * * AUTHOR: * * TCPIP Development Group, CREATION DATE: 31-Jul-2000 * * -- */ /* Build, Configuration, and Run Instructions */ /* * BUILD INSTRUCTIONS: * * To build this example program use commands of the form, * * using the "C" compiler: * * $ cc/prefix=all TCPIP$ECHO_SERVER_PLUS.C * $ link TCPIP$ECHO_SERVER_PLUS * * * CONFIGURATION INSTRUCTIONS: * * No special configuration required. * * * RUN INSTRUCTIONS: * * To run this example program: * * $ run tcpip$echo_server_plus * */ /* * HEADER FILES */ #include #include #include #include #include #include #include #include #include #include #include #define ECHO_PORT 7 #define DAYTIME_PORT 13 #define ECHOLEN 65535 #define MAXCLIENTS 16 /* * Functional Description: * * This example is able to create sockets of type SOCK_STREAM (TCP) * and SOCK_DGRAM (UDP), bind either or both, select to receive a * message on any of its sockets, send either message or date/time * back on the appropriate socket. * * Error messages are sent to SYS$OUTPUT. * * Socket library calls used: * socket * bind * listen * select * accept * recvfrom * close * sendto * recv * write * * Design Note: * * For purposes of this example, we aren't particularly careful about * source address selection. However, if this code is to run on a * multi-homed host, we really should determine which interface each * UDP query arrives on and respond using that same source address. */ main (void) { int i, on = 1, echo_tcp, echo_udp, daytime_tcp, daytime_udp, sockfd, bytes; unsigned int maxfd, retlen; fd_set rset, allset; time_t ticks; struct sockaddr_in echo_sin, daytime_sin, rmtaddr; int echo_client[MAXCLIENTS]; char message[ECHOLEN]; memset (&echo_sin, 0, sizeof (echo_sin)); echo_sin.sin_family = AF_INET; echo_sin.sin_port = htons (ECHO_PORT); echo_sin.sin_addr.s_addr = INADDR_ANY; memset (&daytime_sin, 0, sizeof (daytime_sin)); daytime_sin.sin_family = AF_INET; daytime_sin.sin_port = htons (DAYTIME_PORT); daytime_sin.sin_addr.s_addr = INADDR_ANY; /* Initialize each spot in array to -1 to indicate it is available. */ for (i = 0; i < MAXCLIENTS; i++) echo_client[i] = -1; /****** TCP ECHO socket, bind ******/ if ((echo_tcp = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("echo tcp socket"); exit (1); } /* Set socket option to avoid errors when restarting. */ if (setsockopt (echo_tcp, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)) < 0) { perror ("echo tcp setsockopt"); exit (1); } if (bind (echo_tcp, (struct sockaddr *) &echo_sin, sizeof (echo_sin)) < 0) { perror ("echo tcp bind"); exit (1); } if (listen (echo_tcp, 1) < 0) { perror ("echo tcp listen"); exit (1); } /****** UDP ECHO (socket, bind) ******/ if ((echo_udp = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { perror ("echo udp socket"); exit (1); } if (bind (echo_udp, (struct sockaddr *) &echo_sin, sizeof (echo_sin)) < 0) { perror ("echo udp bind"); exit (1); } /****** TCP DAYTIME socket, bind ******/ if ((daytime_tcp = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("daytime tcp socket"); exit (1); } /* set socket option to avoid errors when restarting */ if (setsockopt (daytime_tcp, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))<0) { perror ("daytime tcp setsockopt"); exit (1); } if (bind (daytime_tcp, (struct sockaddr *) &daytime_sin, sizeof (daytime_sin)) < 0) { perror ("daytime tcp bind"); exit (1); } if (listen (daytime_tcp, 5) < 0) { perror ("daytime listen"); exit (1); } /****** UDP DAYTIME socket, bind ******/ if ((daytime_udp = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { perror ("daytime udp socket"); exit (1); } if (bind (daytime_udp, (struct sockaddr *) &daytime_sin, sizeof (daytime_sin)) < 0) { perror ("daytime udp bind"); exit (1); } /* Since fd's are assigned sequentially, the last will be the highest. */ maxfd = daytime_udp; /* Set bits for all the listener sockets. */ FD_ZERO (&allset); FD_SET (daytime_tcp, &allset); FD_SET (daytime_udp, &allset); FD_SET (echo_tcp, &allset); FD_SET (echo_udp, &allset); for (;;) { rset = allset; if (select (maxfd + 1, &rset, NULL, NULL, NULL) < 0) { if (errno == EINTR) continue; perror ("select"); exit (1); } /****** New ECHO connection ******/ if (FD_ISSET (echo_tcp, &rset)) { retlen = sizeof (rmtaddr); /* Accept new client's connection. */ if ((sockfd = accept (echo_tcp, (struct sockaddr *) &rmtaddr, &retlen)) == -1) { perror ("echo accept"); continue; } /* Add new client to client array. */ for (i = 0; i < MAXCLIENTS; i++) if (echo_client[i] < 0) { echo_client[i] = sockfd; break; } if (i == MAXCLIENTS) { printf ("Too many clients\n"); close (sockfd); continue; } if (sockfd > maxfd) maxfd = sockfd; FD_SET (sockfd, &allset); } /****** UDP ECHO message ******/ if (FD_ISSET (echo_udp, &rset)) { retlen = sizeof (rmtaddr); /* Read message sent by the client. */ if ((bytes = recvfrom (echo_udp, &message, sizeof (message), 0, (struct sockaddr *) &rmtaddr, &retlen)) <= 0) { perror ("recvfrom"); continue; } /* Send message right back to the client. */ if (sendto (echo_udp, &message, bytes, 0, (struct sockaddr *) &rmtaddr, retlen) == -1) perror ("echo send"); } /****** TCP DAYTIME ******/ if (FD_ISSET (daytime_tcp, &rset)) { if ((sockfd = accept (daytime_tcp, (struct sockaddr *) NULL, NULL)) == -1) { perror ("daytime accept"); continue; } ticks = time (NULL); /* Write date/time to client. */ if ((write (sockfd, ctime (&ticks), 25)) == -1) { perror ("daytime tcp write"); continue; } close (sockfd); } /****** UDP DAYTIME ******/ if (FD_ISSET (daytime_udp, &rset)) { retlen = sizeof (rmtaddr); /* Get message from client. */ if (recvfrom (daytime_udp, &message, sizeof (message), 0, (struct sockaddr *) &rmtaddr, &retlen) == -1) { perror ("daytime recvfrom"); continue; } ticks = time (NULL); /* Send date/time string to client. */ if (sendto (daytime_udp, ctime (&ticks), 25, 0, (struct sockaddr *) &rmtaddr, retlen) == -1) { perror ("daytime sendto"); continue; } } /* Check all TCP ECHO clients for newly-arrived data. */ for (i = 0; i < MAXCLIENTS; i++) { if ((sockfd = echo_client[i]) < 0) continue; /* see if data arrived on this socket */ if (FD_ISSET (sockfd, &rset)) { /* recv will return number of received bytes */ if ((bytes=recv (sockfd, &message, sizeof (message), 0)) <= 0) { close (sockfd); FD_CLR (sockfd, &allset); echo_client[i] = -1; } else if (write (sockfd, &message, bytes) < 0) perror ("echo write"); } } } }