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