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