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 / udp_time_client.c < prev    next >
C/C++ Source or Header  |  2004-05-03  |  9KB  |  261 lines

  1. main (argc,argv)
  2. int argc;
  3. char *argv[];
  4. {
  5. /*
  6.     client process to connect to  the time service via port 37 using
  7.     udp.  The client process uses the time message received to check 
  8.     (and optionally to set) the time of the local clock.  the comparison 
  9.     assumes that the local clock keeps time in seconds from 1/1/70 
  10.     which is the UNIX standard, and it assumes that the received time
  11.     is in seconds since 1900.0 to conform to rfc868.  It computes the
  12.     time difference by subtracting 2208988800 from the received time
  13.     to convert it to seconds since 1970 and then makes the comparison
  14.     directly. If the local machine keeps time in some other way, then 
  15.     the comparison method will have to change, but the rest should be 
  16.     okay.
  17.  
  18.     This software was developed with US Government support
  19.     and it may not be sold, restricted or licensed.  You 
  20.     may duplicate this program provided that this notice
  21.     remains in all of the copies, and you may give it to
  22.     others provided they understand and agree to this
  23.     condition.
  24.  
  25.     This program and the time protocol it uses are under 
  26.     development and the implementation may change without 
  27.     notice.
  28.  
  29.     For questions or additional information, contact:
  30.  
  31.     Judah Levine
  32.     Time and Frequency Division
  33.     NIST/847
  34.     325 Broadway
  35.     Boulder, Colorado 80305
  36.     (303) 492 7785
  37.     jlevine@boulder.nist.gov
  38. */
  39. #include <stdio.h>
  40. #include <sys/types.h>
  41. #include <sys/socket.h>
  42. #include <sys/time.h>
  43. #include <netinet/in.h>
  44. #include <netdb.h>
  45. #include <arpa/inet.h>
  46. #include <string.h>
  47. #include <ctype.h>
  48. long int address;        /* holds ip address */
  49. int pserv = 37;        /* time port number on server */
  50. char *cp;            /* server address in . notation */
  51. char *sp;            /* temporary for server address*/
  52. int aindots[4];                 /* numerical host address in dot notation*/
  53. char addrbuf[20];               /* address formatted into dot notation*/
  54. int j;
  55. struct sockaddr_in sin;        /* socket address structure */
  56. int s;                /* socket number */
  57. int length;            /* size of message */
  58. char buf[10];            /* holds message */
  59. unsigned long recdtime;        /* received time in local byte order */
  60. unsigned long dorg = 2208988800ul;    /*seconds from 1900.0 -> 1970.0*/
  61. unsigned long netcons;        /*received time in network order */
  62. struct timeval tvv,tgg;        /* holds local time */
  63. long int diff;            /* time difference, local - NIST */
  64. char cc;
  65. int stat;
  66. int use_serv=0;            /*use server number 1 by default,see below*/
  67. int sw();            /*parses command line switches*/
  68. char let;            /*switch letter*/
  69. long int val;            /*value associated with switch*/
  70. struct hostent *serv0;          /*pointer to structure returned by gethost */
  71. /*
  72.         the following is a list of the servers operated by
  73.         NIST. All of them will support the daytime protocol
  74.         in the format that this program expects.
  75.  
  76.         Each server may be specified either by name, as in
  77.         time.nist.gov or by ip as in 192.43.244.18. If the
  78.         first character of the specification is a digit, then
  79.         the numerical format is assumed. If a name is entered,
  80.         it is converted to the corresponding ip address using
  81.         the standard DNS query. The program will fail if the
  82.         DNS query cannot find the ip number of the server
  83.  
  84.  
  85.         For more information about these servers, look at the
  86.         entry for the Internet Time Service on the Time and
  87.         Frequency Division homepage at www.boulder.nist.gov/timefreq
  88. */
  89. #define NUMSRV 15
  90. char *serv_ip[NUMSRV]= {"64.236.96.53"   ,/*nist1.aol-va.truetime.com*/
  91.                         "128.138.140.44" ,/*utcnist.colorado.edu*/
  92.                         "207.200.81.113" ,/*nist1.aol-ca.truetime.com*/
  93.                         "216.200.93.8"   ,/*nist1-dc.glassey.com*/
  94.                         "63.149.208.50"  ,/*nist1.datum.com*/
  95.                         "208.184.49.9"   ,/*nist1-ny.glassey.com*/
  96.                         "207.126.103.204",/*nist1-sj.glassey.com*/
  97.                         "129.6.15.28"    ,/*time-a.nist.gov*/
  98.                         "129.6.15.29"    ,/*time-b.nist.gov*/
  99.                         "132.163.4.101"  ,/*time-a.timefreq.bldrdoc.gov*/
  100.                         "132.163.4.102"  ,/*time-b.timefreq.bldrdoc.gov*/
  101.                         "132.163.4.103"  ,/*time-c.timefreq.bldrdoc.gov*/
  102.                         "192.43.244.18"  ,/*time.nist.gov*/
  103.                         "131.107.1.10"   ,/*time-nw.nist.gov*/
  104.             "utcnist.colorado.edu" /*DNS entry = 128.138.140.44*/
  105.             };
  106. /*
  107.     parse command line switch to select server
  108.  
  109.        -u<j>           use server number j, where j is the index number
  110.                         of the NIST server chosen from the following list.
  111.                         the first server on the list is number 1, the
  112.                         second is number 2, etc.
  113.                         the default is to use the first server, which
  114.                         is number 1.
  115.                         note that the array uses C indexing, so that the
  116.                         first entry in the array is number 0, etc.
  117.                         thus any user response is decremented before
  118.                         being used.
  119.  
  120.         -u0             the name of the server is given as the next
  121.                         parameter on the command line. the name can
  122.                         be either a name or an ip address in dot
  123.                         notation. The entry will be taken as a name
  124.                         if the first non-blank character is not a
  125.                         digit.
  126. */
  127.        while( sw(argc,argv,&let,&val) != 0) /*switch is present*/
  128.            {
  129.            switch(let)
  130.               {
  131.               case 'u':
  132.                if(val == 0)    /*next parameter specifies server*/
  133.                    {
  134.                    argc--;
  135.                    argv++;      /*skip over the switch*/
  136.                    if(argc <= 1)
  137.                         {
  138.                         printf("\n Expected server name is missing.\n\n");
  139.                         exit();
  140.                    }
  141.                    cp=argv[1];  /*save the next parameter as the server name*/
  142.                    use_serv=999;        /*set flag*/
  143.                    break;
  144.                 }
  145.                 /*  server 1 has internal index 0 */
  146.                 use_serv=val-1;
  147.                 /*  check if entry is out of range*/
  148.                 if(use_serv < 0) use_serv=0;
  149.                 if(use_serv >= NUMSRV) use_serv=NUMSRV - 1;
  150.                 break;
  151.              default:
  152.                 fprintf(stderr,"\nSwitch %c not recognized.",let);
  153.                 break;
  154.            }
  155.            argc--;      /*decrement argument counter */
  156.            argv++;      /*and increment pointer */
  157.         }
  158. /*
  159.     internet address of selected server
  160. */
  161.     if(use_serv != 999) cp=serv_ip[use_serv];
  162.         if(!isdigit(*cp))       /*first char not a digit, must convert name*/
  163.            {
  164.            if( (serv0=gethostbyname(cp)) == NULL)
  165.                 {
  166.                 printf("\n Cannot resolve name %s",cp);
  167.                 exit();
  168.            }
  169.            if(serv0->h_length != 4)
  170.               {
  171.               printf("\nLength of host address (= %d) is wrong, 4 expected.",
  172.                         serv0->h_length);
  173.               exit();
  174.            }
  175.            sp= serv0->h_addr_list[0];
  176.            for(j=0; j<4; j++)   /*store and convert address*/
  177.               {
  178.               aindots[j]= *(sp++);
  179.               aindots[j] &= 0xff;       /*turn off sign extension*/
  180.            }
  181.            sprintf(addrbuf,"%d.%d.%d.%d",
  182.                 aindots[0],aindots[1],aindots[2],aindots[3]);
  183.        cp= addrbuf;
  184.         }
  185.         printf("\n Using server at address %s",cp);
  186. /*
  187.     convert address to internal format
  188. */
  189.     if( (address=inet_addr(cp) ) == -1)
  190.        {
  191.        fprintf(stderr,"\n Internet address error.");
  192.        exit(1);
  193.     }
  194.     bzero( (char *)&sin,sizeof(sin));
  195.     sin.sin_addr.s_addr=address;
  196.     sin.sin_family=AF_INET;
  197.     sin.sin_port=htons(pserv);
  198. /*
  199.     create the socket and then connect to the server
  200.     note that this is a UDP datagram socket 
  201. */
  202.     if( (s=socket(AF_INET,SOCK_DGRAM,0) ) < 0)
  203.        {
  204.        fprintf(stderr,"\n Socket creation error.");
  205.        exit(1);
  206.     }
  207.     if(connect(s, (struct sockaddr *) &sin, sizeof(sin) ) < 0)
  208.        {
  209.        perror(" time server Connect failed --");
  210.        exit(1);
  211.     }
  212. /*
  213.     send a UDP datagram to start the server 
  214.     going.
  215. */
  216.     write(s,buf,10);
  217.     length=read(s,&netcons,4);
  218.     gettimeofday(&tvv,0);    /*get time as soon as read completes*/
  219.     if(length <= 0) 
  220.        {
  221.        fprintf(stderr,"\n No response from server.");
  222.        close(s);
  223.        exit(1);
  224.     }
  225.     recdtime=ntohl(netcons);    /*convert to local byte order */
  226.     recdtime -= dorg;    /*convert to seconds since 1970*/
  227.     close(s);
  228. /*
  229.     now compute difference between local time and
  230.     received time.
  231. */
  232.     diff=tvv.tv_sec - recdtime;
  233.     if(tvv.tv_usec >= 500000l) diff++;    /*round microseconds */
  234.     printf("\nLocal Clock - NIST = %ld second(s).",diff);
  235.     if(diff == 0)
  236.        {
  237.        printf("\n No adjustment is needed.\n");
  238.        exit();
  239.     }
  240.     printf("\n Do you want to adjust the local clock ? [y/n] ");
  241.     cc=getchar();
  242.     if( (cc == 'y') || (cc == 'Y') )
  243.        {
  244.        if(diff > 2100l)
  245.           {
  246.           printf("\n Adjustment limited to -2100 s.");
  247.           diff= 2100l;
  248.        }
  249.        if(diff < -2100l)
  250.           {
  251.           printf("\n Adjustment limited to +2100 s.");
  252.          diff= -2100l;
  253.        }
  254.        tvv.tv_sec= -diff;
  255.        tvv.tv_usec = 0;
  256.        stat=adjtime(&tvv,&tgg);
  257.        if(stat == 0) printf("\n Adjustment was performed.\n");
  258.        else perror("Adjustment failed. ");
  259.     }
  260. }
  261.