home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: InfoMgt / InfoMgt.zip / nistime.zip / nistime.c next >
C/C++ Source or Header  |  1999-10-29  |  17KB  |  397 lines

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