home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / daytime.zip / daytimed.c < prev    next >
C/C++ Source or Header  |  1999-03-05  |  13KB  |  532 lines

  1. /* daytimed.c - daytime and time server daemon
  2.  *
  3.  * Author:  Kai Uwe Rommel <rommel@ars.muc.de>
  4.  * Created: Sun Apr 10 1994
  5.  *
  6.  * This code is in the public domain.
  7.  * Let the author know if you make improvements or fixes, though.
  8.  */
  9.  
  10. static char *rcsid =
  11. "$Id: daytimed.c,v 1.9 1999/03/05 15:47:06 rommel Exp rommel $";
  12. static char *rcsrev = "$Revision: 1.9 $";
  13.  
  14. /*
  15.  * $Log: daytimed.c,v $
  16.  * Revision 1.9  1999/03/05 15:47:06  rommel
  17.  * added logging
  18.  *
  19.  * Revision 1.8  1999/02/27 14:17:07  rommel
  20.  * changed NT service code
  21.  * skip unavailable service port information
  22.  *
  23.  * Revision 1.7  1998/10/19 05:59:07  rommel
  24.  * minor changes/fixes
  25.  *
  26.  * Revision 1.6  1998/10/18 19:36:26  rommel
  27.  * make code time_t independent
  28.  *
  29.  * Revision 1.5  1998/10/01 10:06:10  rommel
  30.  * fixes from colinw@ami.com.au
  31.  *
  32.  * Revision 1.4  1998/07/30 06:46:09  rommel
  33.  * added Win32 port
  34.  * added SNTP support
  35.  * fixed many bugs
  36.  * prepared for modem support
  37.  *
  38.  * Revision 1.3  1995/08/20 08:15:10  rommel
  39.  * updated for new emx socket library, IBM compiler
  40.  * fixed minor bugs
  41.  *
  42.  * Revision 1.2  1994/07/17 21:06:45  rommel
  43.  * bug fix: display correct peer address
  44.  *
  45.  * Revision 1.1  1994/07/17 20:46:11  rommel
  46.  * Initial revision
  47.  */
  48.  
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51. #include <getopt.h>
  52. #include <time.h>
  53. #include <string.h>
  54.  
  55. #include "daytime.h"
  56. #include "os.h"
  57.  
  58. struct options
  59. {
  60.   char logfile[256];
  61. };
  62.  
  63. static struct options opts;
  64.  
  65. int handle_request(int sock, service serv, protocol proto)
  66. {
  67.   struct sockaddr_in client;
  68.   struct linger linger;
  69.   char buffer[64], *timestr, *service;
  70.   time_t now;
  71.   long ourtime;
  72.   sntp *message;
  73.   int bytes, size;
  74.  
  75.   if (proto == TCP)
  76.   {
  77.     if (serv == SNTP)
  78.     {
  79.       if ((bytes = recv(sock, buffer, sizeof(buffer), 0)) <= 0)
  80.     return psock_errno("recv()"), 1;
  81.     }
  82.   }
  83.   else
  84.   {
  85.     size = sizeof(client);
  86.     if (recvfrom(sock, buffer, sizeof(buffer), 0,
  87.          (struct sockaddr *) &client, &size) < 0)
  88.       return psock_errno("recvfrom()"), 1;
  89.   }
  90.  
  91.   time(&now);
  92.   ourtime = (long) now;
  93.  
  94.   switch (serv)
  95.   {
  96.  
  97.   case DAYTIME:
  98.  
  99.     timestr = ctime(&now);
  100.     bytes = strlen(timestr) + 1;
  101.     service = "daytime";
  102.  
  103.     break;
  104.  
  105.   case TIME:
  106.  
  107.     /* The time service returns seconds since 1900/01/01 00:00:00 GMT, not
  108.      * since 1970 as assumed by Unix time values.  We need to add 70
  109.      * years' worth of seconds.  Fortunately, RFC 868 tells us that the
  110.      * daytime value 2,208,988,800 corresponds to 00:00  1 Jan 1970 GMT. */
  111.     ourtime += 2208988800UL;
  112.     ourtime = htonl(ourtime);
  113.  
  114.     timestr = (char *) &ourtime;
  115.     bytes = sizeof(ourtime);
  116.     service = "time";
  117.  
  118.     break;
  119.  
  120.   case SNTP:
  121.  
  122.     /* same here */
  123.     ourtime += 2208988800UL;
  124.     ourtime = htonl(ourtime);
  125.  
  126.     timestr = buffer;
  127.     bytes = sizeof(sntp);
  128.     service = "SNTP";
  129.  
  130.     message = (sntp *) buffer;
  131.  
  132.     message->flags.leap_ind = 0;
  133.  
  134.     if (message->flags.version < 1 || 3 < message->flags.version)
  135.       message->flags.version  = 3;
  136.  
  137.     message->flags.mode = (message->flags.mode == 3) ? 4 : 2;
  138.     message->stratum = 1;
  139.     message->precision = 0;
  140.     message->root_delay = 0;
  141.     message->root_dispersion = 0;
  142.     message->reference_id = 0;
  143.  
  144.     message->reference_time.integer = ourtime;
  145.     message->reference_time.fraction = 0;
  146.  
  147.     message->receive_time = message->reference_time;
  148.     message->transmit_time = message->reference_time;
  149.  
  150.     break;
  151.  
  152.   }
  153.  
  154.   if (proto == TCP)
  155.   {
  156.     linger.l_onoff = 1;
  157.     linger.l_linger = 10;
  158.  
  159.     if (setsockopt(sock, SOL_SOCKET, SO_LINGER,
  160.            (char *) &linger, sizeof(linger)) < 0)
  161.       return psock_errno("setsockopt(SO_LINGER)"), 1;
  162.  
  163.     if (send(sock, timestr, bytes, 0) < 0)
  164.       return psock_errno("send()"), 1;
  165.  
  166.     size = sizeof(client);
  167.     if (getpeername(sock, (struct sockaddr *) &client, &size) < 0)
  168.       return psock_errno("getsockname()"), 1;
  169.  
  170.     soclose(sock);
  171.   }
  172.   else
  173.   {
  174.     if (sendto(sock, timestr, bytes, 0,
  175.            (struct sockaddr *) &client, size) < 0)
  176.       return psock_errno("sendto()"), 1;
  177.   }
  178.  
  179.   lprintf("served '%s' request from %s via '%s'",
  180.       service, inet_ntoa(client.sin_addr), proto == TCP ? "tcp" : "udp");
  181.  
  182.   return 0;
  183. }
  184.  
  185. int serve(void)
  186. {
  187.   struct sockaddr_in server, client;
  188.   struct servent *port;
  189.   int tcp_13 = 0, tcp_37 = 0, udp_13 = 0, udp_37 = 0, tcp_123 = 0, udp_123 = 0;
  190.  
  191.   /* We set up all our services. If any of them fails to set up properly,
  192.      it will be ignored and not be serviced. NT, for example, already
  193.      has a daytime service for both TCP and UDP. */
  194.  
  195.   /* set up daytime (tcp) server */
  196.  
  197.   if ((port = getservbyname("daytime", "tcp")) != NULL)
  198.   {
  199.     if ((tcp_13 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  200.       return psock_errno("socket(daytime tcp)"), 1;
  201.  
  202.     server.sin_family = AF_INET;
  203.     server.sin_port = port -> s_port;
  204.     server.sin_addr.s_addr = INADDR_ANY;
  205.  
  206.     if (bind(tcp_13, (struct sockaddr *) &server, sizeof(server)) < 0)
  207.     {
  208.       soclose(tcp_13);
  209.       tcp_13 = 0;
  210.     }
  211.     else
  212.     {
  213.       if (listen(tcp_13, 4) != 0)
  214.     return psock_errno("listen(daytime tcp)"), 1;
  215.  
  216.       lprintf("listening for daytime requests via tcp");
  217.     }
  218.   }
  219.  
  220.   /* set up daytime (udp) server */
  221.  
  222.   if ((port = getservbyname("daytime", "udp")) != NULL)
  223.   {
  224.     if ((udp_13 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
  225.       return psock_errno("socket(daytime udp)"), 1;
  226.  
  227.     server.sin_family = AF_INET;
  228.     server.sin_port = port -> s_port;
  229.     server.sin_addr.s_addr = INADDR_ANY;
  230.  
  231.     if (bind(udp_13, (struct sockaddr *) &server, sizeof(server)) < 0)
  232.     {
  233.       soclose(udp_13);
  234.       udp_13 = 0;
  235.     }
  236.     else
  237.       lprintf("listening for daytime requests via udp");
  238.   }
  239.  
  240.   /* set up time (tcp) server */
  241.  
  242.   if ((port = getservbyname("time", "tcp")) != NULL)
  243.   {
  244.     if ((tcp_37 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  245.       return psock_errno("socket(time tcp)"), 1;
  246.  
  247.     server.sin_family = AF_INET;
  248.     server.sin_port = port -> s_port;
  249.     server.sin_addr.s_addr = INADDR_ANY;
  250.  
  251.     if (bind(tcp_37, (struct sockaddr *) &server, sizeof(server)) < 0)
  252.     {
  253.       soclose(tcp_37);
  254.       tcp_37 = 0;
  255.     }
  256.     else
  257.     {
  258.       if (listen(tcp_37, 4) != 0)
  259.     return psock_errno("listen(time tcp)"), 1;
  260.  
  261.       lprintf("listening for time requests via tcp");
  262.     }
  263.   }
  264.  
  265.   /* set up time (udp) server */
  266.  
  267.   if ((port = getservbyname("time", "udp")) != NULL)
  268.   {
  269.     if ((udp_37 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
  270.       return psock_errno("socket(time udp)"), 1;
  271.  
  272.     server.sin_family = AF_INET;
  273.     server.sin_port = port -> s_port;
  274.     server.sin_addr.s_addr = INADDR_ANY;
  275.  
  276.     if (bind(udp_37, (struct sockaddr *) &server, sizeof(server)) < 0)
  277.     {
  278.       soclose(udp_37);
  279.       udp_37 = 0;
  280.     }
  281.     else
  282.       lprintf("listening for time requests via udp");
  283.   }
  284.  
  285.   /* set up sntp (tcp) server, nonstandard */
  286.  
  287.   if ((port = getservbyname("ntp", "tcp")) != NULL)
  288.   {
  289.     if ((tcp_123 = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  290.       return psock_errno("socket(ntp tcp)"), 1;
  291.  
  292.     server.sin_family = AF_INET;
  293.     server.sin_port = port -> s_port;
  294.     server.sin_addr.s_addr = INADDR_ANY;
  295.  
  296.     if (bind(tcp_123, (struct sockaddr *) &server, sizeof(server)) < 0)
  297.     {
  298.       soclose(tcp_123);
  299.       tcp_123 = 0;
  300.     }
  301.     else
  302.     {
  303.       if (listen(tcp_123, 4) != 0)
  304.     return psock_errno("listen(ntp tcp)"), 1;
  305.  
  306.       lprintf("listening for SNTP requests via tcp");
  307.     }
  308.   }
  309.  
  310.   /* set up sntp (udp) server */
  311.  
  312.   if ((port = getservbyname("ntp", "udp")) != NULL)
  313.   {
  314.     if ((udp_123 = socket(PF_INET, SOCK_DGRAM, 0)) < 0)
  315.       return psock_errno("socket(ntp udp)"), 1;
  316.  
  317.     server.sin_family = AF_INET;
  318.     server.sin_port = port -> s_port;
  319.     server.sin_addr.s_addr = INADDR_ANY;
  320.  
  321.     if (bind(udp_123, (struct sockaddr *) &server, sizeof(server)) < 0)
  322.     {
  323.       soclose(udp_123);
  324.       udp_123 = 0;
  325.     }
  326.     else
  327.       lprintf("listening for SNTP requests via udp");
  328.   }
  329.  
  330.   /* server loop */
  331.  
  332.   if (tcp_13 == 0 && tcp_37 == 0 && tcp_123 == 0 &&
  333.       udp_13 == 0 && udp_37 == 0 && udp_123 == 0)
  334.   {
  335.     lprintf("nothing to serve");
  336.     return 1;
  337.   }
  338.  
  339.   for (;;)
  340.   {
  341.     struct timeval tv;
  342.     fd_set fds;
  343.     int rc, sock, sock_clt, length;
  344.     service serv;
  345.     protocol proto;
  346.  
  347.     /* wait for a request */
  348.  
  349.     FD_ZERO(&fds);
  350.  
  351.     if (tcp_13)
  352.       FD_SET(tcp_13, &fds);
  353.     if (tcp_37)
  354.       FD_SET(tcp_37, &fds);
  355.     if (tcp_123)
  356.       FD_SET(tcp_123, &fds);
  357.     if (udp_13)
  358.       FD_SET(udp_13, &fds);
  359.     if (udp_37)
  360.       FD_SET(udp_37, &fds);
  361.     if (udp_123)
  362.       FD_SET(udp_123, &fds);
  363.  
  364.     tv.tv_sec  = 60;
  365.     tv.tv_usec = 0;
  366.  
  367.     if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
  368.       return psock_errno("select()"), 1;
  369.     else if (rc == 0)
  370.       continue;
  371.  
  372.     /* determine type and protocol */
  373.  
  374.     if (tcp_13 && FD_ISSET(tcp_13, &fds) != 0)
  375.     {
  376.       sock = tcp_13;
  377.       serv = DAYTIME;
  378.       proto = TCP;
  379.     }
  380.     else if (tcp_37 && FD_ISSET(tcp_37, &fds) != 0)
  381.     {
  382.       sock = tcp_37;
  383.       serv = TIME;
  384.       proto = TCP;
  385.     }
  386.     else if (tcp_123 && FD_ISSET(tcp_123, &fds) != 0)
  387.     {
  388.       sock = tcp_123;
  389.       serv = SNTP;
  390.       proto = TCP;
  391.     }
  392.     else if (udp_13 && FD_ISSET(udp_13, &fds) != 0)
  393.     {
  394.       sock = udp_13;
  395.       serv = DAYTIME;
  396.       proto = UDP;
  397.     }
  398.     else if (udp_37 && FD_ISSET(udp_37, &fds) != 0)
  399.     {
  400.       sock = udp_37;
  401.       serv = TIME;
  402.       proto = UDP;
  403.     }
  404.     else if (udp_123 && FD_ISSET(udp_123, &fds) != 0)
  405.     {
  406.       sock = udp_123;
  407.       serv = SNTP;
  408.       proto = UDP;
  409.     }
  410.     else
  411.       continue;
  412.  
  413.     /* and handle it */
  414.  
  415.     if (proto == TCP)
  416.     {
  417.       length = sizeof(client);
  418.       if ((sock_clt = accept(sock, (struct sockaddr *) &client, &length)) == -1)
  419.     return psock_errno("accept()"), 1;
  420.  
  421.       handle_request(sock_clt, serv, TCP);
  422.     }
  423.     else
  424.       handle_request(sock, serv, UDP);
  425.   }
  426.  
  427.   return 0;
  428. }
  429.  
  430. int usage(void)
  431. {
  432.   printf("\nTime Server, %s"
  433.      "\n(C) 1997 Kai-Uwe Rommel\n", rcsrev);
  434.  
  435. #ifdef OS2
  436.   printf("\nUsage: daytimed [-l file] [-S] [[-dtsu] socket]\n"
  437.          "\n  -l  write messages to file"
  438.          "\n  -S  run as a standalone server (not from inetd)\n"
  439.          "\n  -d  serve DAYTIME request on socket"
  440.          "\n  -t  serve TIME request on socket"
  441.          "\n  -s  serve SNTP request on socket"
  442.          "\n  -u  use UDP instead of TCP to serve request\n"
  443.      "\nThe -d, -t, -s and -u options are for use with inetd only.\n");
  444. #endif
  445.  
  446. #ifdef WIN32
  447.   printf("\nUsage: daytimed [-l file] [-SIU] \n"
  448.          "\n  -l  write messages to file"
  449.          "\n  -S  run as a standalone server (not as a service)"
  450.          "\n  -I  install as a service"
  451.          "\n  -U  uninstall service\n");
  452. #endif
  453.  
  454.   return 1;
  455. }
  456.  
  457. int main(int argc, char **argv)
  458. {
  459.   int opt, rc, isrv = 0;
  460.   service serv = TIME;
  461.   protocol proto = TCP;
  462.  
  463.   tzset();
  464.  
  465.   if (sock_init())
  466.     return psock_errno("sock_init()"), 1;
  467.  
  468. #ifdef WIN32
  469. #define SERVICE_NAME "daytimed"
  470. #define SERVICE_TITLE "Daytime Server"
  471.   if (started_as_service())
  472.   {
  473.     restore_options(SERVICE_NAME, &opts, sizeof(opts));
  474.     logfile = opts.logfile;
  475.     run_as_service(SERVICE_NAME, serve);
  476.   }
  477. #endif
  478.  
  479.   while ((opt = getopt(argc, argv, "?l:dtsuSIU")) != EOF)
  480.     switch (opt)
  481.     {
  482.     case 'l':
  483.       strcpy(opts.logfile, optarg);
  484.       logfile = opts.logfile;
  485.       break;
  486. #ifdef OS2
  487.     case 'd':
  488.       serv = DAYTIME;
  489.       break;
  490.     case 't':
  491.       serv = TIME;
  492.       break;
  493.     case 's':
  494.       serv = SNTP;
  495.       break;
  496.     case 'u':
  497.       proto = UDP;
  498.       break;
  499. #endif
  500.     case 'S':
  501.       return serve();
  502. #ifdef WIN32
  503.     case 'I':
  504.       isrv = 1;
  505.       break;
  506.     case 'U':
  507.       if ((rc = install_as_service(SERVICE_NAME, NULL, 0)) != 0)
  508.     printf("deinstallation of service failed\n");
  509.       return rc;
  510. #endif
  511.     default:
  512.       return usage();
  513.     }
  514.  
  515. #ifdef WIN32
  516.   if (isrv)
  517.   {
  518.     if ((rc = install_as_service(SERVICE_NAME, SERVICE_TITLE, 1)) != 0)
  519.       return printf("installation as service failed\n"), rc;
  520.     else
  521.       return save_options(SERVICE_NAME, &opts, sizeof(opts));
  522.   }
  523. #endif
  524.  
  525.   if (optind == argc)
  526.     return usage();
  527.  
  528.   return handle_request(atoi(argv[optind]), serv, proto);
  529. }
  530.  
  531. /* end of daytimed.c */
  532.