/* * File name: TCPIP$ECHO_SERVER_PLUS.C * Product: Compaq TCP/IP Services for OpenVMS * Version: V5.2 * * Copyright 2000 Compaq Computer Corporation * * COMPAQ Registered in U.S. Patent and Trademark Office. * * Licensed computer software. Valid license from Compaq * or authorized sublicensor 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. * * * 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. * * ENVIRONMENT: * TCP/IP Services V5.0 or higher * OpenVMS 7.1 or higher * * BUILD INSTRUCTIONS: * * Using "DEC C" compiler: * * $ cc TCPIP$ECHO_SERVER_PLUS * $ link TCPIP$ECHO_SERVER_PLUS * $ run TCPIP$ECHO_SERVER_PLUS * * REVISION HISTORY: * * 31-Jul-2000 Deepa Vachhani * Original creation * * 28-Sep-2000 M. T. Hollinger * Restructured and integrated example into product build */ /* * 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"); } } } }