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