home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / tolkit45.zip / os2tk45 / samples / tcpiptk / echosamp / echosrv / echosrv.c < prev    next >
Text File  |  1999-05-11  |  10KB  |  334 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. #include <stdio.h>
  78.  
  79. #include <types.h>
  80. #include <netinet\in.h>
  81. #include <sys\socket.h>
  82. #include <netdb.h>
  83. #include <sys\ioctl.h>
  84. #include <sys\time.h>
  85. #include <unistd.h>
  86. #include <arpa\inet.h>
  87. #include <nerrno.h>
  88.  
  89. #define MAX_CONNS    2
  90.  
  91. void ServiceUDP(int sock);
  92. int ServiceTCP(int sock);
  93.  
  94.  
  95. void main(int argc, char **argv) {
  96.    int listen_sock, udp_sock, newsock;
  97.    int connsocks[MAX_CONNS], selsocks[MAX_CONNS + 2];
  98.    struct servent *echoprot;
  99.    struct sockaddr_in server, client;
  100.    int rc, numconns;
  101.    int asize, i;
  102.  
  103.    // Initialize TCP/IP
  104.  
  105.    if (sock_init() != 0) {
  106.       printf("INET.SYS probably is not running");
  107.       exit(1);
  108.    }
  109.  
  110. //------ Create the TCP server socket
  111.  
  112.    // Create a TCP socket to accept incoming connections
  113.  
  114.    listen_sock = socket(AF_INET, SOCK_STREAM, 0);
  115.    if (listen_sock == -1) {
  116.        psock_errno("tcp socket()");
  117.        exit(1);
  118.    }
  119.  
  120.    printf("TCP socket assigned is %d\n", listen_sock);
  121.  
  122.    // Get the port for the echo protocol out of the etc\services file
  123.  
  124.    echoprot = getservbyname("echo", "tcp");
  125.    if (echoprot == NULL) {
  126.       printf("The echo/tcp protocol is not listed in the etc/services file\n");
  127.       exit(1);
  128.    }
  129.  
  130.    // Bind the TCP socket to the echo port
  131.  
  132.    server.sin_family = AF_INET;
  133.    server.sin_port = echoprot->s_port;
  134.    server.sin_addr.s_addr = INADDR_ANY;
  135.  
  136.    rc = bind(listen_sock, (struct sockaddr *)&server, sizeof(server));
  137.    if (rc == -1) {
  138.        psock_errno("tcp bind()");
  139.        exit(1);
  140.    }
  141.  
  142.    // Put the socket into listen mode
  143.  
  144.    rc = listen(listen_sock, SOMAXCONN);
  145.    if (rc == -1) {
  146.        psock_errno("listen()");
  147.        exit(1);
  148.    }
  149.  
  150. //------ Create the UDP server socket
  151.  
  152.    // Create a UDP socket to accept incoming data
  153.  
  154.    udp_sock = socket(AF_INET, SOCK_DGRAM, 0);
  155.    if (udp_sock == -1) {
  156.        psock_errno("udp socket()");
  157.        exit(1);
  158.    }
  159.  
  160.    printf("UDP socket assigned is %d\n", udp_sock);
  161.  
  162.    // Get the port for the echo protocol out of the etc\services file
  163.  
  164.    echoprot = getservbyname("echo", "udp");
  165.    if (echoprot == NULL) {
  166.       printf("The echo/udp protocol is not listed in the etc/services file\n");
  167.       exit(1);
  168.    }
  169.  
  170.    // Bind the UDP socket to the echo port
  171.  
  172.    server.sin_family = AF_INET;
  173.    server.sin_port = echoprot->s_port;
  174.    server.sin_addr.s_addr = INADDR_ANY;
  175.  
  176.    rc = bind(udp_sock, (struct sockaddr *)&server, sizeof(server));
  177.    if (rc == -1) {
  178.        psock_errno("udp bind()");
  179.        exit(1);
  180.    }
  181.  
  182.    // No connections yet
  183.  
  184.    numconns = 0;
  185.  
  186. //------ Wait for data to echo or a connection on the TCP socket
  187.  
  188.    while (1) {
  189.  
  190.       // Setup the socket array for select()
  191.  
  192.       selsocks[0] = listen_sock;
  193.       selsocks[1] = udp_sock;
  194.       for (i = 0; i < numconns; i++)
  195.          selsocks[i+2] = connsocks[i];
  196.  
  197.       // Wait indefinitely
  198.  
  199.       rc = os2_select(selsocks, numconns + 2, 0, 0, -1);
  200.       if (rc == -1) {
  201.          // If the select was interrupted, just continue
  202.          if (sock_errno() == SOCEINTR)
  203.             continue;
  204.          psock_errno("select()");
  205.          exit(1);
  206.       }
  207.  
  208.       // Check the TCP sockets to see if we got any data on them
  209.  
  210.       for (i = 0; i < numconns; i++) {
  211.          if (selsocks[i+2] != -1) {
  212.             // We got some data - handle it
  213.  
  214.             rc = ServiceTCP(selsocks[i+2]);
  215.             if (rc == -1) {
  216.  
  217.                // The connection was closed - move the last connected socket
  218.                // into the position this socket occupies
  219.  
  220.                connsocks[i] = connsocks[numconns-1];
  221.                numconns--;
  222.             }
  223.          }
  224.       }
  225.  
  226.       // If this was a request for a new TCP connection, accept it
  227.  
  228.       if (selsocks[0] != -1) {
  229.  
  230.          // accept() the new connection
  231.  
  232.          asize = sizeof(client);
  233.          newsock = accept(selsocks[0], (struct sockaddr *)&client, &asize);
  234.          if (newsock == -1) {
  235.             psock_errno("accept()");
  236.             exit(1);
  237.          }
  238.  
  239.          printf("Received a TCP connection on socket %d from %s port %d\n",
  240.                 newsock, inet_ntoa(client.sin_addr), ntohs(client.sin_port));
  241.  
  242.          // If there are more concurrent connections than we can handle, just
  243.          // close the socket -- doing the accept() and then a soclose() takes
  244.          // the connection request off our queue, and keeps the client from
  245.          // hanging around forever trying to connect.
  246.  
  247.          if (numconns >= MAX_CONNS)
  248.             soclose(newsock);
  249.          else
  250.             connsocks[numconns++] = newsock;
  251.       }
  252.  
  253.       // If we received a UDP packet, handle it
  254.  
  255.       if (selsocks[1] != -1)
  256.          ServiceUDP(selsocks[1]);
  257.    }
  258. }
  259.  
  260.  
  261. // The UDP socket has a packet waiting to be received-- receive it and echo
  262. // it back to the sender
  263.  
  264. void ServiceUDP(int sock) {
  265.    static char buf[32767];
  266.    int rc;
  267.    int asize, len;
  268.    struct sockaddr_in client;
  269.  
  270.    // Receive the datagram
  271.  
  272.    asize = sizeof(client);
  273.    len = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&client,
  274.                   &asize);
  275.    if (len == -1) {
  276.       psock_errno("recvfrom()");
  277.       exit(1);
  278.    }
  279.  
  280.    printf("Received a UDP echo request from %s port %d\n",
  281.           inet_ntoa(client.sin_addr), ntohs(client.sin_port));
  282.  
  283.    // Echo it back
  284.  
  285.    rc = sendto(sock, buf, len, 0, (struct sockaddr *)&client, sizeof(client));
  286.    if (rc == -1 || rc != len) {
  287.       psock_errno("sendto()");
  288.       exit(1);
  289.    }
  290. }
  291.  
  292.  
  293. // A client sent us some data - echo it back to him
  294.  
  295. int ServiceTCP(int sock) {
  296.    int rc, len;
  297.    int socks[1];
  298.    char buf[1024];
  299.  
  300.    // Find out how much data he sent us
  301.  
  302.    rc = ioctl(sock, FIONREAD, (char *)&len, sizeof(len));
  303.    if (rc == -1) {
  304.       psock_errno("ioctl()");
  305.       exit(1);
  306.    }
  307.  
  308.    // Read the data
  309.  
  310.    rc = recv(sock, buf, len, 0);
  311.    if (rc == -1) {
  312.       psock_errno("recv()");
  313.       exit(1);
  314.    }
  315.  
  316.    if (rc == 0) {
  317.       printf("TCP socket %d: The client broke the connection\n", sock);
  318.       soclose(sock);
  319.       return -1;
  320.    }
  321.  
  322.    printf("TCP socket %d: received %d bytes\n", sock, len);
  323.  
  324.    // Echo the data back
  325.  
  326.    rc = send(sock, buf, len, 0);
  327.    if (rc == -1) {
  328.       psock_errno("send()");
  329.       exit(1);
  330.    }
  331.  
  332.    return 0;
  333. }
  334.