2 * ntpclient.c - NTP client
4 * Copyright 1997, 1999, 2000, 2003 Larry Doolittle <larry@doolittle.boa.org>
5 * Last hack: July 5, 2003
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License (Version 2,
9 * June 1991) as published by the Free Software Foundation. At the
10 * time of writing, that license was published by the FSF with the URL
11 * http://www.gnu.org/copyleft/gpl.html, and is incorporated herein by
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * Possible future improvements:
20 * - Double check that the originate timestamp in the received packet
21 * corresponds to what we sent.
22 * - Verify that the return packet came from the host we think
23 * we're talking to. Not necessarily useful since UDP packets
24 * are so easy to forge.
25 * - Write more documentation :-(
27 * Compile with -D_PRECISION_SIOCGSTAMP if your machine really has it.
28 * There are patches floating around to add this to Linux, but
29 * usually you only get an answer to the nearest jiffy.
30 * Hint for Linux hacker wannabes: look at the usage of get_fast_time()
31 * in net/core/dev.c, and its definition in kernel/time.c .
33 * If the compile gives you any flak, check below in the section
34 * labelled "XXXX fixme - non-automatic build configuration".
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <netdb.h> /* gethostbyname */
44 #include <arpa/inet.h>
48 #ifdef _PRECISION_SIOCGSTAMP
49 #include <sys/ioctl.h>
56 /* XXXX fixme - non-automatic build configuration */
58 #include <sys/utsname.h>
60 typedef u_int32_t __u32;
61 #include <sys/timex.h>
63 extern struct hostent *gethostbyname(const char *name);
65 #define herror(hostname) \
66 fprintf(stderr,"Error %d looking up hostname %s\n", h_errno,hostname)
67 typedef uint32_t __u32;
70 #define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */
71 #define NTP_PORT (123)
73 /* How to multiply by 4294.967296 quickly (and not quite exactly)
74 * without using floating point or greater than 32-bit integers.
75 * If you want to fix the last 12 microseconds of error, add in
78 #define NTPFRAC(x) ( 4294*(x) + ( (1981*(x))>>11 ) )
80 /* The reverse of the above, needed if we want to set our microsecond
81 * clock (via settimeofday) based on the incoming time in NTP format.
84 #define USEC(x) ( ( (x) >> 12 ) - 759 * ( ( ( (x) >> 10 ) + 32768 ) >> 16 ) )
86 /* Converts NTP delay and dispersion, apparently in seconds scaled
87 * by 65536, to microseconds. RFC1305 states this time is in seconds,
88 * doesn't mention the scaling.
89 * Should somehow be the same as 1000000 * x / 65536
91 #define sec2u(x) ( (x) * 15.2587890625 )
98 /* prototype for function defined in phaselock.c */
99 int contemplate_data(unsigned int absolute, double skew, double errorbar, int freq);
101 /* prototypes for some local routines */
102 void send_packet(int usd);
103 int rfc1305print(uint32_t *data, struct ntptime *arrival);
104 void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len);
106 /* variables with file scope
107 * (I know, bad form, but this is a short program) */
108 static uint32_t incoming_word[325];
109 #define incoming ((char *) incoming_word)
110 #define sizeof_incoming (sizeof(incoming_word)*sizeof(uint32_t))
111 static struct timeval time_of_send;
113 static int set_clock=0; /* non-zero presumably needs root privs */
115 /* when present, debug is a true global, shared with phaselock.c */
118 #define DEBUG_OPTION "d"
124 int get_current_freq(void)
126 /* OS dependent routine to get the current value of clock frequency.
131 if (__adjtimex(&txc) < 0) {
132 perror("adjtimex"); exit(1);
140 int set_freq(int new_freq)
142 /* OS dependent routine to set a new value of clock frequency.
146 txc.modes = ADJ_FREQUENCY;
148 if (__adjtimex(&txc) < 0) {
149 perror("adjtimex"); exit(1);
157 void send_packet(int usd)
168 if (debug) fprintf(stderr,"Sending ...\n");
169 if (sizeof(data) != 48) {
170 fprintf(stderr,"size error\n");
173 bzero((char *) data,sizeof(data));
175 ( LI << 30 ) | ( VN << 27 ) | ( MODE << 24 ) |
176 ( STRATUM << 16) | ( POLL << 8 ) | ( PREC & 0xff ) );
177 data[1] = htonl(1<<16); /* Root Delay (seconds) */
178 data[2] = htonl(1<<16); /* Root Dispersion (seconds) */
179 gettimeofday(&now,NULL);
180 data[10] = htonl(now.tv_sec + JAN_1970); /* Transmit Timestamp coarse */
181 data[11] = htonl(NTPFRAC(now.tv_usec)); /* Transmit Timestamp fine */
186 void get_packet_timestamp(int usd, struct ntptime *udp_arrival_ntp)
188 struct timeval udp_arrival;
189 #ifdef _PRECISION_SIOCGSTAMP
190 if ( ioctl(usd, SIOCGSTAMP, &udp_arrival) < 0 ) {
191 perror("ioctl-SIOCGSTAMP");
192 gettimeofday(&udp_arrival,NULL);
195 gettimeofday(&udp_arrival,NULL);
197 udp_arrival_ntp->coarse = udp_arrival.tv_sec + JAN_1970;
198 udp_arrival_ntp->fine = NTPFRAC(udp_arrival.tv_usec);
201 void check_source(int data_len, struct sockaddr *sa_source, int sa_len)
203 /* This is where one could check that the source is the server we expect */
205 struct sockaddr_in *sa_in=(struct sockaddr_in *)sa_source;
206 printf("packet of length %d received\n",data_len);
207 if (sa_source->sa_family==AF_INET) {
208 printf("Source: INET Port %d host %s\n",
209 ntohs(sa_in->sin_port),inet_ntoa(sa_in->sin_addr));
211 printf("Source: Address family %d\n",sa_source->sa_family);
216 double ntpdiff( struct ntptime *start, struct ntptime *stop)
220 a = stop->coarse - start->coarse;
221 if (stop->fine >= start->fine) {
222 b = stop->fine - start->fine;
224 b = start->fine - stop->fine;
229 return a*1.e6 + b * (1.e6/4294967296.0);
232 /* Does more than print, so this name is bogus.
233 * It also makes time adjustments, both sudden (-s)
234 * and phase-locking (-l). */
235 /* return value is number of microseconds uncertainty in answer */
236 int rfc1305print(uint32_t *data, struct ntptime *arrival)
238 /* straight out of RFC-1305 Appendix A */
239 int li, vn, mode, stratum, poll, prec;
240 int delay, disp, refid;
241 struct ntptime reftime, orgtime, rectime, xmttime;
242 double el_time,st_time,skew1,skew2;
245 #define Data(i) ntohl(((uint32_t *)data)[i])
246 li = Data(0) >> 30 & 0x03;
247 vn = Data(0) >> 27 & 0x07;
248 mode = Data(0) >> 24 & 0x07;
249 stratum = Data(0) >> 16 & 0xff;
250 poll = Data(0) >> 8 & 0xff;
251 prec = Data(0) & 0xff;
252 if (prec & 0x80) prec|=0xffffff00;
256 reftime.coarse = Data(4);
257 reftime.fine = Data(5);
258 orgtime.coarse = Data(6);
259 orgtime.fine = Data(7);
260 rectime.coarse = Data(8);
261 rectime.fine = Data(9);
262 xmttime.coarse = Data(10);
263 xmttime.fine = Data(11);
266 if (set_clock) { /* you'd better be root, or ntpclient will crash! */
267 struct timeval tv_set;
268 /* it would be even better to subtract half the slop */
269 tv_set.tv_sec = xmttime.coarse - JAN_1970;
270 /* divide xmttime.fine by 4294.967296 */
271 tv_set.tv_usec = USEC(xmttime.fine);
272 if (settimeofday(&tv_set,NULL)<0) {
273 perror("settimeofday");
277 printf("set time to %lu.%.6lu\n", tv_set.tv_sec, tv_set.tv_usec);
282 printf("LI=%d VN=%d Mode=%d Stratum=%d Poll=%d Precision=%d\n",
283 li, vn, mode, stratum, poll, prec);
284 printf("Delay=%.1f Dispersion=%.1f Refid=%u.%u.%u.%u\n",
285 sec2u(delay),sec2u(disp),
286 refid>>24&0xff, refid>>16&0xff, refid>>8&0xff, refid&0xff);
287 printf("Reference %u.%.10u\n", reftime.coarse, reftime.fine);
288 printf("Originate %u.%.10u\n", orgtime.coarse, orgtime.fine);
289 printf("Receive %u.%.10u\n", rectime.coarse, rectime.fine);
290 printf("Transmit %u.%.10u\n", xmttime.coarse, xmttime.fine);
291 printf("Our recv %u.%.10u\n", arrival->coarse, arrival->fine);
293 el_time=ntpdiff(&orgtime,arrival); /* elapsed */
294 st_time=ntpdiff(&rectime,&xmttime); /* stall */
295 skew1=ntpdiff(&orgtime,&rectime);
296 skew2=ntpdiff(&xmttime,arrival);
297 freq=get_current_freq();
299 printf("Total elapsed: %9.2f\n"
300 "Server stall: %9.2f\n"
302 el_time, st_time, el_time-st_time);
303 printf("Skew: %9.2f\n"
305 " day second elapsed stall skew dispersion freq\n",
306 (skew1-skew2)/2, freq);
308 /* Not the ideal order for printing, but we want to be sure
309 * to do all the time-sensitive thinking (and time setting)
310 * before we start the output, especially fflush() (which
311 * could be slow). Of course, if debug is turned on, speed
312 * has gone down the drain anyway. */
315 new_freq = contemplate_data(arrival->coarse, (skew1-skew2)/2,
316 el_time+sec2u(disp), freq);
317 if (!debug && new_freq != freq) set_freq(new_freq);
319 printf("%d %.5d.%.3d %8.1f %8.1f %8.1f %8.1f %9d\n",
320 arrival->coarse/86400, arrival->coarse%86400,
321 arrival->fine/4294967, el_time, st_time,
322 (skew1-skew2)/2, sec2u(disp), freq);
324 return(el_time-st_time);
327 void stuff_net_addr(struct in_addr *p, char *hostname)
329 struct hostent *ntpserver;
330 ntpserver=gethostbyname(hostname);
331 if (ntpserver == NULL) {
335 if (ntpserver->h_length != 4) {
336 fprintf(stderr,"oops %d\n",ntpserver->h_length);
339 memcpy(&(p->s_addr),ntpserver->h_addr_list[0],4);
342 void setup_receive(int usd, unsigned int interface, short port)
344 struct sockaddr_in sa_rcvr;
345 bzero((char *) &sa_rcvr, sizeof(sa_rcvr));
346 sa_rcvr.sin_family=AF_INET;
347 sa_rcvr.sin_addr.s_addr=htonl(interface);
348 sa_rcvr.sin_port=htons(port);
349 if(bind(usd,(struct sockaddr *) &sa_rcvr,sizeof(sa_rcvr)) == -1) {
350 fprintf(stderr,"could not bind to udp port %d\n",port);
357 void setup_transmit(int usd, char *host, short port)
359 struct sockaddr_in sa_dest;
360 bzero((char *) &sa_dest, sizeof(sa_dest));
361 sa_dest.sin_family=AF_INET;
362 stuff_net_addr(&(sa_dest.sin_addr),host);
363 sa_dest.sin_port=htons(port);
364 if (connect(usd,(struct sockaddr *)&sa_dest,sizeof(sa_dest))==-1)
365 {perror("connect");exit(1);}
368 int primary_loop(int usd, int num_probes, int interval, int goodness)
371 struct sockaddr sa_xmit;
372 int i, pack_len, sa_xmit_len, probes_sent, error;
374 struct ntptime udp_arrival_ntp;
376 if (debug) printf("Listening...\n");
379 sa_xmit_len=sizeof(sa_xmit);
385 i=select(usd+1,&fds,NULL,NULL,&to); /* Wait on read or error */
386 if ((i!=1)||(!FD_ISSET(usd,&fds))) {
387 if (i==EINTR) continue;
388 if (i<0) perror("select");
389 if (to.tv_sec == 0) {
390 if (probes_sent >= num_probes &&
391 num_probes != 0) break;
399 pack_len=recvfrom(usd,incoming,sizeof_incoming,0,
400 &sa_xmit,&sa_xmit_len);
404 } else if (pack_len>0 && (unsigned)pack_len<sizeof_incoming){
405 get_packet_timestamp(usd, &udp_arrival_ntp);
406 check_source(pack_len, &sa_xmit, sa_xmit_len);
407 error = rfc1305print(incoming_word, &udp_arrival_ntp);
408 /* udp_handle(usd,incoming,pack_len,&sa_xmit,sa_xmit_len); */
410 printf("Ooops. pack_len=%d\n",pack_len);
413 if ( error < goodness && goodness != 0) return 0;
414 if (probes_sent >= num_probes && num_probes != 0) break;
422 int n, day, freq, absolute;
423 float sec, el_time, st_time, disp;
424 double skew, errorbar;
425 int simulated_freq = 0;
426 unsigned int last_fake_time = 0;
427 double fake_delta_time = 0.0;
429 while (fgets(line,sizeof(line),stdin)) {
430 n=sscanf(line,"%d %f %f %f %lf %f %d",
431 &day, &sec, &el_time, &st_time, &skew, &disp, &freq);
434 absolute=day*86400+(int)sec;
435 errorbar=el_time+disp;
436 if (debug) printf("contemplate %u %.1f %.1f %d\n",
437 absolute,skew,errorbar,freq);
438 if (last_fake_time==0) simulated_freq=freq;
439 fake_delta_time += (absolute-last_fake_time)*((double)(freq-simulated_freq))/65536;
440 if (debug) printf("fake %f %d \n", fake_delta_time, simulated_freq);
441 skew += fake_delta_time;
442 freq = simulated_freq;
443 last_fake_time=absolute;
444 simulated_freq = contemplate_data(absolute, skew, errorbar, freq);
446 fprintf(stderr,"Replay input error\n");
452 void usage(char *argv0)
455 "Usage: %s [-c count] [-d] [-g goodness] -h hostname [-i interval]\n"
456 "\t[-l] [-p port] [-r] [-s] \n",
460 /* Copy each token in wordlist delimited by space into word */
461 #define foreach(word, wordlist, next) \
462 for (next = &wordlist[strspn(wordlist, ",")], \
463 strncpy(word, next, sizeof(word)), \
464 word[strcspn(word, ",")] = '\0', \
465 word[sizeof(word) - 1] = '\0', \
466 next = strchr(next, ','); \
468 next = next ? &next[strspn(next, ",")] : "", \
469 strncpy(word, next, sizeof(word)), \
470 word[strcspn(word, ",")] = '\0', \
471 word[sizeof(word) - 1] = '\0', \
472 next = strchr(next, ','))
474 int main(int argc, char *argv[]) {
475 int usd; /* socket */
477 /* These parameters are settable from the command line
478 the initializations here provide default behavior */
479 short int udp_local_port=0; /* default of 0 means kernel chooses */
480 int cycle_time=600; /* seconds */
481 int probe_count=0; /* default of 0 means loop forever */
482 /* int debug=0; is a global above */
484 char *hostname=NULL; /* must be set */
485 int replay=0; /* replay mode overrides everything */
486 char ntps[32], *next;
490 c = getopt( argc, argv, "c:" DEBUG_OPTION "g:h:i:lp:rs");
494 probe_count = atoi(optarg);
502 goodness = atoi(optarg);
508 cycle_time = atoi(optarg);
514 udp_local_port = atoi(optarg);
532 if (hostname == NULL) {
537 printf("Configuration:\n"
538 " -c probe_count %d\n"
544 " -p local_port %d\n"
545 " -s set_clock %d\n",
546 probe_count, debug, goodness, hostname, cycle_time,
547 live, udp_local_port, set_clock );
550 foreach(ntps, hostname, next) {
552 /* Startup sequence */
553 if ((usd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1)
554 {perror ("socket");exit(1);}
556 setup_receive(usd, INADDR_ANY, udp_local_port);
558 setup_transmit(usd, ntps, NTP_PORT);
560 if (!primary_loop(usd, probe_count, cycle_time, goodness)) {