home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / viscobv6.zip / vac22os2 / ibmcobol / samples / toolkit / tcpiptk / echosamp / echosrv / echosrv.c < prev    next >
Text File  |  1996-11-19  |  10KB  |  330 lines

  1. /********************************************************copyrite.xic********/
  2. /*                                                                          */
  3. /*   Licensed Materials - Property of IBM                                   */
  4. /*   IBM TCP/IP for OS/2                                                    */
  5. /*   (C) Copyright IBM Corporation. 1996.                                   */
  6. /*                                                                          */
  7. /*   All rights reserved.                                                   */
  8. /*                                                                          */
  9. /*   US Government Users Restricted Rights -                                */
  10. /*   Use, duplication or disclosure restricted by GSA ADP Schedule          */
  11. /*   Contract with IBM Corp.                                                */
  12. /*                                                                          */
  13. /*--------------------------------------------------------------------------*/
  14. /*                                                                          */
  15. /*  DISCLAIMER OF WARRANTIES.  The following [enclosed] code is             */
  16. /*  sample code created by IBM Corporation. This sample code is not         */
  17. /*  part of any standard or IBM product and is provided to you solely       */
  18. /*  for  the purpose of assisting you in the development of your            */
  19. /*  applications.  The code is provided "AS IS", without                    */
  20. /*  warranty of any kind.  IBM shall not be liable for any damages          */
  21. /*  arising out of your use of the sample code, even if they have been      */
  22. /*  advised of the possibility of such damages.                             */
  23. /*--------------------------------------------------------------------------*/
  24.  
  25. /*****************************************************************************
  26. *
  27. * Single threaded ECHO server
  28. * ---------------------------
  29. *
  30. * Written by Andre Asselin
  31. *
  32. * Description
  33. * -----------
  34. *
  35. * This program implements the server side of the Echo protocol (RFC 862).  The
  36. * Echo protocol is very simple: whatever the client sends to the server, the
  37. * server will send right back to the client.
  38. *
  39. * This version of the server services UDP echo requests, TCP echo requests, and
  40. * requests for new TCP connections all from one thread using select().
  41. *
  42. * The complete RFC is reproduced below:
  43. *
  44.  
  45. Network Working Group                                          J. Postel
  46. Request for Comments: 862                                            ISI
  47.                                                                 May 1983
  48.  
  49.                              Echo Protocol
  50.  
  51. This RFC specifies a standard for the ARPA Internet community.  Hosts on
  52. the ARPA Internet that choose to implement an Echo Protocol are expected
  53. to adopt and implement this standard.
  54.  
  55. A very useful debugging and measurement tool is an echo service.  An
  56. echo service simply sends back to the originating source any data it
  57. receives.
  58.  
  59. TCP Based Echo Service
  60.  
  61.    One echo service is defined as a connection based application on TCP.
  62.    A server listens for TCP connections on TCP port 7.  Once a
  63.    connection is established any data received is sent back.  This
  64.    continues until the calling user terminates the connection.
  65.  
  66. UDP Based Echo Service
  67.  
  68.    Another echo service is defined as a datagram based application on
  69.    UDP.  A server listens for UDP datagrams on UDP port 7.  When a
  70.    datagram is received, the data from it is sent back in an answering
  71.    datagram.
  72.  
  73. *************************************************************************/
  74.  
  75.  
  76. #include <stdlib.h>
  77.  
  78. #include <types.h>
  79. #include <netinet\in.h>
  80. #include <sys\socket.h>
  81. #include <netdb.h>
  82. #include <sys\ioctl.h>
  83.  
  84.  
  85. #define MAX_CONNS    2
  86.  
  87. void ServiceUDP(int sock);
  88. int ServiceTCP(int sock);
  89.  
  90.  
  91. void main(int argc, char **argv) {
  92.    int listen_sock, udp_sock, newsock;
  93.    int connsocks[MAX_CONNS], selsocks[MAX_CONNS + 2];
  94.    struct servent *echoprot;
  95.    struct sockaddr_in server, client;
  96.    int rc, numconns;
  97.    int asize, i;
  98.  
  99.    // Initialize TCP/IP
  100.  
  101.    if (sock_init() != 0) {
  102.       printf("INET.SYS probably is not running");
  103.       exit(1);
  104.    }
  105.  
  106. //------ Create the TCP server socket
  107.  
  108.    // Create a TCP socket to accept incoming connections
  109.  
  110.    listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  111.    if (listen_sock == -1) {
  112.        psock_errno("tcp socket()");
  113.        exit(1);
  114.    }
  115.  
  116.    printf("TCP socket assigned is %d\n", listen_sock);
  117.  
  118.    // Get the port for the echo protocol out of the etc\services file
  119.  
  120.    echoprot = getservbyname("echo", "tcp");
  121.    if (echoprot == NULL) {
  122.       printf("The echo/tcp protocol is not listed in the etc/services file\n");
  123.       exit(1);
  124.    }
  125.  
  126.    // Bind the TCP socket to the echo port
  127.  
  128.    server.sin_family = AF_INET;   
  129.    server.sin_port = echoprot->s_port;
  130.    server.sin_addr.s_addr = INADDR_ANY;
  131.  
  132.    rc = bind(listen_sock, (struct sockaddr *)&server, sizeof(server));
  133.    if (rc == -1) {
  134.        psock_errno("tcp bind()");
  135.        exit(1);
  136.    }
  137.  
  138.    // Put the socket into listen mode
  139.  
  140.    rc = listen(listen_sock, SOMAXCONN);
  141.    if (rc == -1) {
  142.        psock_errno("listen()");
  143.        exit(1);
  144.    }
  145.  
  146. //------ Create the UDP server socket
  147.  
  148.    // Create a UDP socket to accept incoming data
  149.  
  150.    udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
  151.    if (udp_sock == -1) {
  152.        psock_errno("udp socket()");
  153.        exit(1);
  154.    }
  155.  
  156.    printf("UDP socket assigned is %d\n", udp_sock);
  157.  
  158.    // Get the port for the echo protocol out of the etc\services file
  159.  
  160.    echoprot = getservbyname("echo", "udp");
  161.    if (echoprot == NULL) {
  162.       printf("The echo/udp protocol is not listed in the etc/services file\n");
  163.       exit(1);
  164.    }
  165.  
  166.    // Bind the UDP socket to the echo port
  167.  
  168.    server.sin_family = AF_INET;   
  169.    server.sin_port = echoprot->s_port;
  170.    server.sin_addr.s_addr = INADDR_ANY;
  171.  
  172.    rc = bind(udp_sock, (struct sockaddr *)&server, sizeof(server));
  173.    if (rc == -1) {
  174.        psock_errno("udp bind()");
  175.        exit(1);
  176.    }
  177.  
  178.    // No connections yet
  179.  
  180.    numconns = 0;
  181.  
  182. //------ Wait for data to echo or a connection on the TCP socket
  183.  
  184.    while (1) {
  185.  
  186.       // Setup the socket array for select()
  187.  
  188.       selsocks[0] = listen_sock;
  189.       selsocks[1] = udp_sock;
  190.       for (i = 0; i < numconns; i++)
  191.          selsocks[i+2] = connsocks[i];
  192.  
  193.       // Wait indefinitely
  194.  
  195.       rc = select(selsocks, numconns + 2, 0, 0, -1);
  196.       if (rc == -1) {
  197.          // If the select was interrupted, just continue
  198.          if (sock_errno() == SOCEINTR)
  199.             continue;
  200.          psock_errno("select()");
  201.          exit(1);
  202.       }
  203.  
  204.       // Check the TCP sockets to see if we got any data on them
  205.  
  206.       for (i = 0; i < numconns; i++) {
  207.          if (selsocks[i+2] != -1) {
  208.             // We got some data - handle it
  209.  
  210.             rc = ServiceTCP(selsocks[i+2]);
  211.             if (rc == -1) {
  212.  
  213.                // The connection was closed - move the last connected socket
  214.                // into the position this socket occupies
  215.  
  216.                connsocks[i] = connsocks[numconns-1];
  217.                numconns--;
  218.             }
  219.          }
  220.       }
  221.  
  222.       // If this was a request for a new TCP connection, accept it
  223.  
  224.       if (selsocks[0] != -1) {
  225.  
  226.          // accept() the new connection
  227.  
  228.          asize = sizeof(client);
  229.          newsock = accept(selsocks[0], (struct sockaddr *)&client, &asize);
  230.          if (newsock == -1) {
  231.             psock_errno("accept()");
  232.             exit(1);
  233.          }
  234.  
  235.          printf("Received a TCP connection on socket %d from %s port %d\n",
  236.                 newsock, inet_ntoa(client.sin_addr), ntohs(client.sin_port));
  237.  
  238.          // If there are more concurrent connections than we can handle, just
  239.          // close the socket -- doing the accept() and then a soclose() takes
  240.          // the connection request off our queue, and keeps the client from
  241.          // hanging around forever trying to connect.
  242.  
  243.          if (numconns >= MAX_CONNS)
  244.             soclose(newsock);
  245.          else
  246.             connsocks[numconns++] = newsock;
  247.       }
  248.  
  249.       // If we received a UDP packet, handle it
  250.  
  251.       if (selsocks[1] != -1) 
  252.          ServiceUDP(selsocks[1]);
  253.    }
  254. }
  255.  
  256.  
  257. // The UDP socket has a packet waiting to be received-- receive it and echo
  258. // it back to the sender
  259.  
  260. void ServiceUDP(int sock) {
  261.    static char buf[32767];
  262.    int rc;
  263.    int asize, len;
  264.    struct sockaddr_in client;
  265.  
  266.    // Receive the datagram
  267.  
  268.    asize = sizeof(client);
  269.    len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&client,
  270.                   &asize);
  271.    if (len == -1) {
  272.       psock_errno("recvfrom()");
  273.       exit(1);
  274.    }
  275.  
  276.    printf("Received a UDP echo request from %s port %d\n",
  277.           inet_ntoa(client.sin_addr), ntohs(client.sin_port));
  278.  
  279.    // Echo it back
  280.  
  281.    rc = sendto(sock, buf, len, 0, (struct sockaddr *)&client, sizeof(client));
  282.    if (rc == -1 || rc != len) {
  283.       psock_errno("sendto()");
  284.       exit(1);
  285.    }
  286. }
  287.  
  288.  
  289. // A client sent us some data - echo it back to him
  290.  
  291. int ServiceTCP(int sock) {
  292.    int rc, len;
  293.    int socks[1];
  294.    char buf[1024];
  295.  
  296.    // Find out how much data he sent us
  297.  
  298.    rc = ioctl(sock, FIONREAD, (char *)&len, sizeof(len));
  299.    if (rc == -1) {
  300.       psock_errno("ioctl()");
  301.       exit(1);
  302.    }
  303.  
  304.    // Read the data
  305.  
  306.    rc = recv(sock, buf, len, 0);
  307.    if (rc == -1) {
  308.       psock_errno("recv()");
  309.       exit(1);
  310.    }
  311.  
  312.    if (rc == 0) {
  313.       printf("TCP socket %d: The client broke the connection\n", sock);
  314.       soclose(sock);
  315.       return -1;
  316.    }
  317.  
  318.    printf("TCP socket %d: received %d bytes\n", sock, len);
  319.  
  320.    // Echo the data back
  321.  
  322.    rc = send(sock, buf, len, 0);
  323.    if (rc == -1) {
  324.       psock_errno("send()");
  325.       exit(1);
  326.    }
  327.  
  328.    return 0;
  329. }
  330.