home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: InfoMgt / InfoMgt.zip / nistimex.zip / nistime.c < prev    next >
C/C++ Source or Header  |  1993-06-12  |  16KB  |  396 lines

  1. /* nistime.c - query and set time from NIST server */
  2.  
  3. /* ------------------------------ */
  4. /* Feature test macros            */
  5. /* ------------------------------ */
  6. /* #define _POSIX_SOURCE                  /* Always require POSIX standard */
  7.  
  8. /* ------------------------------ */
  9. /* Standard include files         */
  10. /* ------------------------------ */
  11. #define INCL_DOSDATETIME
  12. #include <os2.h>
  13.  
  14. #include <stdio.h>
  15. #include <time.h>
  16. #include <string.h>
  17. #include <ctype.h>
  18. #include <stdlib.h>
  19.  
  20. #include <types.h>                     /* Will be OS/2 TCP/IP types.h file */
  21. #include <sys/socket.h>                /* More TCP/IP include files        */
  22. #include <netinet/in.h>
  23. #include <arpa/inet.h>
  24.  
  25. /* ------------------------------ */
  26. /* Local include files            */
  27. /* ------------------------------ */
  28.  
  29. /* ------------------------------- */
  30. /* My local typedef's and defines  */
  31. /* ------------------------------- */
  32. #define  panic    SysPanic(__FILE__, __LINE__)
  33.  
  34. #define  NIST_TIME_INET_ADDRESS  "132.163.135.130"    /* time.nist.gov   */
  35. #define  NIST_TIME_PORT          13                   /* specific port   */
  36. #define  UNIX_EPOCH_MJD          40587                /* UNIX epoch date */
  37.  
  38. /* ------------------------------- */
  39. /* My external function prototypes */
  40. /* ------------------------------- */
  41.  
  42. /* ------------------------------- */
  43. /* My internal function prototypes */
  44. /* ------------------------------- */
  45. static int sw(int argc, char *arg, char *let, long *val);
  46. static int ShiftTime(time_t diff);
  47. static void PrintUsage(void);
  48.  
  49. /* ------------------------------- */
  50. /* My usage of other external fncs */
  51. /* ------------------------------- */
  52.  
  53. /* ------------------------------- */
  54. /* Locally defined global vars     */
  55. /* ------------------------------- */
  56.  
  57.  
  58. /* ---------------------------------------------------------------------------
  59. - client process to connect to the daytime service via port 13 from nist
  60. - time server.
  61. -
  62. - This OS/2 implementation is a port of the unix utility by the same name
  63. - obtained by anonymous FTP from time_a.timefreq.bldrdoc.gov.  My apologies
  64. - to Judah Levine for the hack of his code.  For questions about this OS/2
  65. - implementation, contact:
  66. -
  67. -   Michael Thompson
  68. -   Cornell University
  69. -   Dept. of Materials Science
  70. -   129 Bard Hall
  71. -   tommy@msc.cornell.edu
  72. -
  73. -
  74. - The client process uses the time message received to check (and optionally 
  75. - to set) the time of the local clock.  the comparison assumes that the local
  76. - clock keeps time in seconds from 1/1/70 which is the UNIX standard, and it
  77. - computes the time difference by converting the received MJD to seconds
  78. - since 1/1/70 and adding the received hr, min and sec, also converted to
  79. - seconds.  If the local machine keeps time in some other way, then the
  80. - comparison method will have to change, but the rest should be okay.
  81. -
  82. - This software was developed with US Government support and it may not be
  83. - sold, restricted or licensed.  You may duplicate this program provided
  84. - that this notice remains in all of the copies, and you may give it to
  85. - others provided they understand and agree to this condition.
  86. -
  87. - This program and the time protocol it uses are under development and the
  88. - implementation may change without notice.
  89. -
  90. - For questions or additional information, contact:
  91. -
  92. -   Judah Levine
  93. -   Time and Frequency Division
  94. -   NIST/847
  95. -   325 Broadway
  96. -   Boulder, Colorado 80303
  97. -   (303) 492 7785
  98. -   jlevine@time_a.timefreq.bldrdoc.gov
  99. --------------------------------------------------------------------------- */
  100. int main(int argc, char *argv[]) {
  101.  
  102. /* Internet socket access parameters */
  103.    char *cp   = NIST_TIME_INET_ADDRESS;   /* server address in . notation  */
  104.    int  pserv = NIST_TIME_PORT;           /* port for time service         */
  105.    long address;                          /* ip address                    */
  106.    struct sockaddr_in *sin;               /* socket address structure      */
  107.    int s;                                 /* socket number                 */
  108.    int length;                            /* size of message               */
  109.    char buf[132];                         /* holds message                 */
  110.  
  111.    time_t my_time, nist_time;             /* Time since epoch              */
  112.    time_t diff;                           /* time difference, local - NIST */
  113.  
  114. /* Values obtained from the internet message */
  115.    long mjd0  = UNIX_EPOCH_MJD;           /* MJD of the UNIX EPOCH         */
  116.    long mjd;                              /* holds parsed received mjd     */
  117.    int yr,mo,dy,hr,min,sec;               /* holds parsed received time    */
  118.    int day_light,                         /* Daylight savings flag         */
  119.        leap_sec,                          /* Leap second status            */
  120.        health;                            /* Health of server status       */
  121.  
  122. /* Local variables */
  123.    char achr;                             /* Random character              */
  124.    char let;                              /* command-line letter           */
  125.    long val;                              /* command line value            */
  126.  
  127. /* ---------------------------------------------------------------------------
  128. -  the following variables define what this program should do and what
  129. -  output should be produced.  The values below are the defaults which
  130. -  may be changed by characters on the command line as described below.
  131. -  The effect of each variable is as follows:
  132. -
  133. - Command-Line Switch   effect
  134. -  -m0      msg  = 0 Do not produce any messages; only time difference is 
  135. -                    written to standard output.
  136. -  -m1 or -M     = 1 Produce short messages.
  137. -  -m2           = 2 Produce longer messages.
  138. -
  139. -  -s0      set  = 0 Do not adjust local time.
  140. -  -s1 or -S     = 1 Adjust local time if server is healthy.
  141. -  -s2           = 2 Adjust local time even if server is unhealthy.
  142. -  -s3           = 3 Ask operator first.
  143. --------------------------------------------------------------------------- */
  144. int msg = 1;                        /* default is short messages           */
  145. int set = 3;                        /* default is ask before setting clock */
  146.  
  147. /* parse command line switches */
  148.    ++argv; --argc;                                 /* Skip command name */
  149.    while (sw(argc, argv[0], &let, &val) != 0) {    /* Switch present    */
  150.       switch (let) {
  151.          case '?':
  152.             case 'h':
  153.             case 'H':
  154.             PrintUsage();
  155.             return(EXIT_SUCCESS);
  156.          case 'm':
  157.             msg=val;
  158.             break;
  159.          case 's':
  160.             set=val;
  161.             break;
  162.          case 'S':
  163.             set=1;
  164.             break;
  165.          case 'M':
  166.             msg=1;
  167.             break;
  168.          default:
  169.             fprintf(stderr, "\nSwitch %c not recognized.\n", let);
  170.             break;
  171.       }
  172.       argc--;  /* decrement argument counter */
  173.       argv++;  /* and increment pointer      */
  174.    }
  175.  
  176. /* -----------------------------------------------------------------
  177. -- (1) Make sure we are using the TZ variable
  178. -- (2) Convert xxx.xxx internet address to internal format
  179. -- (3) allocate space for socket info, and fill int
  180. -- (4) Create socket
  181. -- (5) Connect to server.  Note this is a stream server and
  182. --     record boundaries are not preserved.
  183. -- (6) Query local time via time() call
  184. -- (7) Close socket and free allocated memory
  185. ----------------------------------------------------------------- */
  186.     _tzset();                                                        /* Get timezone from TZ */
  187.  
  188.    sock_init();                                       /* Initialize sockets */
  189.    if ( (address=inet_addr(cp)) == -1) {              /* Internal format */
  190.       fprintf(stderr,"Internet address error.\n");
  191.       return(EXIT_FAILURE);
  192.    }
  193.    if ( (sin = calloc(sizeof(*sin), 1)) == NULL) {    /* Allocate space  */
  194.       fprintf(stderr, "Unable to allocate memory for socket info.\n");
  195.       return(EXIT_FAILURE);
  196.    }
  197.    sin->sin_family      = AF_INET;                    /* Fill in request */
  198.    sin->sin_addr.s_addr = address;
  199.    sin->sin_port        = htons(pserv);
  200.  
  201. /* Now, create socket, open and read */
  202.    if ( (s = socket(AF_INET, SOCK_STREAM, 0) ) < 0) { /* Get a socket    */
  203.       fprintf(stderr,"Socket creation error.\n");
  204.       return(EXIT_FAILURE);
  205.    } else if (connect(s, (struct sockaddr *) sin, sizeof(*sin) ) < 0) {
  206.       fprintf(stderr, "Failed to connect to time server: %d\n", tcperrno());
  207.       return(EXIT_FAILURE);
  208.    }
  209.    if ( (length = recv(s, buf, sizeof(buf)-1, 0)) <= 0) {
  210.       fprintf(stderr, "No response from NIST server.\n");
  211.       soclose(s);
  212.       return(EXIT_FAILURE);
  213.    }
  214.    buf[length] = '\0';                                   /* terminate msg  */
  215.  
  216. /* Immediately, get local time as well for comparison */
  217.    if ( (my_time = time(NULL)) == (time_t) -1) {
  218.       fprintf(stderr, "Unable to determine local clock time\n");
  219.       return(EXIT_FAILURE);
  220.    }
  221.  
  222. /* And close socket, free allocated space */
  223.    soclose(s);                      /* Close port and free memory now      */
  224.    free(sin);
  225.  
  226. /* --------------------------------------------------------------------------
  227. -- convert received time to seconds since EPOCH and subtract this from the
  228. -- local time in the same units.  Since POSIX makes no specification about
  229. -- times less than 1 second, and the internet message only goes to seconds,
  230. -- look only this far and ignore smaller differences.  Fortunately, the delay
  231. -- in the net should be no more than about 0.05 seconds (according to NIST).
  232. --------------------------------------------------------------------------- */
  233.    sscanf(buf," %ld %2d-%2d-%2d %2d:%2d:%2d %d %d %d",
  234.       &mjd, &yr, &mo, &dy, &hr, &min, &sec, &day_light, &leap_sec, &health);
  235.    nist_time = 86400*(mjd-mjd0) + 3600*hr + 60*min + sec;
  236.    diff = my_time - nist_time;
  237.  
  238. /* --------------------------------------------------------------------------
  239. -- Output various reports to stdout depending on the setting of msg
  240. -- parameter.
  241. --------------------------------------------------------------------------- */
  242. /* Output desired messages */
  243.    if (msg != 0) {
  244.       printf(" Time message received:\n");
  245.       printf("                        D  L\n");
  246.       printf(" MJD  YY MM DD HH MM SS ST S H  Adv.%s", buf);
  247.    }
  248.    if (msg == 2) {                  /* longer messages selected */
  249.       if( (day_light == 0) || (day_light > 51) ) {
  250.          printf("Standard Time now in effect\n");
  251.          if (day_light > 51) 
  252.            printf("Change to Daylight Saving Time in %d days\n",day_light-51);
  253.       }
  254.       if( (day_light <= 50) && (day_light > 1) ) {
  255.          printf("Daylight Saving Time now in effect\n");
  256.          if (day_light > 1 && day_light != 50) 
  257.             printf("Change to Standard Time in %d days\n", day_light-1);
  258.       }
  259.       if (day_light == 1)  printf("Standard time begins at 2am today\n");
  260.       if (day_light == 51) printf("Daylight Saving Time begins at 2am today\n");
  261.       if (leap_sec == 1)   printf("Leap Second to be added at end of month\n");
  262.       if (leap_sec == 2)   printf("Second to be dropped at end of month\n");
  263.    }
  264.    if (msg == 0) {                           /* no messages except time diff */
  265.       printf("%ld", diff);
  266.    } else {
  267.       printf("Local Clock - NIST = %ld second(s)\n", diff);
  268.    }
  269.  
  270.  
  271. /* --------------------------------------------------------------------------
  272. -- Deal with possibly resetting the clock based on setting of set parameter
  273. --------------------------------------------------------------------------- */
  274.    if (set == 0 || diff == 0) {
  275.       if (diff == 0 && msg != 0) printf("\n No adjustment is needed.\n");
  276.       return(EXIT_SUCCESS);
  277.    }
  278.  
  279.    if( (health != 0) && (msg != 0) )
  280.       printf("\n Server is not healthy, adjustment not recommended.");
  281.  
  282.    achr = 'n';                         /* default is not to set */
  283.    if (set == 3) {                     /* action depends on answer to query */
  284.       printf("Do you want to adjust the local clock ? [y/n] ");
  285.       fflush(stdout);
  286.       achr = getchar();
  287.    }
  288.  
  289.    if ( (set==2) || (set==1 && health==0) || (tolower(achr) == 'y') ) {
  290.       if (ShiftTime(diff) != 0) {
  291.          fprintf(stderr, "Unable to modify system clock\n");
  292.          return(EXIT_FAILURE);
  293.         } else {
  294.             if (msg != 0) printf("Local clock time reset to NIST standard\n");
  295.       }
  296.    }
  297.  
  298.    return(EXIT_SUCCESS);
  299. }
  300.  
  301.  
  302. /* ---------------------------------------------------------------------------
  303. --
  304. -- Inputs:  diff - Time difference from current setting 
  305. --------------------------------------------------------------------------- */
  306. static int ShiftTime(time_t diff) {
  307.  
  308.    DATETIME os2_time;
  309.    struct tm *tm;
  310.    time_t newtime;
  311.    int rc;
  312.    
  313.    DosGetDateTime(&os2_time);                /* Fill in unknown components */
  314.    newtime = time(NULL) - diff;              /* Get corrected time      */
  315.    tm = localtime(&newtime);                 /* Fill in the structure   */
  316.  
  317.    os2_time.hours      = tm->tm_hour;
  318.    os2_time.minutes    = tm->tm_min;
  319.    os2_time.seconds    = tm->tm_sec;
  320.    os2_time.hundredths = 0;
  321.    os2_time.day        = tm->tm_mday;
  322.    os2_time.month      = tm->tm_mon  + 1;
  323.    os2_time.year       = tm->tm_year + 1900;
  324.    os2_time.weekday    = tm->tm_wday;
  325.  
  326.    rc = DosSetDateTime(&os2_time);
  327.    return(rc);
  328. }
  329.  
  330.  
  331. /* ---------------------------------------------------------------------------
  332. -  this subroutine parses switches on the command line. 
  333. -  switches are of the form -<letter><value>.  If one is found, a pointer to
  334. -  the letter is returned in let and a pointer to the value in val as a 
  335. -  long integer.
  336. -
  337. -  parameters argc and argv are passed in from the main calling program.
  338. -  Note that if argc = 0, no arguments are left.
  339. -  if a switch is decoded, the value of the function is 1, otherwise zero.
  340. -  
  341. -  a number following the letter is decoded as a decimal value unless it
  342. -  has a leading x in which case it is decoded as hexadecimal.
  343. --------------------------------------------------------------------------- */
  344. static int sw(int argc, char *arg, char *let, long *val) {
  345.  
  346. /* either nothing is left or what is left is not a switch */
  347.    if( (argc == 0) || (*arg != '-') ) {
  348.      *let = '\0';
  349.      *val = 0;
  350.      return(0);
  351.    }
  352.  
  353.    ++arg;                        /* Jump over the - sign */
  354.    *let = *arg++;                /* Letter option        */
  355.    if (*arg != 'x') {            /* if next char is not x, decode number */
  356.       *val = atol(arg);
  357.    } else {                      /* Use sscanf to interpret complex value */
  358.       sscanf(arg+1, "%lx", val);
  359.    }
  360.    return(1);
  361. }
  362.  
  363. /* ---------------------------------------------------------------------------
  364. - Routine to print the usage in response to a -? option.
  365. --------------------------------------------------------------------------- */
  366. static void PrintUsage(void) {
  367.  
  368.    fputs(
  369. "   Syntax: nistime [ options ]\n"
  370. "\n"
  371. "   Description:\n"
  372. "      This program connects to the daytime service on the NIST time server\n"
  373. "      time_a.timefreq.bldrdoc.gov using tcp/ip port 13.  The time server\n"
  374. "      returns the current time which is then compared with the time of the\n"
  375. "      local clock. The difference may be used to adjust the time of the\n"
  376. "      local clock using DosSetDateTime().\n"
  377. "\n"
  378. "   Options:\n"
  379. "     -m0  Terse mode.  Only the time difference in seconds is written\n"
  380. "          to standard output.  A positive value means local clock is fast.\n"
  381. "     -m1  Display short time messages. (also -M and default)\n"
  382. "     -m2  Display verbose time messages.\n"
  383. "\n"
  384. "     -s0  Do not set the local clock.\n"
  385. "     -s1  Set the local clock if the server is healthy. (also -S)\n"
  386. "     -s2  Set the local clock even if the server is not healthy.\n"
  387. "     -s3  Query operator before setting the clock. (default)\n"
  388. "\n"
  389. "Bugs: (1) This version does not estimate transmission delays in the network.\n"
  390. "          Not a big deal since time is set to the nearest second only.\n"
  391. "      (2) Time is instantaneously reset and thus may be non-monotonic.\n"
  392.    , stdout);
  393.  
  394.    return;
  395. }
  396.