afsconfig-and-rcsid-all-around-20010705
[openafs.git] / src / ntp / ntp.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11  * This program expects a list of host names.  It will send off a
12  * network time protocol packet and print out the replies on the
13  * terminal.
14  * 
15  * Example:
16  *
17  *  % ntp umd1.umd.edu
18  *  Packet from: [128.8.10.1]
19  *  Leap 0, version 1, mode Server, poll 6, precision -10 stratum 1 (WWVB)
20  *  Synch Distance is 0000.1999  0.099991
21  *  Synch Dispersion is 0000.0000  0.000000
22  *  Reference Timestamp is a7bea6c3.88b40000 Tue Mar  7 14:06:43 1989
23  *  Originate Timestamp is a7bea6d7.d7e6e652 Tue Mar  7 14:07:03 1989
24  *  Receive Timestamp is   a7bea6d7.cf1a0000 Tue Mar  7 14:07:03 1989
25  *  Transmit Timestamp is  a7bea6d8.0ccc0000 Tue Mar  7 14:07:04 1989
26  *  Input Timestamp is     a7bea6d8.1a77e5ea Tue Mar  7 14:07:04 1989
27  *  umd1: delay:0.019028 offset:-0.043890
28  *  Tue Mar  7 14:07:04 1989
29  *
30  */
31
32 #include <afs/param.h>
33 #include <afsconfig.h>
34
35 RCSID("$Header$");
36
37 #include <stdio.h>
38 #ifdef  AFS_AIX32_ENV
39 #include <signal.h>
40 #endif
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/time.h>
44 #include <sys/uio.h>
45 #include <sys/socket.h>
46 #include <sys/ioctl.h>
47
48 #include <netinet/in.h>
49 #include <netinet/in_systm.h>
50 #include <netinet/ip.h>
51 #include <netinet/udp.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #include <strings.h>
55
56 #ifdef AFS_AIX32_ENV
57 #include <sys/select.h>
58 #endif
59
60 #include <errno.h>
61 #include "ntp.h"
62
63 char *modename[8] = {
64         "Unspecified",
65         "Symmetric Active",
66         "Symmetric Passive",
67         "Client",
68         "Server",
69         "Broadcast",
70         "Reserved-1",
71         "Reserved-2"
72         };
73
74 #define RETRY_COUNT     2       /* number of times we want to retry */
75 #define TIME_OUT        10      /* time to wait for reply, in secs */
76
77
78 struct sockaddr_in sin = {AF_INET};
79 struct sockaddr_in dst = {AF_INET};
80 struct servent *sp;
81 extern double ul_fixed_to_double(), s_fixed_to_double();
82 extern int errno;
83 int set, verbose, force;
84 int debug;
85 extern int optind;
86
87 #include "AFS_component_version_number.c"
88
89 main(argc, argv)
90         int argc;
91         char *argv[];
92 {
93         struct hostent *hp;
94         struct in_addr clock_host;
95         struct l_fixedpt in_timestamp;
96         static struct ntpdata ntp_data;
97         struct ntpdata *pkt = &ntp_data;
98         struct timeval tp, timeout;
99         int host, n, retry, s;
100         fd_set readfds;
101         int dstlen = sizeof(dst);
102         double t1, t2, t3, t4, offset, delay;
103         char ref_clock[5];
104         time_t net_time;
105
106 #ifdef  AFS_AIX32_ENV
107         /*
108          * The following signal action for AIX is necessary so that in case of a 
109          * crash (i.e. core is generated) we can include the user's data section 
110          * in the core dump. Unfortunately, by default, only a partial core is
111          * generated which, in many cases, isn't too useful.
112          */
113         struct sigaction nsa;
114     
115         sigemptyset(&nsa.sa_mask);
116         nsa.sa_handler = SIG_DFL;
117         nsa.sa_flags = SA_FULLDUMP;
118         sigaction(SIGSEGV, &nsa, NULL);
119 #endif
120         ref_clock[4] = '\0';
121         timeout.tv_sec = TIME_OUT;
122         timeout.tv_usec = 0;
123         retry = RETRY_COUNT;
124
125         sp = getservbyname("ntp", "udp");
126         if (sp == NULL) {
127                 fprintf(stderr, "udp/ntp: service unknown; using default %d\n",
128                         NTP_PORT);
129                 dst.sin_port = htons(NTP_PORT);
130         } else
131                 dst.sin_port = sp->s_port;
132
133         dst.sin_family = AF_INET;
134         while ((n = getopt(argc, argv, "vsf")) != EOF) {
135                 switch (n) {
136                 case 'v':
137                         verbose = 1;
138                         break;
139                 case 's':
140                         set = 1;
141                         break;
142                 case 'f':
143                         force = 1;
144                         break;
145                 }
146         }
147         for (host = optind; host < argc; ++host) {
148                 afs_int32       HostAddr;
149
150                 if (argv[host] == NULL)
151                         continue;
152
153                 hp = NULL;
154                 HostAddr = inet_addr(argv[host]);
155                 dst.sin_addr.s_addr = (afs_uint32) HostAddr;
156                 if (HostAddr == -1) {
157                         hp = gethostbyname(argv[host]);
158                         if (hp == NULL) {
159                                 fprintf(stderr, "\nNo such host: %s\n",
160                                         argv[host]);
161                                 continue;
162                         }
163                         bcopy(hp->h_addr, (char *) &dst.sin_addr,hp->h_length);
164                 }
165
166                 bzero((char *)pkt, sizeof(ntp_data));
167
168                 pkt->status = NTPVERSION_1 | NO_WARNING | MODE_CLIENT;
169                 pkt->stratum = UNSPECIFIED;
170                 pkt->ppoll = 0;
171
172                 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
173                         perror("ntp socket");
174                         exit(1);
175                 }
176
177                 FD_ZERO(&readfds);
178                 FD_SET(s, &readfds);    /* since it's always modified on ret */
179
180                 if (connect(s, (struct sockaddr *)&dst, dstlen)) {
181                         perror("connect");
182                         exit(1);
183                 }
184
185                 /*
186                  * Needed to fill in the time stamp fields
187                  */
188                 (void) gettimeofday(&tp, (struct timezone *) 0);
189                 tstamp(&pkt->xmt, &tp);
190
191                 if (send(s, (char *) pkt, sizeof(ntp_data), 0) < 0) {
192                         perror("send");
193                         exit(1);
194                 }
195
196                 /*
197                  * Wait for the reply by watching the file descriptor 
198                  */
199                 if ((n = select(FD_SETSIZE, (fd_set *) & readfds, (fd_set *) 0,
200                                 (fd_set *) 0, &timeout)) < 0) {
201                         perror("ntp select");
202                         exit(1);
203                 }
204
205                 if (n == 0) {
206                         fprintf(stderr,"*Timeout*\n");
207                         if (--retry)
208                                 --host;
209                         else {
210                                 fprintf(stderr,"Host %s is not responding\n",
211                                        argv[host]);
212                                 retry = RETRY_COUNT;
213                         }
214                         continue;
215                 }
216                 if ((recvfrom(s, (char *) pkt, sizeof(ntp_data), 0,
217                               (struct sockaddr *) &sin, &dstlen)) < 0) {
218                         perror("recvfrom");
219                         exit(1);
220                 }
221                 (void) gettimeofday(&tp, (struct timezone *) 0);
222                 tstamp(&in_timestamp, &tp);
223
224                 close(s);
225                 if (verbose) {
226                         printf("Packet from: [%s]\n", inet_ntoa(sin.sin_addr));
227                         printf("Leap %d, version %d, mode %s, poll %d, precision %d stratum %d",
228                                (pkt->status & LEAPMASK) >> 6, 
229                                (pkt->status & VERSIONMASK) >> 3,
230                                modename[pkt->status & MODEMASK],
231                                pkt->ppoll, pkt->precision, pkt->stratum);
232                         switch (pkt->stratum) {
233                         case 0:
234                         case 1:
235                                 (void) strncpy(ref_clock, (char *) &pkt->refid, 4);
236                                 ref_clock[4] = '\0';
237                                 printf(" (%s)\n", ref_clock);
238                                 break;
239                         default:
240                                 clock_host.s_addr = (afs_uint32) pkt->refid;
241                                 printf(" [%s]\n", inet_ntoa(clock_host));
242                                 break;
243                         }
244                         printf("Synch Distance is %04X.%04x  %f\n",
245                                ntohs(pkt->distance.int_part),
246                                ntohs(pkt->distance.fraction),
247                                s_fixed_to_double(&pkt->distance));
248
249                         printf("Synch Dispersion is %04X.%04x  %f\n",
250                                ntohs(pkt->dispersion.int_part),
251                                ntohs(pkt->dispersion.fraction),
252                                s_fixed_to_double(&pkt->dispersion));
253
254                         net_time = ntohl(pkt->reftime.int_part) - JAN_1970;
255                         printf("Reference Timestamp is %08lx.%08lx %s",
256                                ntohl(pkt->reftime.int_part),
257                                ntohl(pkt->reftime.fraction),
258                                ctime(&net_time));
259
260                         net_time = ntohl(pkt->org.int_part) - JAN_1970;
261                         printf("Originate Timestamp is %08lx.%08lx %s",
262                                ntohl(pkt->org.int_part),
263                                ntohl(pkt->org.fraction),
264                                ctime(&net_time));
265
266                         net_time = ntohl(pkt->rec.int_part) - JAN_1970;
267                         printf("Receive Timestamp is   %08lx.%08lx %s",
268                                ntohl(pkt->rec.int_part),
269                                ntohl(pkt->rec.fraction),
270                                ctime(&net_time));
271
272                         net_time = ntohl(pkt->xmt.int_part) - JAN_1970;
273                         printf("Transmit Timestamp is  %08lx.%08lx %s",
274                                ntohl(pkt->xmt.int_part),
275                                ntohl(pkt->xmt.fraction),
276                                ctime(&net_time));
277                 }
278                 t1 = ul_fixed_to_double(&pkt->org);
279                 t2 = ul_fixed_to_double(&pkt->rec);
280                 t3 = ul_fixed_to_double(&pkt->xmt);
281                 t4 = ul_fixed_to_double(&in_timestamp);
282
283                 net_time = ntohl(in_timestamp.int_part) - JAN_1970;
284                 if (verbose) 
285                         printf("Input Timestamp is     %08lx.%08lx %s",
286                                ntohl(in_timestamp.int_part),
287                                ntohl(in_timestamp.fraction), ctime(&net_time));
288
289                 delay = (t4 - t1) - (t3 - t2);
290                 offset = (t2 - t1) + (t3 - t4);
291                 offset = offset / 2.0;
292                 printf("%.20s: delay:%f offset:%f  ",
293                        hp ? hp->h_name : argv[host],
294                        delay, offset);
295                 net_time = ntohl(pkt->xmt.int_part) - JAN_1970 + delay;
296                 fputs(ctime(&net_time), stdout);
297                 (void)fflush(stdout);
298
299                 if (!set)
300                         continue;
301
302                 if ((offset < 0 ? -offset  : offset) > WAYTOOBIG && !force) {
303                         fprintf(stderr, "Offset too large - use -f option to force clock set.\n");
304                         continue;
305                 }
306
307                 if (pkt->status & LEAPMASK == ALARM) {
308                         fprintf(stderr, "Can't set time from %s - unsynchronized\n",
309                                 argv[host]);
310                         continue;
311                 }
312
313                 /* set the clock */
314                 gettimeofday(&tp, (struct timezone *) 0);
315                 offset += tp.tv_sec;
316                 offset += tp.tv_usec / 1000000.0;
317                 tp.tv_sec = offset;
318                 tp.tv_usec = (offset - tp.tv_sec) * 1000000.0;
319
320                 if (settimeofday(&tp, (struct timezone *) 0)) {
321                         perror("Can't set time (settimeofday)");
322                 } else
323                         set = 0;
324         }                       /* end of for each host */
325         exit(0);
326 }                               /* end of main */