home *** CD-ROM | disk | FTP | other *** search
/ nisttime.carsoncity.k12.mi.us / nisttime.carsoncity.k12.mi.us.tar / nisttime.carsoncity.k12.mi.us / pub / daytime / tcp_time_client.c < prev    next >
C/C++ Source or Header  |  2004-05-03  |  11KB  |  345 lines

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/socket.h>
  4. #include <sys/time.h>
  5. #include <netinet/in.h>
  6. #include <netdb.h>
  7. #include <arpa/inet.h>
  8. #include <string.h>
  9. #include <ctype.h>
  10. main(argc,argv)
  11. int argc;
  12. char *argv[];
  13. {
  14. /*
  15.     client process to connect to  the daytime service via port 13.
  16.     The client process uses the time message received to check (and
  17.     optionally to set) the time of the local clock.  the comparison 
  18.     assumes that the local clock keeps time in seconds from 1/1/70 
  19.     which is the UNIX standard, and it computes the time difference 
  20.     by converting the received MJD to seconds since 1/1/70 and adding 
  21.     the received hr, min and sec, also converted to seconds.  If the
  22.     local machine keeps time in some other way, then the comparison
  23.     method will have to change, but the rest should be okay.
  24.  
  25.     This software was developed with US Government support
  26.     and it may not be sold, restricted or licensed.  You 
  27.     may duplicate this program provided that this notice
  28.     remains in all of the copies, and you may give it to
  29.     others provided they understand and agree to this
  30.     condition.
  31.  
  32.     This program and the time protocol it uses are under 
  33.     development and the implementation may change without 
  34.     notice.
  35.  
  36.     For questions or additional information, contact:
  37.  
  38.     Judah Levine
  39.     Time and Frequency Division
  40.     NIST/847
  41.     325 Broadway
  42.     Boulder, Colorado 80305
  43.     (303) 492 7785
  44.     jlevine@boulder.nist.gov
  45. */
  46. long int address;        /* holds ip address */
  47. int pserv = 13;            /* daytime port number on server */
  48. char *cp;            /* server address in . notation */
  49. char *sp;            /* temporary for server address*/
  50. int aindots[4];            /* numerical host address in dot notation*/
  51. char addrbuf[20];        /* address formatted into dot notation*/
  52. int j;
  53. struct sockaddr_in sin;        /* socket address structure */
  54. int s;                /* socket number */
  55. int length;            /* size of message */
  56. char buf[132];            /* holds message */
  57. long int mjd0 = 40587;        /* MJD of 1/1/70 = origin of UNIX time system*/
  58. struct timeval tvv,tgg;        /* holds local time */
  59. long int mjd;            /* holds parsed received mjd*/
  60. int yr,mo,dy,hr,min,sec;    /* holds parsed received time */
  61. int dst,ls,health;        /* received flags: dst, ls and health */
  62. long int diff;            /* time difference, local - NIST */
  63. char cc;
  64. int stat;
  65. int sw();            /*parses command-line switches*/
  66. char let;            /*command-line letter*/
  67. long int val;            /*command line value*/
  68. struct hostent *serv0;        /*pointer to structure returned by gethost */
  69. /*
  70.     the following variables define what this program
  71.     should do and what output should be produced.  The
  72.     values below are the defaults which may be changed
  73.     by characters on the command line as described below.
  74.     The effect of each variable is as follows:
  75.  
  76. Command-Line Switch    effect
  77.     -m0        msg  = 0    Do not produce any messages;
  78.                     only time difference is written to
  79.                     standard output.
  80.  
  81.     -m1 or -M         = 1    Produce short messages.
  82.     -m2             = 2    Produce longer messages.
  83.  
  84.     -s0        set  = 0    Do not adjust local time.
  85.     -s1 or -S         = 1    Adjust local time if server is healthy.
  86.     -s2                 = 2    Adjust local time even if server is 
  87.                     unhealthy.
  88.     -s3             = 3    Ask operator first.
  89.  
  90.     -u<j>        use server number j, where j is the index number
  91.             of the NIST server chosen from the following list.
  92.             the first server on the list is number 1, the
  93.             second is number 2, etc.
  94.             the default is to use the first server, which
  95.             is number 1.
  96.             note that the array uses C indexing, so that the
  97.             first entry in the array is number 0, etc.
  98.             thus any user response is decremented before
  99.             being used.
  100.  
  101.     -u0        the name of the server is given as the next
  102.             parameter on the command line. the name can
  103.             be either a name or an ip address in dot
  104.             notation. The entry will be taken as a name
  105.             if the first non-blank character is not a
  106.             digit.
  107. */
  108. int msg =1;        /*default is short messages */
  109. int set =3;        /*default is ask before setting clock */
  110. int use_serv=0;        /*use server 1 by default*/
  111. /*
  112.     the following is a list of the servers operated by
  113.     NIST. All of them will support the daytime protocol
  114.     in the format that this program expects.
  115.  
  116.     Each server may be specified either by name, as in
  117.     time.nist.gov or by ip as in 192.43.244.18. If the
  118.     first character of the specification is a digit, then
  119.     the numerical format is assumed. If a name is entered,
  120.     it is converted to the corresponding ip address using
  121.     the standard DNS query. The program will fail if the
  122.     DNS query cannot find the ip number of the server
  123.  
  124.     For more information about these servers, look at the
  125.     entry for the Internet Time Service on the Time and
  126.     Frequency Division homepage at www.boulder.nist.gov/timefreq
  127. */
  128. #define NUMSRV 15
  129. char *serv_ip[NUMSRV]= {"64.236.96.53"   ,/*nist1.aol-va.truetime.com*/
  130.             "128.138.140.44" ,/*utcnist.colorado.edu*/
  131.             "207.200.81.113" ,/*nist1.aol-ca.truetime.com*/
  132.             "216.200.93.8"   ,/*nist1-dc.glassey.com*/
  133.             "63.149.208.50"  ,/*nist1.datum.com*/
  134.             "208.184.49.9"   ,/*nist1-ny.glassey.com*/
  135.             "207.126.103.204",/*nist1-sj.glassey.com*/
  136.             "129.6.15.28"    ,/*time-a.nist.gov*/
  137.             "129.6.15.29"    ,/*time-b.nist.gov*/
  138.             "132.163.4.101"  ,/*time-a.timefreq.bldrdoc.gov*/
  139.             "132.163.4.102"  ,/*time-b.timefreq.bldrdoc.gov*/
  140.             "132.163.4.103"  ,/*time-c.timefreq.bldrdoc.gov*/
  141.             "192.43.244.18"  ,/*time.nist.gov*/
  142.             "131.107.1.10"   ,/*time-nw.nist.gov*/  
  143.             "utcnist.colorado.edu"/*DNS entry =128.138.140.44*/
  144.             }; 
  145. /*
  146.     parse command line 
  147. */
  148.     while( sw(argc,argv,&let,&val) != 0) /*switch is present*/
  149.        {
  150.        switch(let)
  151.           {
  152.           case 'm':
  153.         msg=val;
  154.         break;
  155.           case 's':
  156.         set=val;
  157.         break;
  158.           case 'S':
  159.         set=1;
  160.         break;
  161.           case 'M':
  162.         msg=1;
  163.         break;
  164.           case 'u':        /*specifies which server to use*/
  165.         if(val == 0)     /*next parameter specifies server*/
  166.            {
  167.            argc--;
  168.            argv++;    /*skip over the switch*/
  169.            if(argc <= 1)
  170.             {
  171.             printf("\n Expected server name is missing.\n\n");
  172.             exit();
  173.            }
  174.            cp=argv[1];    /*save the next parameter as the server name*/
  175.            use_serv=999;    /*set flag*/
  176.            break;
  177.         }
  178.         /*  server 1 has internal index 0 */
  179.         use_serv=val-1;
  180.         /*  check if entry is out of range*/
  181.         if(use_serv < 0) use_serv=0;
  182.         if(use_serv >= NUMSRV) use_serv=NUMSRV - 1; 
  183.         break;
  184.           default:
  185.         fprintf(stderr,"\nSwitch %c not recognized.",let);
  186.         break;
  187.        }
  188.        argc--;    /*decrement argument counter */
  189.        argv++;    /*and increment pointer */
  190.     }
  191. /*
  192.     get internet address of selected server
  193.     if the first digit is not a digit then lookup
  194.     the host name and get its ip address. the program
  195.     will fail and exit if the name cannot be resolved.
  196. */
  197.     if(use_serv != 999) cp=serv_ip[use_serv];
  198.     if(!isdigit(*cp))     /*first char not a digit, must convert name*/
  199.        {
  200.        if( (serv0=gethostbyname(cp)) == NULL)
  201.         {
  202.         printf("\n Cannot resolve name %s",cp);
  203.         exit();
  204.        }
  205.        if(serv0->h_length != 4)
  206.           {
  207.           printf("\nLength of host address (= %d) is wrong, 4 expected.",
  208.             serv0->h_length);
  209.           exit();
  210.        }
  211.        sp= serv0->h_addr_list[0];
  212.        for(j=0; j<4; j++)    /*store and convert address*/
  213.           {
  214.           aindots[j]= *(sp++);
  215.           aindots[j] &= 0xff;    /*turn off sign extension*/
  216.        }
  217.        sprintf(addrbuf,"%d.%d.%d.%d",
  218.         aindots[0],aindots[1],aindots[2],aindots[3]);
  219.        cp= addrbuf;
  220.     }
  221.     printf("\n Using server at address %s",cp);
  222. /*
  223.     convert address to internal format
  224. */
  225.     if( (address=inet_addr(cp) ) == -1)
  226.        {
  227.        fprintf(stderr,"\n Internet address error.");
  228.        exit(1);
  229.     }
  230.     bzero( (char *)&sin,sizeof(sin));
  231.     sin.sin_addr.s_addr=address;
  232.     sin.sin_family=AF_INET;
  233.     sin.sin_port=htons(pserv);
  234. /*
  235.     create the socket and then connect to the server
  236.     note that this is a stream socket and that record
  237.     boundaries are not preserved.
  238. */
  239.     if( (s=socket(AF_INET,SOCK_STREAM,0) ) < 0)
  240.        {
  241.        fprintf(stderr,"\n Socket creation error.");
  242.        exit(1);
  243.     }
  244.     if(connect(s, (struct sockaddr *) &sin, sizeof(sin) ) < 0)
  245.        {
  246.        perror(" time server Connect failed --");
  247.        exit(1);
  248.     }
  249.     length=read(s,buf,80);
  250.     gettimeofday(&tvv,0);    /*get time as soon as read completes*/
  251.     if(length <= 0) 
  252.        {
  253.        fprintf(stderr,"\n No response from server.");
  254.        close(s);
  255.        exit(1);
  256.     }
  257.     buf[length]= '\0';   /*add terminating null */
  258.     if(msg != 0)
  259.        {
  260.        printf("\n Time message received:");
  261.        printf("\n                        D  L");
  262.        printf("\n MJD  YY MM DD HH MM SS ST S H  Adv.");
  263.        printf("%s\n",buf);
  264.     }
  265.     close(s);
  266. /*
  267.     now compute difference between local time and
  268.     received time.
  269. */
  270.     sscanf(buf," %ld %2d-%2d-%2d %2d:%2d:%2d %d %d %d",
  271.         &mjd,&yr,&mo,&dy,&hr,&min,&sec,&dst,&ls,&health);
  272.     if(msg == 2)        /*longer messages selected */
  273.        {
  274.        if( (dst == 0)  || (dst > 51) )
  275.           {
  276.           printf("\nStandard Time now in effect.");
  277.           if(dst > 51) 
  278.         printf("\nChange to Daylight Saving Time in %d days.",dst-51);
  279.        }
  280.        if( (dst <= 50) && (dst > 1) )
  281.           {
  282.           printf("\nDaylight Saving Time now in effect.");
  283.           if( (dst > 1)  && (dst < 50) )
  284.         printf("\nChange to Standard Time in %d days.",dst-1);
  285.        }
  286.        if(dst == 1) printf("\nStandard time begins at 2am today.");
  287.        if(dst == 51)printf("\nDaylight Saving Time begins at 2am today.");
  288.        if(ls ==1) printf("\nLeap Second to be added at end of month.");
  289.        if(ls ==2) printf("\nSecond to be dropped at end of month.");
  290.     }
  291. /*
  292.     convert received time to seconds since 1/1/70 and subtract
  293.     this from the local time in the same units.
  294.     Since no correction has been made for the network delay,
  295.     this difference cannot be taken too seriously, although
  296.     the delay in a local network should be no more than about
  297.     0.05 seconds.
  298. */
  299.     diff=tvv.tv_sec - 86400*(mjd-mjd0) - 3600*hr -60*min - sec;
  300.     if(tvv.tv_usec >= 500000l) diff++;    /*round microseconds */
  301.     if(msg == 0)        /*no messages except time diff.*/
  302.        printf("%ld",diff);
  303.     else
  304.        printf("\nLocal Clock - NIST = %ld second(s).",diff);
  305.     if(diff == 0)
  306.       {
  307.       if(msg != 0) printf("\n No adjustment is needed.\n");
  308.       exit(0);
  309.     }
  310.     if(set == 0) exit(0);
  311.     if( (health != 0) && (msg != 0) )
  312.        printf("\n Server is not healthy, adjustment not recommended.");
  313.     cc = 'n';    /*default is not to set */
  314.     if(set == 3)    /*action depends on answer to query*/
  315.        {
  316.        printf("\n Do you want to adjust the local clock ? [y/n] ");
  317.        cc=getchar();
  318.     }
  319.     if( (set == 2) ||              /*always set */
  320.         ( (set == 1) && (health == 0) ) ||   /*set if healthy*/
  321.         (cc == 'y') ||             /*set if response yes*/
  322.         (cc == 'Y') )
  323.        {
  324.        if(diff > 2100l)
  325.           {
  326.           printf("\n Adjustment limited to -2100 s.");
  327.           diff= 2100l;
  328.        }
  329.        if(diff < -2100l)
  330.           {
  331.           printf("\n Adjustment limited to +2100 s.");
  332.           diff= -2100l;
  333.        }
  334.        tvv.tv_sec= -diff;
  335.        tvv.tv_usec = 0;
  336.        stat=adjtime(&tvv,&tgg);
  337.        if(msg != 0)
  338.           {
  339.           if(stat == 0) printf("\n Adjustment was started.\n");
  340.           else perror("Adjustment failed. ");
  341.        }
  342.     }
  343.     exit(0);
  344. }
  345.