1 2 3#include <stdio.h> 4#include <stdlib.h> 5#include <string.h> 6#include <sys/types.h> 7#include <sys/socket.h> 8#include <netinet/in.h> 9#include <netdb.h> 10#include <arpa/inet.h> 11#include <time.h> 12#include <unistd.h> 13#include <errno.h> 14#ifdef _PRECISION_SIOCGSTAMP 15#include <sys/ioctl.h> 16#endif 17 18#define ENABLE_DEBUG 19 20extern char *optarg; 21 22#ifdef linux 23#include <sys/utsname.h> 24#include <sys/time.h> 25typedef u_int32_t __u32; 26#include <sys/timex.h> 27#else 28#define main ntpclient 29extern struct hostent *gethostbyname(const char *name); 30extern int h_errno; 31#define herror(hostname) \ 32 fprintf(stderr,"Error %d looking up hostname %s\n", h_errno,hostname) 33typedef uint32_t __u32; 34#endif 35 36#define JAN_1970 0x83aa7e80 /* 2208988800 1970 - 1900 in seconds */ 37#define NTP_PORT (123) 38 39/* How to multiply by 4294.967296 quickly (and not quite exactly) 40 * without using floating point or greater than 32-bit integers. 41 * If you want to fix the last 12 microseconds of error, add in 42 * (2911*(x))>>28) 43 */ 44#define NTPFRAC(x) ( 4294*(x) + ( (1981*(x))>>11 ) ) 45 46/* The reverse of the above, needed if we want to set our microsecond 47 * clock (via settimeofday) based on the incoming time in NTP format. 48 * Basically exact. 49 */ 50#define USEC(x) ( ( (x) >> 12 ) - 759 * ( ( ( (x) >> 10 ) + 32768 ) >> 16 ) ) 51 52/* Converts NTP delay and dispersion, apparently in seconds scaled 53 * by 65536, to microseconds. RFC1305 states this time is in seconds, 54 * doesn't mention the scaling. 55 * Should somehow be the same as 1000000 * x / 65536 56 */ 57#define sec2u(x) ( (x) * 15.2587890625 ) 58 59struct ntptime { 60 unsigned int coarse; 61 unsigned int fine; 62}; 63 64void send_packet(int usd); 65void rfc1305print(char *data, struct ntptime *arrival); 66void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len); 67 68/* global variables (I know, bad form, but this is a short program) */ 69char incoming[1500]; 70struct timeval time_of_send; 71int live=0; 72int set_clock=0; /* non-zero presumably needs root privs */ 73 74static __u32 transmit_timestamp[2]; /* Foxconn added pling 10/31/2006 */ 75 76#ifdef ENABLE_DEBUG 77int debug=0; 78#define DEBUG_OPTION "d" 79#else 80#define debug 0 81#define DEBUG_OPTION 82#endif 83 84#ifdef NOT_REMOVED 85int contemplate_data(unsigned int absolute, double skew, double errorbar, int freq); 86 87int get_current_freq() 88{ 89 /* OS dependent routine to get the current value of clock frequency. 90 */ 91#ifdef linux 92 struct timex txc; 93 txc.modes=0; 94 if (__adjtimex(&txc) < 0) { 95 perror("adjtimex"); exit(1); 96 } 97 return txc.freq; 98#else 99 return 0; 100#endif 101} 102 103int set_freq(int new_freq) 104{ 105 /* OS dependent routine to set a new value of clock frequency. 106 */ 107#ifdef linux 108 struct timex txc; 109 txc.modes = ADJ_FREQUENCY; 110 txc.freq = new_freq; 111 if (__adjtimex(&txc) < 0) { 112 perror("adjtimex"); exit(1); 113 } 114 return txc.freq; 115#else 116 return 0; 117#endif 118} 119#endif /* NOT_REMOVED */ 120 121void send_packet(int usd) 122{ 123 __u32 data[12]; 124 struct timeval now; 125#define LI 0 126#define VN 3 127#define MODE 3 128#define STRATUM 0 129#define POLL 4 130#define PREC -6 131 132 if (debug) fprintf(stderr,"Sending ...\n"); 133 if (sizeof(data) != 48) { 134 fprintf(stderr,"size error\n"); 135 return; 136 } 137 bzero((char*)data,sizeof(data)); 138 data[0] = htonl ( 139 ( LI << 30 ) | ( VN << 27 ) | ( MODE << 24 ) | 140 ( STRATUM << 16) | ( POLL << 8 ) | ( PREC & 0xff ) ); 141 data[1] = htonl(1<<16); /* Root Delay (seconds) */ 142 data[2] = htonl(1<<16); /* Root Dispersion (seconds) */ 143 gettimeofday(&now,NULL); 144 data[10] = htonl(now.tv_sec + JAN_1970); /* Transmit Timestamp coarse */ 145 data[11] = htonl(NTPFRAC(now.tv_usec)); /* Transmit Timestamp fine */ 146 147 /* Foxconn added start pling 10/31/2006 */ 148 /* Save the transmit timestamp */ 149 transmit_timestamp[0] = ntohl(data[10]); 150 transmit_timestamp[1] = ntohl(data[11]); 151 /* Foxconn added end pling 10/31/2006 */ 152 153 send(usd,data,48,0); 154 time_of_send=now; 155} 156 157 158void udp_handle(int usd, char *data, int data_len, struct sockaddr *sa_source, int sa_len) 159{ 160 struct timeval udp_arrival; 161 struct ntptime udp_arrival_ntp; 162 163#ifdef _PRECISION_SIOCGSTAMP 164 if ( ioctl(usd, SIOCGSTAMP, &udp_arrival) < 0 ) { 165 perror("ioctl-SIOCGSTAMP"); 166 gettimeofday(&udp_arrival,NULL); 167 } 168#else 169 gettimeofday(&udp_arrival,NULL); 170#endif 171 udp_arrival_ntp.coarse = udp_arrival.tv_sec + JAN_1970; 172 udp_arrival_ntp.fine = NTPFRAC(udp_arrival.tv_usec); 173 174 if (debug) { 175 struct sockaddr_in *sa_in=(struct sockaddr_in *)sa_source; 176 printf("packet of length %d received\n",data_len); 177 if (sa_source->sa_family==AF_INET) { 178 printf("Source: INET Port %d host %s\n", 179 ntohs(sa_in->sin_port),inet_ntoa(sa_in->sin_addr)); 180 } else { 181 printf("Source: Address family %d\n",sa_source->sa_family); 182 } 183 } 184 rfc1305print(data,&udp_arrival_ntp); 185} 186 187double ntpdiff( struct ntptime *start, struct ntptime *stop) 188{ 189 int a; 190 unsigned int b; 191 a = stop->coarse - start->coarse; 192 if (stop->fine >= start->fine) { 193 b = stop->fine - start->fine; 194 } else { 195 b = start->fine - stop->fine; 196 b = ~b; 197 a -= 1; 198 } 199 200 return a*1.e6 + b * (1.e6/4294967296.0); 201} 202 203void rfc1305print(char *data, struct ntptime *arrival) 204{ 205/* straight out of RFC-1305 Appendix A */ 206 int li, vn, mode, stratum, poll, prec; 207 int delay, disp, refid; 208 struct ntptime reftime, orgtime, rectime, xmttime; 209#ifdef NOT_REMOVED 210 double etime,stime,skew1,skew2; 211 int freq; 212#endif /* NOT_REMOVED */ 213 214#define Data(i) ntohl(((unsigned int *)data)[i]) 215 li = Data(0) >> 30 & 0x03; 216 vn = Data(0) >> 27 & 0x07; 217 mode = Data(0) >> 24 & 0x07; 218 stratum = Data(0) >> 16 & 0xff; 219 poll = Data(0) >> 8 & 0xff; 220 prec = Data(0) & 0xff; 221 if (prec & 0x80) prec|=0xffffff00; 222 delay = Data(1); 223 disp = Data(2); 224 refid = Data(3); 225 reftime.coarse = Data(4); 226 reftime.fine = Data(5); 227 orgtime.coarse = Data(6); 228 orgtime.fine = Data(7); 229 rectime.coarse = Data(8); 230 rectime.fine = Data(9); 231 xmttime.coarse = Data(10); 232 xmttime.fine = Data(11); 233#undef Data 234 235 /* Foxconn added start pling 10/31/2006 */ 236 /* Add validity checks for reply packet */ 237 if (stratum == 0) { 238 if (debug) 239 printf("Got Kiss of death packet from NTP server.\n"); 240 exit(2); 241 } 242 243 if (orgtime.coarse != transmit_timestamp[0] || 244 orgtime.fine != transmit_timestamp[1]) { 245 if (debug) 246 printf("Incorrect original timestamp. Drop NTP reply.\n"); 247 exit(1); 248 } 249 250 if (xmttime.coarse == 0 && xmttime.fine == 0) { 251 if (debug) 252 printf("Transmit timestamp is 0. Drop NTP reply.\n"); 253 exit(1); 254 } 255 256 if (mode != 4) { 257 if (debug) 258 printf("Incorrect mode (%d). Drop NTP reply.\n", mode); 259 exit(1); 260 } 261 /* Foxconn added end pling 10/31/2006 */ 262 263 if (set_clock) { /* you'd better be root, or ntpclient will crash! */ 264 struct timeval tv_set; 265 /* it would be even better to subtract half the slop */ 266 tv_set.tv_sec = xmttime.coarse - JAN_1970; 267 /* divide xmttime.fine by 4294.967296 */ 268 tv_set.tv_usec = USEC(xmttime.fine); 269 if (settimeofday(&tv_set,NULL)<0) { 270 perror("settimeofday"); 271 exit(1); 272 } 273 if (debug) { 274 printf("set time to %lu.%.6lu\n", tv_set.tv_sec, tv_set.tv_usec); 275 } 276 } 277 278#ifdef NOT_REMOVED 279 if (debug) { 280 printf("LI=%d VN=%d Mode=%d Stratum=%d Poll=%d Precision=%d\n", 281 li, vn, mode, stratum, poll, prec); 282 printf("Delay=%.1f Dispersion=%.1f Refid=%u.%u.%u.%u\n", 283 sec2u(delay),sec2u(disp), 284 refid>>24&0xff, refid>>16&0xff, refid>>8&0xff, refid&0xff); 285 printf("Reference %u.%.10u\n", reftime.coarse, reftime.fine); 286 printf("Originate %u.%.10u\n", orgtime.coarse, orgtime.fine); 287 printf("Receive %u.%.10u\n", rectime.coarse, rectime.fine); 288 printf("Transmit %u.%.10u\n", xmttime.coarse, xmttime.fine); 289 printf("Our recv %u.%.10u\n", arrival->coarse, arrival->fine); 290 } 291 etime=ntpdiff(&orgtime,arrival); 292 stime=ntpdiff(&rectime,&xmttime); 293 skew1=ntpdiff(&orgtime,&rectime); 294 skew2=ntpdiff(&xmttime,arrival); 295 freq=get_current_freq(); 296 if (debug) { 297 printf("Total elapsed: %9.2f\n" 298 "Server stall: %9.2f\n" 299 "Slop: %9.2f\n", 300 etime, stime, etime-stime); 301 printf("Skew: %9.2f\n" 302 "Frequency: %9d\n" 303 " day second elapsed stall skew dispersion freq\n", 304 (skew1-skew2)/2, freq); 305 } 306 if (debug) { 307 printf("%d %5d.%.3d %8.1f %8.1f %8.1f %8.1f %9d\n", 308 arrival->coarse/86400+15020, arrival->coarse%86400, 309 arrival->fine/4294967, etime, stime, 310 (skew1-skew2)/2, sec2u(disp), freq); 311 fflush(stdout); 312 } 313 if (live) { 314 int new_freq; 315 new_freq = contemplate_data(arrival->coarse, (skew1-skew2)/2, 316 etime+sec2u(disp), freq); 317 if (!debug && new_freq != freq) set_freq(new_freq); 318 } 319#endif /* NOT_REMOVED */ 320} 321 322void stuff_net_addr(struct in_addr *p, char *hostname) 323{ 324 struct hostent *ntpserver; 325 ntpserver=gethostbyname(hostname); 326 if (ntpserver == NULL) { 327 herror(hostname); 328 exit(1); 329 } 330 if (ntpserver->h_length != 4) { 331 fprintf(stderr,"oops %d\n",ntpserver->h_length); 332 exit(1); 333 } 334 memcpy(&(p->s_addr),ntpserver->h_addr_list[0],4); 335} 336 337void setup_receive(int usd, unsigned int interface, short port) 338{ 339 struct sockaddr_in sa_rcvr; 340 bzero((char *) &sa_rcvr, sizeof(sa_rcvr)); 341 sa_rcvr.sin_family=AF_INET; 342 sa_rcvr.sin_addr.s_addr=htonl(interface); 343 sa_rcvr.sin_port=htons(port); 344 if(bind(usd,(struct sockaddr *) &sa_rcvr,sizeof(sa_rcvr)) == -1) { 345 fprintf(stderr,"could not bind to udp port %d\n",port); 346 perror("bind"); 347 exit(1); 348 } 349 listen(usd,3); 350} 351 352void setup_transmit(int usd, char *host, short port) 353{ 354 struct sockaddr_in sa_dest; 355 bzero((char *) &sa_dest, sizeof(sa_dest)); 356 sa_dest.sin_family=AF_INET; 357 stuff_net_addr(&(sa_dest.sin_addr),host); 358 sa_dest.sin_port=htons(port); 359 if (connect(usd,(struct sockaddr *)&sa_dest,sizeof(sa_dest))==-1) 360 {perror("connect");exit(1);} 361} 362 363int primary_loop(int usd, int num_probes, int cycle_time) 364{ 365 fd_set fds; 366 struct sockaddr sa_xmit; 367 int i, pack_len, sa_xmit_len, probes_sent; 368 struct timeval to; 369 370 if (debug) printf("Listening...\n"); 371 372 probes_sent=0; 373 sa_xmit_len=sizeof(sa_xmit); 374 to.tv_sec=0; 375 to.tv_usec=0; 376 for (;;) { 377 FD_ZERO(&fds); 378 FD_SET(usd,&fds); 379 i=select(usd+1,&fds,NULL,NULL,&to); /* Wait on read or error */ 380 if ((i!=1)||(!FD_ISSET(usd,&fds))) { 381 if (i==EINTR) continue; 382 if (i<0) perror("select"); 383 if ((to.tv_sec == 0) || (to.tv_sec == cycle_time)) { 384 if (probes_sent >= num_probes && 385 num_probes != 0) break; 386 send_packet(usd); 387 ++probes_sent; 388 to.tv_sec=cycle_time; 389 to.tv_usec=0; 390 } 391 continue; 392 } 393 pack_len=recvfrom(usd,incoming,sizeof(incoming),0, 394 &sa_xmit,&sa_xmit_len); 395 if (pack_len<0) { 396 perror("recvfrom"); 397 } else if (pack_len>0 && pack_len<sizeof(incoming)){ 398 udp_handle(usd,incoming,pack_len,&sa_xmit,sa_xmit_len); 399 return 0; 400 } else { 401 printf("Ooops. pack_len=%d\n",pack_len); 402 fflush(stdout); 403 } 404 if (probes_sent >= num_probes && num_probes != 0) break; 405 } 406 return -1; 407} 408 409#ifdef NOT_REMOVED 410void do_replay(void) 411{ 412 char line[100]; 413 int n, day, freq, absolute; 414 float sec, etime, stime, disp; 415 double skew, errorbar; 416 int simulated_freq = 0; 417 unsigned int last_fake_time = 0; 418 double fake_delta_time = 0.0; 419 420 while (fgets(line,sizeof(line),stdin)) { 421 n=sscanf(line,"%d %f %f %f %lf %f %d", 422 &day, &sec, &etime, &stime, &skew, &disp, &freq); 423 if (n==7) { 424 fputs(line,stdout); 425 absolute=(day-15020)*86400+(int)sec; 426 errorbar=etime+disp; 427 if (debug) printf("contemplate %u %.1f %.1f %d\n", 428 absolute,skew,errorbar,freq); 429 if (last_fake_time==0) simulated_freq=freq; 430 fake_delta_time += (absolute-last_fake_time)*((double)(freq-simulated_freq))/65536; 431 if (debug) printf("fake %f %d \n", fake_delta_time, simulated_freq); 432 skew += fake_delta_time; 433 freq = simulated_freq; 434 last_fake_time=absolute; 435 simulated_freq = contemplate_data(absolute, skew, errorbar, freq); 436 } else { 437 fprintf(stderr,"Replay input error\n"); 438 exit(2); 439 } 440 } 441} 442#endif /* NOT_REMOVED */ 443 444void usage(char *argv0) 445{ 446 fprintf(stderr, 447 "Usage: %s [-c count] [-d] -h hostname [-i interval] [-l]\n" 448 "\t[-p port] [-r] [-s] \n", 449 argv0); 450} 451 452/* Copy each token in wordlist delimited by space into word */ 453#define foreach(word, wordlist, next) \ 454 for (next = &wordlist[strspn(wordlist, " ")], \ 455 strncpy(word, next, sizeof(word)), \ 456 word[strcspn(word, " ")] = '\0', \ 457 word[sizeof(word) - 1] = '\0', \ 458 next = strchr(next, ' '); \ 459 strlen(word); \ 460 next = next ? &next[strspn(next, " ")] : "", \ 461 strncpy(word, next, sizeof(word)), \ 462 word[strcspn(word, " ")] = '\0', \ 463 word[sizeof(word) - 1] = '\0', \ 464 next = strchr(next, ' ')) 465 466int main(int argc, char *argv[]) { 467 int usd; /* socket */ 468 int c; 469 /* These parameters are settable from the command line 470 the initializations here provide default behavior */ 471 short int udp_local_port=0; /* default of 0 means kernel chooses */ 472 int cycle_time=3; /* request timeout in seconds */ 473 int probe_count=0; /* default of 0 means loop forever */ 474 /* int debug=0; is a global above */ 475 char *hostname=NULL; /* must be set */ 476 int replay=0; /* replay mode overrides everything */ 477 char ntps[32], *next; 478 479 for (;;) { 480 c = getopt( argc, argv, "c:" DEBUG_OPTION "h:i:p:lrs"); 481 if (c == EOF) break; 482 switch (c) { 483 case 'c': 484 probe_count = atoi(optarg); 485 break; 486#ifdef ENABLE_DEBUG 487 case 'd': 488 ++debug; 489 break; 490#endif 491 case 'h': 492 hostname = optarg; 493 break; 494 case 'i': 495 cycle_time = atoi(optarg); 496 break; 497 case 'l': 498 live++; 499 break; 500 case 'p': 501 udp_local_port = atoi(optarg); 502 break; 503 case 'r': 504 replay++; 505 break; 506 case 's': 507 set_clock = 1; 508 probe_count = 1; 509 break; 510 default: 511 usage(argv[0]); 512 exit(1); 513 } 514 } 515 516#ifdef NOT_REMOVED 517 if (replay) { 518 do_replay(); 519 exit(0); 520 } 521#endif /* NOT_REMOVED */ 522 523 if (hostname == NULL) { 524 usage(argv[0]); 525 exit(1); 526 } 527 if (debug) { 528 printf("Configuration:\n" 529 " -c probe_count %d\n" 530 " -d (debug) %d\n" 531 " -h hostname %s\n" 532 " -i interval %d\n" 533 " -l live %d\n" 534 " -p local_port %d\n" 535 " -s set_clock %d\n", 536 probe_count, debug, hostname, cycle_time, 537 live, udp_local_port, set_clock); 538 } 539 540 foreach(ntps, hostname, next) { 541 542 /* Startup sequence */ 543 if ((usd=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP))==-1) { 544 perror ("socket"); 545 exit(1); 546 } 547 548 setup_receive(usd, INADDR_ANY, udp_local_port); 549 550 setup_transmit(usd, ntps, NTP_PORT); 551 552 if (!primary_loop(usd, probe_count, cycle_time)) { 553 close(usd); 554 return 0; /* break; */ /* wklin modified */ 555 } 556 557 close(usd); 558 } 559 560 return 1; 561} 562