1 #include <u.h> 2 #include <libc.h> 3 #include <auth.h> 4 #include <ip.h> 5 #include <mp.h> 6 7 /* nanosecond times */ 8 #define SEC 1000000000LL 9 #define MIN (60LL*SEC) 10 #define HOUR (60LL*MIN) 11 #define DAY (24LL*HOUR) 12 13 enum { 14 Fs, 15 Rtc, 16 Ntp, 17 Utc, 18 Gps, 19 20 HZAvgSecs= 3*60, /* target averaging period for frequency in seconds */ 21 MinSampleSecs= 60, /* minimum sampling time in seconds */ 22 }; 23 24 25 char *dir = "/tmp"; /* directory sample files live in */ 26 char *logfile = "timesync"; 27 char *timeserver; 28 char *Rootid; 29 int utcfil; 30 int gpsfil; 31 int debug; 32 int impotent; 33 int logging; 34 int type; 35 int gmtdelta; /* rtc+gmtdelta = gmt */ 36 uvlong avgerr; 37 38 /* ntp server info */ 39 int stratum = 14; 40 vlong mydisp, rootdisp; 41 vlong mydelay, rootdelay; 42 vlong avgdelay; 43 vlong lastutc; 44 uchar rootid[4]; 45 char *sysid; 46 int myprec; 47 48 /* list of time samples */ 49 typedef struct Sample Sample; 50 struct Sample 51 { 52 Sample *next; 53 uvlong ticks; 54 vlong ltime; 55 vlong stime; 56 }; 57 58 /* ntp packet */ 59 typedef struct NTPpkt NTPpkt; 60 struct NTPpkt 61 { 62 uchar mode; 63 uchar stratum; 64 uchar poll; 65 uchar precision; 66 uchar rootdelay[4]; 67 uchar rootdisp[4]; 68 uchar rootid[4]; 69 uchar refts[8]; 70 uchar origts[8]; /* departed client */ 71 uchar recvts[8]; /* arrived at server */ 72 uchar xmitts[8]; /* departed server */ 73 uchar keyid[4]; 74 uchar digest[16]; 75 }; 76 77 /* ntp server */ 78 typedef struct NTPserver NTPserver; 79 struct NTPserver 80 { 81 NTPserver *next; 82 char *name; 83 uchar stratum; 84 uchar precision; 85 vlong rootdelay; 86 vlong rootdisp; 87 vlong rtt; 88 vlong dt; 89 }; 90 91 NTPserver *ntpservers; 92 93 enum 94 { 95 NTPSIZE= 48, /* basic ntp packet */ 96 NTPDIGESTSIZE= 20, /* key and digest */ 97 }; 98 99 /* error bound of last sample */ 100 ulong ε; 101 102 static void addntpserver(char *name); 103 static int adjustperiod(vlong diff, vlong accuracy, int secs); 104 static void background(void); 105 static int caperror(vlong dhz, int tsecs, vlong taccuracy); 106 static long fstime(void); 107 static int gettime(vlong *nsec, uvlong *ticks, uvlong *hz); /* returns time, ticks, hz */ 108 static int getclockprecision(vlong); 109 static vlong gpssample(void); 110 static void hnputts(void *p, vlong nsec); 111 static void hnputts(void *p, vlong nsec); 112 static void inittime(void); 113 static vlong nhgetts(void *p); 114 static vlong nhgetts(void *p); 115 static void ntpserver(char*); 116 static vlong ntpsample(void); 117 static int ntptimediff(NTPserver *ns); 118 static int openfreqfile(void); 119 static vlong readfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz); 120 static long rtctime(void); 121 static vlong sample(long (*get)(void)); 122 static void setpriority(void); 123 static void setrootid(char *d); 124 static void settime(vlong now, uvlong hz, vlong delta, int n); /* set time, hz, delta, period */ 125 static vlong utcsample(void); 126 static uvlong vabs(vlong); 127 static uvlong whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz, 128 vlong dt, vlong ticks, vlong period); 129 static void writefreqfile(int fd, vlong hz, int secs, vlong diff); 130 131 // ((1970-1900)*365 + 17 /*leap days*/)*24*60*60 132 #define EPOCHDIFF 2208988800UL 133 134 static void 135 usage(void) 136 { 137 fprint(2, "usage: %s [-a accuracy][-d dir][-I rootid][-s net]" 138 "[-S stratum][-DfGilLnrU] timesource ...\n", argv0); 139 exits("usage"); 140 } 141 142 void 143 main(int argc, char **argv) 144 { 145 int i, t, fd, nservenet; 146 int secs; /* sampling period */ 147 int tsecs; /* temporary sampling period */ 148 uvlong hz, minhz, maxhz, period, nhz; 149 vlong diff, accuracy, taccuracy; 150 char *servenet[4]; 151 Sample *s, *x, *first, **l; 152 Tm tl, tg; 153 154 type = Fs; /* by default, sync with the file system */ 155 debug = 0; 156 accuracy = 1000000LL; /* default accuracy is 1 millisecond */ 157 nservenet = 0; 158 tsecs = secs = MinSampleSecs; 159 timeserver = ""; 160 161 ARGBEGIN{ 162 case 'a': 163 accuracy = strtoll(EARGF(usage()), 0, 0); /* specified in ns */ 164 if(accuracy <= 1) 165 sysfatal("bad accuracy specified"); 166 break; 167 case 'd': 168 dir = EARGF(usage()); 169 break; 170 case 'D': 171 debug = 1; 172 break; 173 case 'f': 174 type = Fs; 175 stratum = 2; 176 break; 177 case 'G': 178 type = Gps; 179 stratum = 1; 180 break; 181 case 'i': 182 impotent = 1; 183 break; 184 case 'I': 185 Rootid = EARGF(usage()); 186 break; 187 case 'l': 188 logging = 1; 189 break; 190 case 'L': 191 /* 192 * Assume time source in local time rather than GMT. 193 * Calculate difference so that rtctime can return GMT. 194 * This is useful with the rtc on PC's that run Windows 195 * since Windows keeps the local time in the rtc. 196 */ 197 t = time(0); 198 tl = *localtime(t); 199 tg = *gmtime(t); 200 201 /* 202 * if the years are different, we're at most a day off, 203 * so just rewrite 204 */ 205 if(tl.year < tg.year){ 206 tg.year--; 207 tg.yday = tl.yday + 1; 208 }else if(tl.year > tg.year){ 209 tl.year--; 210 tl.yday = tg.yday+1; 211 } 212 assert(tl.year == tg.year); 213 214 tg.sec -= tl.sec; 215 tg.min -= tl.min; 216 tg.hour -= tl.hour; 217 tg.yday -= tl.yday; 218 gmtdelta = tg.sec+60*(tg.min+60*(tg.hour+tg.yday*24)); 219 220 assert(abs(gmtdelta) <= 24*60*60); 221 break; 222 case 'n': 223 type = Ntp; 224 break; 225 case 'r': 226 type = Rtc; 227 stratum = 0; 228 break; 229 case 'U': 230 type = Utc; 231 stratum = 1; 232 break; 233 case 's': 234 if(nservenet >= nelem(servenet)) 235 sysfatal("too many networks to serve on"); 236 servenet[nservenet++] = EARGF(usage()); 237 break; 238 case 'S': 239 stratum = strtoll(EARGF(usage()), 0, 0); 240 break; 241 default: 242 usage(); 243 }ARGEND; 244 245 fmtinstall('E', eipfmt); 246 fmtinstall('I', eipfmt); 247 fmtinstall('V', eipfmt); 248 sysid = getenv("sysname"); 249 250 /* detach from the current namespace */ 251 if(debug) 252 rfork(RFNAMEG); 253 254 switch(type){ 255 case Utc: 256 if(argc > 0) 257 timeserver = argv[0]; 258 else 259 sysfatal("bad time source"); 260 break; 261 case Gps: 262 if(argc > 0) 263 timeserver = argv[0]; 264 else 265 timeserver = "/mnt/gps/time"; 266 break; 267 case Fs: 268 if(argc > 0) 269 timeserver = argv[0]; 270 else 271 timeserver = "/srv/boot"; 272 break; 273 case Ntp: 274 if(argc > 0) 275 for(i = 0; i < argc; i++) 276 addntpserver(argv[i]); 277 else 278 addntpserver("$ntp"); 279 break; 280 } 281 282 setpriority(); 283 284 /* figure out our time interface and initial frequency */ 285 inittime(); 286 gettime(0, 0, &hz); 287 minhz = hz/10; 288 maxhz = hz*10; 289 myprec = getclockprecision(hz); 290 291 /* convert the accuracy from nanoseconds to ticks */ 292 taccuracy = hz*accuracy/SEC; 293 294 /* 295 * bind in clocks 296 */ 297 switch(type){ 298 case Fs: 299 fd = open(timeserver, ORDWR); 300 if(fd < 0) 301 sysfatal("opening %s: %r", timeserver); 302 if(amount(fd, "/n/boot", MREPL, "") < 0) 303 sysfatal("mounting %s: %r", timeserver); 304 close(fd); 305 break; 306 case Rtc: 307 bind("#r", "/dev", MAFTER); 308 if(access("/dev/rtc", AREAD) < 0) 309 sysfatal("accessing /dev/rtc: %r"); 310 break; 311 case Utc: 312 fd = open(timeserver, OREAD); 313 if(fd < 0) 314 sysfatal("opening %s: %r", timeserver); 315 utcfil = fd; 316 break; 317 case Gps: 318 fd = open(timeserver, OREAD); 319 if(fd < 0) 320 sysfatal("opening %s: %r", timeserver); 321 gpsfil = fd; 322 break; 323 } 324 325 /* 326 * start a local ntp server(s) 327 */ 328 for(i = 0; i < nservenet; i++) 329 switch(rfork(RFPROC|RFFDG|RFMEM|RFNOWAIT)){ 330 case -1: 331 sysfatal("forking: %r"); 332 case 0: 333 ntpserver(servenet[i]); 334 _exits(0); 335 } 336 337 /* get the last known frequency from the file */ 338 fd = openfreqfile(); 339 hz = readfreqfile(fd, hz, minhz, maxhz); 340 341 /* 342 * this is the main loop. it gets a sample, adjusts the 343 * clock and computes a sleep period until the next loop. 344 * we balance frequency drift against the length of the 345 * period to avoid blowing the accuracy limit. 346 */ 347 first = nil; 348 l = &first; 349 avgerr = accuracy >> 1; 350 for(;; background(), sleep(tsecs*1000)){ 351 s = mallocz(sizeof *s, 1); 352 diff = 0; 353 354 /* get times for this sample */ 355 ε = ~0; 356 switch(type){ 357 case Fs: 358 s->stime = sample(fstime); 359 break; 360 case Rtc: 361 s->stime = sample(rtctime); 362 break; 363 case Utc: 364 s->stime = utcsample(); 365 if(s->stime == 0LL){ 366 if(logging) 367 syslog(0, logfile, "no sample"); 368 free(s); 369 if (secs > 60 * 15) 370 tsecs = 60*15; 371 continue; 372 } 373 break; 374 case Ntp: 375 diff = ntpsample(); 376 if(diff == 0LL){ 377 if(logging) 378 syslog(0, logfile, "no sample"); 379 free(s); 380 if(secs > 60*15) 381 tsecs = 60*15; 382 continue; 383 } 384 break; 385 case Gps: 386 diff = gpssample(); 387 if(diff == 0LL){ 388 if(logging) 389 syslog(0, logfile, "no sample"); 390 free(s); 391 if(secs > 60*15) 392 tsecs = 60*15; 393 continue; 394 } 395 } 396 397 /* use fastest method to read local clock and ticks */ 398 gettime(&s->ltime, &s->ticks, 0); 399 if(type == Ntp || type == Gps) 400 s->stime = s->ltime + diff; 401 402 /* if the sample was bad, ignore it */ 403 if(s->stime < 0){ 404 free(s); 405 continue; 406 } 407 408 /* reset local time */ 409 diff = s->stime - s->ltime; 410 if(diff > 10*SEC || diff < -10*SEC){ 411 /* we're way off, just set the time */ 412 secs = MinSampleSecs; 413 settime(s->stime, 0, 0, 0); 414 } else { 415 /* keep a running average of the error. */ 416 avgerr = (avgerr>>1) + (vabs(diff)>>1); 417 418 /* 419 * the time to next sample depends on how good or 420 * bad we're doing. 421 */ 422 tsecs = secs = adjustperiod(diff, accuracy, secs); 423 424 /* 425 * work off the fixed difference. This is done 426 * by adding a ramp to the clock. Each 100th of a 427 * second (or so) the kernel will add diff/(4*secs*100) 428 * to the clock. we only do 1/4 of the difference per 429 * period to dampen any measurement noise. 430 * 431 * any difference greater than ε we work off during the 432 * sampling period. 433 */ 434 if(abs(diff) > ε) 435 if(diff > 0) 436 settime(-1, 0, diff-((3*ε)/4), secs); 437 else 438 settime(-1, 0, diff+((3*ε)/4), secs); 439 else 440 settime(-1, 0, diff, 4*secs); 441 442 } 443 if(debug) 444 fprint(2, "δ %lld avgδ %lld f %lld\n", diff, avgerr, hz); 445 446 /* dump old samples (keep at least one) */ 447 while(first != nil){ 448 if(first->next == nil) 449 break; 450 if(s->stime - first->next->stime < DAY) 451 break; 452 x = first; 453 first = first->next; 454 free(x); 455 } 456 457 /* 458 * The sampling error is limited by the total error. If 459 * we make sure the sampling period is at least 16 million 460 * times the average error, we should calculate a frequency 461 * with on average a 1e-7 error. 462 * 463 * So that big hz changes don't blow our accuracy requirement, 464 * we shorten the period to make sure that δhz*secs will be 465 * greater than the accuracy limit. 466 */ 467 period = avgerr << 24; 468 for(x = first; x != nil; x = x->next) 469 if(s->stime - x->stime < period || 470 x->next == nil || s->stime - x->next->stime < period) 471 break; 472 if(x != nil){ 473 nhz = whatisthefrequencykenneth( 474 hz, minhz, maxhz, 475 s->stime - x->stime, 476 s->ticks - x->ticks, 477 period); 478 tsecs = caperror(vabs(nhz-hz), tsecs, taccuracy); 479 hz = nhz; 480 writefreqfile(fd, hz, (s->stime - x->stime)/SEC, diff); 481 } 482 483 /* add current sample to list. */ 484 *l = s; 485 l = &s->next; 486 487 if(logging) 488 syslog(0, logfile, "δ %lld avgδ %lld hz %lld", 489 diff, avgerr, hz); 490 } 491 } 492 493 /* 494 * adjust the sampling period with some histeresis 495 */ 496 static int 497 adjustperiod(vlong diff, vlong accuracy, int secs) 498 { 499 uvlong absdiff; 500 501 absdiff = vabs(diff); 502 503 if(absdiff < (accuracy>>1)) 504 secs += 60; 505 else if(absdiff > accuracy) 506 secs >>= 1; 507 else 508 secs -= 60; 509 if(secs < MinSampleSecs) 510 secs = MinSampleSecs; 511 return secs; 512 } 513 514 /* 515 * adjust the frequency 516 */ 517 static uvlong 518 whatisthefrequencykenneth(uvlong hz, uvlong minhz, uvlong maxhz, vlong dt, 519 vlong ticks, vlong period) 520 { 521 uvlong ohz = hz; 522 static mpint *mpdt, *mpticks, *mphz, *mpbillion; 523 524 /* sanity check */ 525 if(dt <= 0 || ticks <= 0) 526 return hz; 527 528 if(mphz == nil){ 529 mphz = mpnew(0); 530 mpbillion = uvtomp(SEC, nil); 531 } 532 533 /* hz = (ticks*SEC)/dt */ 534 mpdt = vtomp(dt, mpdt); 535 mpticks = vtomp(ticks, mpticks); 536 mpmul(mpticks, mpbillion, mpticks); 537 mpdiv(mpticks, mpdt, mphz, nil); 538 hz = mptoui(mphz); 539 540 /* sanity */ 541 if(hz < minhz || hz > maxhz) 542 return ohz; 543 544 /* damp the change if we're shorter than the target period */ 545 if(period > dt) 546 hz = (12ULL*ohz + 4ULL*hz)/16ULL; 547 548 settime(-1, hz, 0, 0); 549 return hz; 550 } 551 552 /* 553 * We may be changing the frequency to match a bad measurement 554 * or to match a condition no longer in effect. To make sure 555 * that this doesn't blow our error budget over the next measurement 556 * period, shorten the period to make sure that δhz*secs will be 557 * less than the accuracy limit. Here taccuracy is accuracy converted 558 * from nanoseconds to ticks. 559 */ 560 static int 561 caperror(vlong dhz, int tsecs, vlong taccuracy) 562 { 563 if(dhz*tsecs <= taccuracy) 564 return tsecs; 565 566 if(debug) 567 fprint(2, "δhz %lld tsecs %d tacc %lld\n", dhz, tsecs, taccuracy); 568 569 tsecs = taccuracy/dhz; 570 if(tsecs < MinSampleSecs) 571 tsecs = MinSampleSecs; 572 return tsecs; 573 } 574 575 /* 576 * kernel interface 577 */ 578 enum 579 { 580 Ibintime, 581 Insec, 582 Itiming, 583 }; 584 int ifc; 585 int bintimefd = -1; 586 int timingfd = -1; 587 int nsecfd = -1; 588 int fastclockfd = -1; 589 590 static void 591 inittime(void) 592 { 593 int mode; 594 595 if(impotent) 596 mode = OREAD; 597 else 598 mode = ORDWR; 599 600 /* bind in clocks */ 601 if(access("/dev/time", 0) < 0) 602 bind("#c", "/dev", MAFTER); 603 if(access("/dev/rtc", 0) < 0) 604 bind("#r", "/dev", MAFTER); 605 606 /* figure out what interface we have */ 607 ifc = Ibintime; 608 bintimefd = open("/dev/bintime", mode); 609 if(bintimefd >= 0) 610 return; 611 ifc = Insec; 612 nsecfd = open("/dev/nsec", mode); 613 if(nsecfd < 0) 614 sysfatal("opening /dev/nsec"); 615 fastclockfd = open("/dev/fastclock", mode); 616 if(fastclockfd < 0) 617 sysfatal("opening /dev/fastclock"); 618 timingfd = open("/dev/timing", OREAD); 619 if(timingfd < 0) 620 return; 621 ifc = Itiming; 622 } 623 624 /* 625 * convert binary numbers from/to kernel 626 */ 627 static uvlong uvorder = 0x0001020304050607ULL; 628 629 static uchar* 630 be2vlong(vlong *to, uchar *f) 631 { 632 uchar *t, *o; 633 int i; 634 635 t = (uchar*)to; 636 o = (uchar*)&uvorder; 637 for(i = 0; i < sizeof(vlong); i++) 638 t[o[i]] = f[i]; 639 return f+sizeof(vlong); 640 } 641 642 static uchar* 643 vlong2be(uchar *t, vlong from) 644 { 645 uchar *f, *o; 646 int i; 647 648 f = (uchar*)&from; 649 o = (uchar*)&uvorder; 650 for(i = 0; i < sizeof(vlong); i++) 651 t[i] = f[o[i]]; 652 return t+sizeof(vlong); 653 } 654 655 static long order = 0x00010203; 656 657 static uchar* 658 be2long(long *to, uchar *f) 659 { 660 uchar *t, *o; 661 int i; 662 663 t = (uchar*)to; 664 o = (uchar*)ℴ 665 for(i = 0; i < sizeof(long); i++) 666 t[o[i]] = f[i]; 667 return f+sizeof(long); 668 } 669 670 static uchar* 671 long2be(uchar *t, long from) 672 { 673 uchar *f, *o; 674 int i; 675 676 f = (uchar*)&from; 677 o = (uchar*)ℴ 678 for(i = 0; i < sizeof(long); i++) 679 t[i] = f[o[i]]; 680 return t+sizeof(long); 681 } 682 683 /* 684 * read ticks and local time in nanoseconds 685 */ 686 static int 687 gettime(vlong *nsec, uvlong *ticks, uvlong *hz) 688 { 689 int i, n; 690 uchar ub[3*8], *p; 691 char b[2*24+1]; 692 693 switch(ifc){ 694 case Ibintime: 695 n = sizeof(vlong); 696 if(hz != nil) 697 n = 3*sizeof(vlong); 698 if(ticks != nil) 699 n = 2*sizeof(vlong); 700 i = read(bintimefd, ub, n); 701 if(i != n) 702 break; 703 p = ub; 704 if(nsec != nil) 705 be2vlong(nsec, ub); 706 p += sizeof(vlong); 707 if(ticks != nil) 708 be2vlong((vlong*)ticks, p); 709 p += sizeof(vlong); 710 if(hz != nil) 711 be2vlong((vlong*)hz, p); 712 return 0; 713 case Itiming: 714 n = sizeof(vlong); 715 if(ticks != nil) 716 n = 2*sizeof(vlong); 717 i = read(timingfd, ub, n); 718 if(i != n) 719 break; 720 p = ub; 721 if(nsec != nil) 722 be2vlong(nsec, ub); 723 p += sizeof(vlong); 724 if(ticks != nil) 725 be2vlong((vlong*)ticks, p); 726 if(hz != nil){ 727 seek(fastclockfd, 0, 0); 728 n = read(fastclockfd, b, sizeof(b)-1); 729 if(n <= 0) 730 break; 731 b[n] = 0; 732 *hz = strtoll(b+24, 0, 0); 733 } 734 return 0; 735 case Insec: 736 if(nsec != nil){ 737 seek(nsecfd, 0, 0); 738 n = read(nsecfd, b, sizeof(b)-1); 739 if(n <= 0) 740 break; 741 b[n] = 0; 742 *nsec = strtoll(b, 0, 0); 743 } 744 if(ticks != nil){ 745 seek(fastclockfd, 0, 0); 746 n = read(fastclockfd, b, sizeof(b)-1); 747 if(n <= 0) 748 break; 749 b[n] = 0; 750 *ticks = strtoll(b, 0, 0); 751 } 752 if(hz != nil){ 753 seek(fastclockfd, 0, 0); 754 n = read(fastclockfd, b, sizeof(b)-1); 755 if(n <= 24) 756 break; 757 b[n] = 0; 758 *hz = strtoll(b+24, 0, 0); 759 } 760 return 0; 761 } 762 return -1; 763 } 764 765 static void 766 settime(vlong now, uvlong hz, vlong delta, int n) 767 { 768 uchar b[1+sizeof(vlong)+sizeof(long)], *p; 769 770 if(debug) 771 fprint(2, "settime(now=%lld, hz=%llud, delta=%lld, period=%d)\n", 772 now, hz, delta, n); 773 if(impotent) 774 return; 775 switch(ifc){ 776 case Ibintime: 777 if(now >= 0){ 778 p = b; 779 *p++ = 'n'; 780 p = vlong2be(p, now); 781 if(write(bintimefd, b, p-b) < 0) 782 sysfatal("writing /dev/bintime: %r"); 783 } 784 if(delta != 0){ 785 p = b; 786 *p++ = 'd'; 787 p = vlong2be(p, delta); 788 p = long2be(p, n); 789 if(write(bintimefd, b, p-b) < 0) 790 sysfatal("writing /dev/bintime: %r"); 791 } 792 if(hz != 0){ 793 p = b; 794 *p++ = 'f'; 795 p = vlong2be(p, hz); 796 if(write(bintimefd, b, p-b) < 0) 797 sysfatal("writing /dev/bintime: %r"); 798 } 799 break; 800 case Itiming: 801 case Insec: 802 seek(nsecfd, 0, 0); 803 if(now >= 0 || delta != 0){ 804 if(fprint(nsecfd, "%lld %lld %d", now, delta, n) < 0) 805 sysfatal("writing /dev/nsec: %r"); 806 } 807 if(hz > 0){ 808 seek(fastclockfd, 0, 0); 809 if(fprint(fastclockfd, "%lld", hz) < 0) 810 sysfatal("writing /dev/fastclock: %r"); 811 } 812 } 813 } 814 815 /* 816 * set priority high and wire process to a processor 817 */ 818 static void 819 setpriority(void) 820 { 821 int fd; 822 char buf[32]; 823 824 sprint(buf, "/proc/%d/ctl", getpid()); 825 fd = open(buf, ORDWR); 826 if(fd < 0){ 827 fprint(2, "can't set priority\n"); 828 return; 829 } 830 if(fprint(fd, "pri 100") < 0) 831 fprint(2, "can't set priority\n"); 832 if(fprint(fd, "wired 2") < 0) 833 fprint(2, "can't wire process\n"); 834 close(fd); 835 } 836 837 /* convert to ntp timestamps */ 838 static void 839 hnputts(void *p, vlong nsec) 840 { 841 uchar *a; 842 ulong tsh, tsl; 843 844 a = p; 845 846 /* zero is a special case */ 847 if(nsec == 0) 848 return; 849 850 tsh = nsec/SEC; 851 nsec -= tsh*SEC; 852 tsl = (nsec<<32)/SEC; 853 hnputl(a, tsh+EPOCHDIFF); 854 hnputl(a+4, tsl); 855 } 856 857 /* convert from ntp timestamps */ 858 static vlong 859 nhgetts(void *p) 860 { 861 uchar *a; 862 ulong tsh, tsl; 863 vlong nsec; 864 865 a = p; 866 tsh = nhgetl(a); 867 tsl = nhgetl(a+4); 868 nsec = tsl*SEC; 869 nsec >>= 32; 870 nsec += (tsh - EPOCHDIFF)*SEC; 871 return nsec; 872 } 873 874 /* convert to ntp 32 bit fixed point */ 875 static void 876 hnputfp(void *p, vlong nsec) 877 { 878 uchar *a; 879 ulong fp; 880 881 a = p; 882 883 fp = nsec/(SEC/((vlong)(1<<16))); 884 hnputl(a, fp); 885 } 886 887 /* convert from ntp fixed point to nanosecs */ 888 static vlong 889 nhgetfp(void *p) 890 { 891 uchar *a; 892 ulong fp; 893 vlong nsec; 894 895 a = p; 896 fp = nhgetl(a); 897 nsec = ((vlong)fp)*(SEC/((vlong)(1<<16))); 898 return nsec; 899 } 900 901 /* get network address of the server */ 902 static void 903 setrootid(char *d) 904 { 905 char buf[128]; 906 int fd, n; 907 char *p; 908 909 snprint(buf, sizeof buf, "%s/remote", d); 910 fd = open(buf, OREAD); 911 if(fd < 0) 912 return; 913 n = read(fd, buf, sizeof buf); 914 close(fd); 915 if(n <= 0) 916 return; 917 p = strchr(buf, '!'); 918 if(p != nil) 919 *p = 0; 920 v4parseip(rootid, buf); 921 } 922 923 static void 924 ding(void*, char *s) 925 { 926 if(strstr(s, "alarm") != nil) 927 noted(NCONT); 928 noted(NDFLT); 929 } 930 931 static void 932 addntpserver(char *name) 933 { 934 NTPserver *ns, **l; 935 936 ns = mallocz(sizeof(NTPserver), 1); 937 if(ns == nil) 938 sysfatal("addntpserver: %r"); 939 timeserver = strdup(name); 940 ns->name = name; 941 for(l = &ntpservers; *l != nil; l = &(*l)->next) 942 ; 943 *l = ns; 944 } 945 946 /* 947 * sntp client, we keep calling if the delay seems 948 * unusually high, i.e., 30% longer than avg. 949 */ 950 static int 951 ntptimediff(NTPserver *ns) 952 { 953 int fd, tries, n; 954 NTPpkt ntpin, ntpout; 955 vlong dt, recvts, origts, xmitts, destts, x; 956 char dir[64]; 957 static int whined; 958 959 notify(ding); 960 alarm(30*1000); /* don't wait forever if ns->name is unreachable */ 961 fd = dial(netmkaddr(ns->name, "udp", "ntp"), 0, dir, 0); 962 alarm(0); 963 if(fd < 0){ 964 if (!whined++) 965 syslog(0, logfile, "can't reach %s: %r", ns->name); 966 return -1; 967 } 968 setrootid(dir); 969 970 memset(&ntpout, 0, sizeof(ntpout)); 971 ntpout.mode = 3 | (3 << 3); 972 973 for(tries = 0; tries < 3; tries++){ 974 alarm(2*1000); 975 976 gettime(&x, 0, 0); 977 hnputts(ntpout.xmitts, x); 978 if(write(fd, &ntpout, NTPSIZE) < 0){ 979 alarm(0); 980 continue; 981 } 982 983 n = read(fd, &ntpin, sizeof ntpin); 984 alarm(0); 985 gettime(&destts, 0, 0); 986 if(n >= NTPSIZE){ 987 close(fd); 988 989 /* we got one, use it */ 990 recvts = nhgetts(ntpin.recvts); 991 origts = nhgetts(ntpin.origts); 992 xmitts = nhgetts(ntpin.xmitts); 993 dt = ((recvts - origts) + (xmitts - destts))/2; 994 995 /* save results */ 996 ns->rtt = ((destts - origts) - (xmitts - recvts))/2; 997 ns->dt = dt; 998 ns->stratum = ntpin.stratum; 999 ns->precision = ntpin.precision; 1000 ns->rootdelay = nhgetfp(ntpin.rootdelay); 1001 ns->rootdisp = nhgetfp(ntpin.rootdisp); 1002 1003 if(debug) 1004 fprint(2, "ntp %s stratum %d ntpdelay(%lld)\n", 1005 ns->name, ntpin.stratum, ns->rtt); 1006 return 0; 1007 } 1008 1009 /* try again */ 1010 sleep(250); 1011 } 1012 close(fd); 1013 return -1; 1014 } 1015 1016 static vlong 1017 gpssample(void) 1018 { 1019 vlong l, g, d; 1020 int i, n; 1021 char *v[4], buf[128]; 1022 1023 d = -1000000000000000000LL; 1024 for(i = 0; i < 5; i++){ 1025 sleep(1100); 1026 seek(gpsfil, 0, 0); 1027 n = read(gpsfil, buf, sizeof buf - 1); 1028 if (n <= 0) 1029 return 0; 1030 buf[n] = 0; 1031 n = tokenize(buf, v, nelem(v)); 1032 if(n != 4 || strcmp(v[3], "A") != 0) 1033 return 0; 1034 g = atoll(v[1]); 1035 l = atoll(v[2]); 1036 if(g-l > d) 1037 d = g-l; 1038 } 1039 return d; 1040 } 1041 1042 static vlong 1043 ntpsample(void) 1044 { 1045 NTPserver *tns, *ns; 1046 vlong metric, x; 1047 1048 metric = 1000LL*SEC; 1049 ns = nil; 1050 for(tns = ntpservers; tns != nil; tns = tns->next){ 1051 if(ntptimediff(tns) < 0) 1052 continue; 1053 x = vabs(tns->rootdisp) + (vabs(tns->rtt+tns->rootdelay)>>1); 1054 if(debug) 1055 fprint(2, "ntp %s rootdelay %lld rootdisp %lld metric %lld\n", 1056 tns->name, tns->rootdelay, tns->rootdisp, x); 1057 if(x < metric){ 1058 metric = x; 1059 ns = tns; 1060 } 1061 } 1062 1063 if(ns == nil) 1064 return 0; 1065 1066 /* save data for our server */ 1067 rootdisp = ns->rootdisp; 1068 rootdelay = ns->rootdelay; 1069 mydelay = ns->rtt; 1070 mydisp = avgerr; 1071 if(ns->stratum == 0) 1072 stratum = 0; 1073 else 1074 stratum = ns->stratum + 1; 1075 1076 ε = abs(ns->rtt/2); 1077 return ns->dt; 1078 } 1079 1080 /* 1081 * sample the utc file 1082 */ 1083 static vlong 1084 utcsample(void) 1085 { 1086 vlong s; 1087 int n; 1088 char *v[2], buf[128]; 1089 1090 s = 0; 1091 seek(utcfil, 0, 0); 1092 n = read(utcfil, buf, sizeof buf - 1); 1093 if (n <= 0) 1094 return 0; 1095 buf[n] = 0; 1096 n = tokenize(buf, v, nelem(v)); 1097 if (strcmp(v[0], "0") == 0) 1098 return 0; 1099 if (n == 2) { 1100 gettime(&s, nil, nil); 1101 s -= atoll(v[1]); 1102 } 1103 lastutc = atoll(v[0]) + s; 1104 return lastutc; 1105 } 1106 1107 /* 1108 * sntp server 1109 */ 1110 static int 1111 openlisten(char *net) 1112 { 1113 int fd, cfd; 1114 char data[128], devdir[40]; 1115 1116 sprint(data, "%s/udp!*!ntp", net); 1117 cfd = announce(data, devdir); 1118 if(cfd < 0) 1119 sysfatal("can't announce"); 1120 if(fprint(cfd, "headers") < 0) 1121 sysfatal("can't set header mode"); 1122 1123 sprint(data, "%s/data", devdir); 1124 fd = open(data, ORDWR); 1125 if(fd < 0) 1126 sysfatal("open %s: %r", data); 1127 return fd; 1128 } 1129 1130 static void 1131 ntpserver(char *servenet) 1132 { 1133 int fd, n, vers, mode; 1134 vlong recvts, x; 1135 char buf[512]; 1136 NTPpkt *ntp; 1137 1138 fd = openlisten(servenet); 1139 1140 if (Rootid == nil) 1141 switch(type){ 1142 case Fs: 1143 Rootid = "WWV"; 1144 break; 1145 case Rtc: 1146 Rootid = "LOCL"; 1147 break; 1148 case Utc: 1149 Rootid = "UTC"; 1150 break; 1151 case Gps: 1152 Rootid = "GPS"; 1153 break; 1154 case Ntp: 1155 /* set by the ntp client */ 1156 break; 1157 } 1158 if (Rootid != nil) 1159 memmove(rootid, Rootid, strlen(Rootid) > 4? 4: strlen(Rootid)); 1160 1161 for(;;){ 1162 n = read(fd, buf, sizeof buf); 1163 gettime(&recvts, 0, 0); 1164 if(n <= 0) { 1165 /* don't croak on input error, but don't spin either */ 1166 sleep(500); 1167 continue; 1168 } 1169 if(n < Udphdrsize + NTPSIZE) 1170 continue; 1171 1172 ntp = (NTPpkt*)(buf + Udphdrsize); 1173 mode = ntp->mode & 7; 1174 vers = (ntp->mode>>3) & 7; 1175 if(mode != 3) 1176 continue; 1177 1178 ntp->mode = (vers<<3)|4; 1179 ntp->stratum = stratum; 1180 ntp->precision = myprec; 1181 hnputfp(ntp->rootdelay, rootdelay + mydelay); 1182 hnputfp(ntp->rootdisp, rootdisp + mydisp); 1183 hnputts(ntp->refts, lastutc); 1184 memmove(ntp->origts, ntp->xmitts, sizeof(ntp->origts)); 1185 hnputts(ntp->recvts, recvts); 1186 memmove(ntp->rootid, rootid, sizeof(ntp->rootid)); 1187 gettime(&x, 0, 0); 1188 hnputts(ntp->xmitts, x); 1189 write(fd, buf, NTPSIZE + Udphdrsize); 1190 } 1191 } 1192 1193 /* 1194 * get the current time from the file system 1195 */ 1196 static long 1197 fstime(void) 1198 { 1199 Dir *d; 1200 ulong t; 1201 1202 d = dirstat("/n/boot"); 1203 if(d != nil){ 1204 t = d->atime; 1205 free(d); 1206 } else 1207 t = 0; 1208 return t; 1209 } 1210 1211 /* 1212 * get the current time from the real time clock 1213 */ 1214 static long 1215 rtctime(void) 1216 { 1217 char b[20]; 1218 static int f = -1; 1219 int i, retries; 1220 1221 memset(b, 0, sizeof(b)); 1222 for(retries = 0; retries < 100; retries++){ 1223 if(f < 0) 1224 f = open("/dev/rtc", OREAD|OCEXEC); 1225 if(f < 0) 1226 break; 1227 if(seek(f, 0, 0) < 0 || (i = read(f, b, sizeof b)) < 0){ 1228 close(f); 1229 f = -1; 1230 } else 1231 if(i != 0) 1232 break; 1233 } 1234 return strtoul(b, 0, 10)+gmtdelta; 1235 } 1236 1237 1238 /* 1239 * Sample a clock. We wait for the clock to always 1240 * be at the leading edge of a clock period. 1241 */ 1242 static vlong 1243 sample(long (*get)(void)) 1244 { 1245 long this, last; 1246 vlong start, end; 1247 1248 /* 1249 * wait for the second to change 1250 */ 1251 last = (*get)(); 1252 for(;;){ 1253 gettime(&start, 0, 0); 1254 this = (*get)(); 1255 gettime(&end, 0, 0); 1256 if(this != last) 1257 break; 1258 last = this; 1259 } 1260 return SEC*this - (end-start)/2; 1261 } 1262 1263 /* 1264 * the name of the frequency file has the method and possibly the 1265 * server name encoded in it. 1266 */ 1267 static int 1268 openfreqfile(void) 1269 { 1270 char *p; 1271 int fd; 1272 1273 if(sysid == nil) 1274 return -1; 1275 1276 switch(type){ 1277 case Ntp: 1278 p = smprint("%s/ts.%s.%d.%s", dir, sysid, type, timeserver); 1279 break; 1280 default: 1281 p = smprint("%s/ts.%s.%d", dir, sysid, type); 1282 break; 1283 } 1284 fd = open(p, ORDWR); 1285 if(fd < 0) 1286 fd = create(p, ORDWR, 0666); 1287 free(p); 1288 if(fd < 0) 1289 return -1; 1290 return fd; 1291 } 1292 1293 /* 1294 * the file contains the last known frequency and the 1295 * number of seconds it was sampled over 1296 */ 1297 static vlong 1298 readfreqfile(int fd, vlong ohz, vlong minhz, vlong maxhz) 1299 { 1300 int n; 1301 char buf[128]; 1302 vlong hz; 1303 1304 n = read(fd, buf, sizeof buf-1); 1305 if(n <= 0) 1306 return ohz; 1307 buf[n] = 0; 1308 hz = strtoll(buf, nil, 0); 1309 1310 if(hz > maxhz || hz < minhz) 1311 return ohz; 1312 1313 settime(-1, hz, 0, 0); 1314 return hz; 1315 } 1316 1317 /* 1318 * remember hz and averaging period 1319 */ 1320 static void 1321 writefreqfile(int fd, vlong hz, int secs, vlong diff) 1322 { 1323 long now; 1324 static long last; 1325 1326 if(fd < 0) 1327 return; 1328 now = time(0); 1329 if(now - last < 10*60) 1330 return; 1331 last = now; 1332 if(seek(fd, 0, 0) < 0) 1333 return; 1334 fprint(fd, "%lld %d %d %lld\n", hz, secs, type, diff); 1335 } 1336 1337 static uvlong 1338 vabs(vlong x) 1339 { 1340 if(x < 0) 1341 return -x; 1342 else 1343 return x; 1344 } 1345 1346 static void 1347 background(void) 1348 { 1349 static int inbackground; 1350 1351 if(inbackground) 1352 return; 1353 1354 if(!debug) 1355 switch(rfork(RFPROC|RFFDG|RFNAMEG|RFNOTEG|RFNOWAIT)){ 1356 case -1: 1357 sysfatal("forking: %r"); 1358 break; 1359 case 0: 1360 break; 1361 default: 1362 exits(0); 1363 } 1364 inbackground = 1; 1365 } 1366 1367 static int 1368 getclockprecision(vlong hz) 1369 { 1370 int i; 1371 1372 i = 8; 1373 while(hz > 0){ 1374 i--; 1375 hz >>= 1; 1376 } 1377 return i; 1378 } 1379