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