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

  1. /* daytime.c - set local time from remote daytime or time server
  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: daytime.c,v 1.16 1999/03/05 15:47:06 rommel Exp rommel $";
  12. static char *rcsrev = "$Revision: 1.16 $";
  13.  
  14. /*
  15.  * $Log: daytime.c,v $
  16.  * Revision 1.16  1999/03/05 15:47:06  rommel
  17.  * added logging
  18.  *
  19.  * Revision 1.15  1999/02/27 14:15:41  rommel
  20.  * changed NT service code
  21.  *
  22.  * Revision 1.14  1998/10/19 05:58:55  rommel
  23.  * minor changes/fixes
  24.  *
  25.  * Revision 1.13  1998/10/18 19:36:26  rommel
  26.  * make code time_t independent
  27.  *
  28.  * Revision 1.12  1998/10/18 17:42:34  rommel
  29.  * fix incompatibility with time_t being defined as double
  30.  *
  31.  * Revision 1.11  1998/10/01 10:06:10  rommel
  32.  * fixes from colinw@ami.com.au
  33.  *
  34.  * Revision 1.10  1998/07/31 14:11:58  rommel
  35.  * fixed small bug
  36.  *
  37.  * Revision 1.9  1998/07/30 06:46:09  rommel
  38.  * added Win32 port
  39.  * added SNTP support
  40.  * fixed many bugs
  41.  * prepared for modem support
  42.  *
  43.  * Revision 1.8  1996/12/08 11:18:04  rommel
  44.  * added get_date prototype
  45.  *
  46.  * Revision 1.7  1996/12/08 11:15:07  rommel
  47.  * don't change time within 1 second margin
  48.  * from Ewen McNeill <ewen@naos.co.nz>
  49.  *
  50.  * Revision 1.6  1996/11/29 15:45:00  rommel
  51.  * changes (maxadj) from Ewen McNeill <ewen@naos.co.nz>
  52.  *
  53.  * Revision 1.5  1995/08/20 08:15:10  rommel
  54.  * updated for new emx socket library, IBM compiler
  55.  * fixed minor bugs
  56.  *
  57.  * Revision 1.4  1994/07/17 21:13:26  rommel
  58.  * fixed usage() display again
  59.  *
  60.  * Revision 1.3  1994/07/17 21:10:23  rommel
  61.  * fixed usage() display
  62.  *
  63.  * Revision 1.2  1994/07/17 21:07:57  rommel
  64.  * added daemon mode, continuously updating local time
  65.  *
  66.  * Revision 1.1  1994/07/17 20:45:55  rommel
  67.  * Initial revision
  68.  */
  69.  
  70. #include <stdio.h>
  71. #include <stdlib.h>
  72. #include <getopt.h>
  73. #include <time.h>
  74. #include <string.h>
  75. #include <ctype.h>
  76. #include <errno.h>
  77.  
  78. #include "daytime.h"
  79. #include "os.h"
  80.  
  81. struct options
  82. {
  83.   int interval;
  84.   int dont;
  85.   int maxadj;
  86.   int maxwait;
  87.   long offset;
  88.   service serv;
  89.   protocol proto;
  90.   int portnum;
  91.   char host[64];
  92.   char port[64];
  93.   char logfile[256];
  94. };
  95.  
  96. static struct options opts;
  97.  
  98. int get_modem_line(int port, char *node, char *buffer, int bytes)
  99. {
  100.   /* get time over modem 0531512038 ? */
  101.   return -1;
  102. }
  103.  
  104. int get_and_set_time(int port, char *node, service serv, protocol proto,
  105.              int dont, long offs, long maxadj, int maxwait)
  106. {
  107.   int sock, bytes, size, rc;
  108.   struct sockaddr_in server;
  109.   struct hostent *host;
  110.   struct linger linger;
  111.   struct timeval tv;
  112.   fd_set fds;
  113.   time_t remote, here;
  114.   long newtime, ourtime;
  115.   char buffer[64], *request, *timestr;
  116.   sntp *message;
  117.  
  118.   switch (serv)
  119.   {
  120.  
  121.   case DAYTIME:
  122.   case TIME:
  123.  
  124.     bytes = 1;
  125.     buffer[0] = 0;
  126.  
  127.     break;
  128.  
  129.   case SNTP:
  130.  
  131.     bytes = sizeof(sntp);
  132.     memset(buffer, 0, bytes);
  133.  
  134.     message = (sntp *) buffer;
  135.  
  136.     message->flags.version = 1;
  137.     message->flags.mode = 3;
  138.  
  139.     break;
  140.  
  141.   }
  142.  
  143.   if (proto != MODEM)
  144.   {
  145.     server.sin_family = AF_INET;
  146.     server.sin_port = port;
  147.  
  148.     if (isdigit(node[0]))
  149.       server.sin_addr.s_addr = inet_addr(node);
  150.     else
  151.     {
  152.       if ((host = gethostbyname(node)) == NULL)
  153.     return psock_errno("gethostbyname()"), 1;
  154.  
  155.       server.sin_addr = * (struct in_addr *) (host -> h_addr);
  156.     }
  157.   }
  158.  
  159.   switch (proto)
  160.   {
  161.  
  162.   case TCP:
  163.  
  164.     if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0)
  165.       return psock_errno("socket(tcp)"), 1;
  166.  
  167.     if (connect(sock, (struct sockaddr *) &server, sizeof(server)) < 0)
  168.       return psock_errno("connect()"), 1;
  169.  
  170.     if (serv == SNTP)
  171.     {
  172.       if (send(sock, buffer, bytes, 0) < 0)
  173.     return psock_errno("send()"), 1;
  174.     }
  175.  
  176.     FD_ZERO(&fds);
  177.     FD_SET(sock, &fds);
  178.     tv.tv_sec  = maxwait;
  179.     tv.tv_usec = 0;
  180.  
  181.     if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
  182.       return psock_errno("select()"), 1;
  183.     else if (rc == 0)
  184.     {
  185.       soclose(sock);
  186.       lprintf("timeout waiting for answer from time server");
  187.       return 0;
  188.     }
  189.  
  190.     if ((bytes = recv(sock, buffer, sizeof(buffer), 0)) <= 0)
  191.       return psock_errno("recv()"), 1;
  192.  
  193.     soclose(sock);
  194.  
  195.     break;
  196.  
  197.   case UDP:
  198.  
  199.     if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 1)
  200.       return psock_errno("socket(udp)"), 1;
  201.  
  202.     if (sendto(sock, buffer, bytes, 0,
  203.                (struct sockaddr *) &server, sizeof(server)) < 0)
  204.       return psock_errno("sendto()"), 1;
  205.  
  206.     FD_ZERO(&fds);
  207.     FD_SET(sock, &fds);
  208.     tv.tv_sec  = maxwait;
  209.     tv.tv_usec = 0;
  210.  
  211.     if ((rc = select(FD_SETSIZE, &fds, 0, 0, &tv)) < 0)
  212.       return psock_errno("select()"), 1;
  213.     else if (rc == 0)
  214.     {
  215.       soclose(sock);
  216.       lprintf("timeout waiting for answer from time server");
  217.       return 0;
  218.     }
  219.  
  220.     size = sizeof(server);
  221.     if ((bytes = recvfrom(sock, buffer, sizeof(buffer), 0,
  222.                           (struct sockaddr *) &server, &size)) < 0)
  223.       psock_errno("recvfrom()");
  224.  
  225.     soclose(sock);
  226.  
  227.     break;
  228.  
  229.   case MODEM:
  230.  
  231.     if ((bytes = get_modem_line(port, node, buffer, sizeof(buffer))) == -1)
  232.       return perror("modem"), 1;
  233.  
  234.     break;
  235.  
  236.   }
  237.  
  238.   switch (serv)
  239.   {
  240.  
  241.   case DAYTIME:
  242.  
  243.     buffer[bytes] = 0;
  244.     remote = get_date(buffer, NULL);
  245.     newtime = (long) remote;
  246.  
  247.     break;
  248.  
  249.   case TIME:
  250.  
  251.     if (bytes != sizeof(long))
  252.       return lprintf("invalid time value received"), 1;
  253.  
  254.     newtime = * (long *) buffer;
  255.     newtime = ntohl(newtime);
  256.     /*
  257.      * The time service returns seconds since 1900/01/01 00:00:00 GMT, not
  258.      * since 1970 as assumed by Unix time_t values.  We need to subtract
  259.      * 70 years' worth of seconds.  Fortunately, RFC 868 tells us that the
  260.      * time value 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT.
  261.      */
  262.     newtime -= 2208988800UL;
  263.  
  264.     break;
  265.  
  266.   case SNTP:
  267.  
  268.     if (message->flags.version < 1 || 3 < message->flags.version)
  269.       return lprintf("incompatible protocol version on server"), 1;
  270.     if (message->flags.leap_ind == 3)
  271.       return lprintf("server not synchronized"), 1;
  272.     if (message->stratum == 0)
  273.       return lprintf("server not synchronized"), 1;
  274.  
  275.     newtime = ntohl(message->transmit_time.integer);
  276.  
  277.     if (newtime == 0)
  278.       return lprintf("server not synchronized"), 1;
  279.  
  280.     /* same here */
  281.     newtime -= 2208988800UL;
  282.  
  283.     break;
  284.  
  285.   }
  286.  
  287.   if (newtime <= 0)
  288.     return lprintf("invalid time (%ld)", newtime), 1;
  289.  
  290.   newtime += offs;
  291.   remote = (time_t) newtime;
  292.  
  293.   time(&here);
  294.   ourtime = (long) here;
  295.  
  296.   if (maxadj)
  297.     if (newtime < (ourtime - maxadj) || (ourtime + maxadj) < newtime)
  298.       dont = 1;               /* too far off: just report it */
  299.  
  300.   if (abs(newtime - ourtime) <= 1)
  301.     dont = 1;
  302.  
  303.   if (!dont && stime(&remote))
  304.     return lprintf("invalid time set request"), 1;
  305.  
  306.   timestr = ctime(&remote);
  307.   timestr[strlen(timestr) - 1] = 0;
  308.   lprintf("time %s %s: (%+ld) %s", dont ? "at" : "set from",
  309.      node, newtime - ourtime, timestr);
  310.   fflush(stdout);
  311.  
  312.   return 0;
  313. }
  314.  
  315. int usage(void)
  316. {
  317.   printf("\nSet time from remote host, %s"
  318.      "\n(C) 1997 Kai-Uwe Rommel\n", rcsrev);
  319.  
  320. #ifdef WIN32
  321.   printf("\nUsage: daytime [-l file] [-IUndtsu] [-m secs] [-c int] [-p port] host\n"
  322.          "\n  -I       install as a service"
  323.          "\n  -U       uninstall service\n"
  324. #else
  325.   printf("\nUsage: daytime [-l file] [-ndtsu] [-m secs] [-c int] [-p port] host\n"
  326. #endif
  327.          "\n  -l file  write messages to logfile"
  328.      "\n  -c int   run continuously, perform action every 'int' seconds"
  329.          "\n  -n       do not set the local clock, display the remote time only"
  330.          "\n  -o offs  adjust the retrieved time by offs seconds before"
  331.      "\n           setting the local clock"
  332.      "\n  -m secs  maximum number of seconds to adjust by"
  333.      "\n  -w secs  maximum number of seconds to wait for the time server's answer\n"
  334.          "\n  -d       use the DAYTIME service (port 13)"
  335.          "\n  -t       use the TIME service (port 37, this is the default)"
  336.          "\n  -s       use the SNTP service (port 123), usually requires -u too"
  337.      "\n  -u       use the UDP protocol (default is to use TCP)"
  338.      "\n  -p port  use nonstandard port number\n"
  339.      "\n  -x       use serial modem to access time server"
  340.      "\n           (in this case, the 'host' is the phone number to dial"
  341.      "\n           and 'port' is the number of the serial port)\n");
  342.   return 1;
  343. }
  344.  
  345. int endless(void)
  346. {
  347.   int rc = 0;
  348.  
  349.   for(;;)
  350.   {
  351.     rc = get_and_set_time(opts.portnum, opts.host, opts.serv, opts.proto,
  352.               opts.dont, opts.offset, opts.maxadj, opts.maxwait);
  353.  
  354.     sleep(opts.interval);
  355.   }
  356. }
  357.  
  358. int main(int argc, char **argv)
  359. {
  360.   int opt, rc, isrv = 0;
  361.   struct servent *port;
  362.  
  363.   tzset();
  364.  
  365.   if (sock_init())
  366.     return psock_errno("sock_init()"), 1;
  367.  
  368. #ifdef WIN32
  369. #define SERVICE_NAME "daytime"
  370. #define SERVICE_TITLE "Daytime Client"
  371.   if (started_as_service())
  372.   {
  373.     restore_options(SERVICE_NAME, &opts, sizeof(opts));
  374.     logfile = opts.logfile;
  375.     run_as_service(SERVICE_NAME, endless);
  376.     return 0;
  377.   }
  378. #endif
  379.  
  380.   opts.serv = TIME;
  381.   opts.proto = TCP;
  382.   opts.portnum = -1;
  383.   opts.maxwait = 60;
  384.  
  385.   while ((opt = getopt(argc, argv, "?l:IUndtsuo:p:c:m:w:x")) != EOF)
  386.     switch (opt)
  387.     {
  388.     case 'l':
  389.       strcpy(opts.logfile, optarg);
  390.       logfile = opts.logfile;
  391.       break;
  392.     case 'n':
  393.       opts.dont = 1;
  394.       break;
  395.     case 'd':
  396.       opts.serv = DAYTIME;
  397.       break;
  398.     case 't':
  399.       opts.serv = TIME;
  400.       break;
  401.     case 's':
  402.       opts.serv = SNTP;
  403.       break;
  404.     case 'u':
  405.       opts.proto = UDP;
  406.       break;
  407.     case 'o':
  408.       opts.offset = atol(optarg);
  409.       break;
  410.     case 'p':
  411.       opts.portnum = htons(atoi(optarg));
  412.       break;
  413.     case 'c':
  414.       opts.interval = atol(optarg);
  415.       break;
  416.     case 'm':
  417.       opts.maxadj = atol(optarg);
  418.       break;
  419.     case 'w':
  420.       opts.maxwait = atol(optarg);
  421.       break;
  422.     case 'x':
  423.       opts.proto = MODEM;
  424.       opts.serv = DAYTIME;
  425.       break;
  426. #ifdef WIN32
  427.     case 'I':
  428.       isrv = 1;
  429.       break;
  430.     case 'U':
  431.       if ((rc = install_as_service(SERVICE_NAME, 0, 0)) != 0)
  432.     printf("deinstallation of service failed\n");
  433.       return rc;
  434. #endif
  435.     default:
  436.       return usage();
  437.     }
  438.  
  439.   if (optind == argc)
  440.     return usage();
  441.   else
  442.     strcpy(opts.host, argv[optind]);
  443.  
  444.   if (opts.portnum == -1)
  445.   {
  446.     char *s_service = opts.serv == SNTP ? "ntp" :
  447.                       opts.serv == DAYTIME ? "daytime" : "time";
  448.     char *s_proto = opts.proto == TCP ? "tcp" : "udp";
  449.  
  450.     if ((port = getservbyname(s_service, s_proto)) == NULL)
  451.       return psock_errno("getservbyname()"), 1;
  452.  
  453.     opts.portnum = port -> s_port;
  454.   }
  455.  
  456. #ifdef WIN32
  457.   if (isrv)
  458.   {
  459.     if ((rc = install_as_service(SERVICE_NAME, SERVICE_TITLE, 1)) != 0)
  460.       return printf("installation as service failed\n"), rc;
  461.     else
  462.       return save_options(SERVICE_NAME, &opts, sizeof(opts));
  463.   }
  464. #endif
  465.  
  466.   if (opts.interval == 0)
  467.     return get_and_set_time(opts.portnum, opts.host, opts.serv, opts.proto,
  468.                 opts.dont, opts.offset, opts.maxadj, opts.maxwait);
  469.   else
  470.     return endless();
  471. }
  472.  
  473. /* end of daytime.c */
  474.