systime.c revision 182007
1/*
2 * systime -- routines to fiddle a UNIX clock.
3 *
4 * ATTENTION: Get approval from Dave Mills on all changes to this file!
5 *
6 */
7#include "ntp_machine.h"
8#include "ntp_fp.h"
9#include "ntp_syslog.h"
10#include "ntp_unixtime.h"
11#include "ntp_stdlib.h"
12#include "ntp_random.h"
13#include "ntpd.h"		/* for sys_precision */
14
15#ifdef SIM
16# include "ntpsim.h"
17#endif /*SIM */
18
19#ifdef HAVE_SYS_PARAM_H
20# include <sys/param.h>
21#endif
22#ifdef HAVE_UTMP_H
23# include <utmp.h>
24#endif /* HAVE_UTMP_H */
25#ifdef HAVE_UTMPX_H
26# include <utmpx.h>
27#endif /* HAVE_UTMPX_H */
28
29/*
30 * These routines (get_systime, step_systime, adj_systime) implement an
31 * interface between the system independent NTP clock and the Unix
32 * system clock in various architectures and operating systems.
33 *
34 * Time is a precious quantity in these routines and every effort is
35 * made to minimize errors by always rounding toward zero and amortizing
36 * adjustment residues. By default the adjustment quantum is 1 us for
37 * the usual Unix tickadj() system call, but this can be increased if
38 * necessary by the tick configuration command. For instance, when the
39 * adjtime() quantum is a clock tick for a 100-Hz clock, the quantum
40 * should be 10 ms.
41 */
42#if defined RELIANTUNIX_CLOCK || defined SCO5_CLOCK
43double	sys_tick = 10e-3;	/* 10 ms tickadj() */
44#else
45double	sys_tick = 1e-6;	/* 1 us tickadj() */
46#endif
47double	sys_residual = 0;	/* adjustment residue (s) */
48
49#ifndef SIM
50
51/*
52 * get_systime - return system time in NTP timestamp format.
53 */
54void
55get_systime(
56	l_fp *now		/* system time */
57	)
58{
59	double dtemp;
60
61#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
62	struct timespec ts;	/* seconds and nanoseconds */
63
64	/*
65	 * Convert Unix clock from seconds and nanoseconds to seconds.
66	 * The bottom is only two bits down, so no need for fuzz.
67	 * Some systems don't have that level of precision, however...
68	 */
69# ifdef HAVE_CLOCK_GETTIME
70	clock_gettime(CLOCK_REALTIME, &ts);
71# else
72	getclock(TIMEOFDAY, &ts);
73# endif
74	now->l_i = ts.tv_sec + JAN_1970;
75	dtemp = ts.tv_nsec / 1e9;
76
77#else /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
78	struct timeval tv;	/* seconds and microseconds */
79
80	/*
81	 * Convert Unix clock from seconds and microseconds to seconds.
82	 * Add in unbiased random fuzz beneath the microsecond.
83	 */
84	GETTIMEOFDAY(&tv, NULL);
85	now->l_i = tv.tv_sec + JAN_1970;
86	dtemp = tv.tv_usec / 1e6;
87
88#endif /* HAVE_CLOCK_GETTIME || HAVE_GETCLOCK */
89
90	/*
91	 * ntp_random() produces 31 bits (always nonnegative).
92	 * This bit is done only after the precision has been
93	 * determined.
94	 */
95	if (sys_precision != 0)
96		dtemp += (ntp_random() / FRAC - .5) / (1 <<
97		    -sys_precision);
98
99	/*
100	 * Renormalize to seconds past 1900 and fraction.
101	 */
102	dtemp += sys_residual;
103	if (dtemp >= 1) {
104		dtemp -= 1;
105		now->l_i++;
106	} else if (dtemp < 0) {
107		dtemp += 1;
108		now->l_i--;
109	}
110	dtemp *= FRAC;
111	now->l_uf = (u_int32)dtemp;
112}
113
114
115/*
116 * adj_systime - adjust system time by the argument.
117 */
118#if !defined SYS_WINNT
119int				/* 0 okay, 1 error */
120adj_systime(
121	double now		/* adjustment (s) */
122	)
123{
124	struct timeval adjtv;	/* new adjustment */
125	struct timeval oadjtv;	/* residual adjustment */
126	double	dtemp;
127	long	ticks;
128	int	isneg = 0;
129
130	/*
131	 * Most Unix adjtime() implementations adjust the system clock
132	 * in microsecond quanta, but some adjust in 10-ms quanta. We
133	 * carefully round the adjustment to the nearest quantum, then
134	 * adjust in quanta and keep the residue for later.
135	 */
136	dtemp = now + sys_residual;
137	if (dtemp < 0) {
138		isneg = 1;
139		dtemp = -dtemp;
140	}
141	adjtv.tv_sec = (long)dtemp;
142	dtemp -= adjtv.tv_sec;
143	ticks = (long)(dtemp / sys_tick + .5);
144	adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
145	dtemp -= adjtv.tv_usec / 1e6;
146	sys_residual = dtemp;
147
148	/*
149	 * Convert to signed seconds and microseconds for the Unix
150	 * adjtime() system call. Note we purposely lose the adjtime()
151	 * leftover.
152	 */
153	if (isneg) {
154		adjtv.tv_sec = -adjtv.tv_sec;
155		adjtv.tv_usec = -adjtv.tv_usec;
156		sys_residual = -sys_residual;
157	}
158	if (adjtv.tv_sec != 0 || adjtv.tv_usec != 0) {
159		if (adjtime(&adjtv, &oadjtv) < 0) {
160			msyslog(LOG_ERR, "adj_systime: %m");
161			return (0);
162		}
163	}
164	return (1);
165}
166#endif
167
168
169/*
170 * step_systime - step the system clock.
171 */
172int
173step_systime(
174	double now
175	)
176{
177	struct timeval timetv, adjtv, oldtimetv;
178	int isneg = 0;
179	double dtemp;
180#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
181	struct timespec ts;
182#endif
183
184	dtemp = sys_residual + now;
185	if (dtemp < 0) {
186		isneg = 1;
187		dtemp = - dtemp;
188		adjtv.tv_sec = (int32)dtemp;
189		adjtv.tv_usec = (u_int32)((dtemp -
190		    (double)adjtv.tv_sec) * 1e6 + .5);
191	} else {
192		adjtv.tv_sec = (int32)dtemp;
193		adjtv.tv_usec = (u_int32)((dtemp -
194		    (double)adjtv.tv_sec) * 1e6 + .5);
195	}
196#if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_GETCLOCK)
197# ifdef HAVE_CLOCK_GETTIME
198	(void) clock_gettime(CLOCK_REALTIME, &ts);
199# else
200	(void) getclock(TIMEOFDAY, &ts);
201# endif
202	timetv.tv_sec = ts.tv_sec;
203	timetv.tv_usec = ts.tv_nsec / 1000;
204#else /*  not HAVE_GETCLOCK */
205	(void) GETTIMEOFDAY(&timetv, (struct timezone *)0);
206#endif /* not HAVE_GETCLOCK */
207
208	oldtimetv = timetv;
209
210#ifdef DEBUG
211	if (debug)
212		printf("step_systime: step %.6f residual %.6f\n", now, sys_residual);
213#endif
214	if (isneg) {
215		timetv.tv_sec -= adjtv.tv_sec;
216		timetv.tv_usec -= adjtv.tv_usec;
217		if (timetv.tv_usec < 0) {
218			timetv.tv_sec--;
219			timetv.tv_usec += 1000000;
220		}
221	} else {
222		timetv.tv_sec += adjtv.tv_sec;
223		timetv.tv_usec += adjtv.tv_usec;
224		if (timetv.tv_usec >= 1000000) {
225			timetv.tv_sec++;
226			timetv.tv_usec -= 1000000;
227		}
228	}
229	if (ntp_set_tod(&timetv, NULL) != 0) {
230		msyslog(LOG_ERR, "step-systime: %m");
231		return (0);
232	}
233	sys_residual = 0;
234
235#ifdef NEED_HPUX_ADJTIME
236	/*
237	 * CHECKME: is this correct when called by ntpdate?????
238	 */
239	_clear_adjtime();
240#endif
241
242	/*
243	 * FreeBSD, for example, has:
244	 * struct utmp {
245	 *	   char    ut_line[UT_LINESIZE];
246	 *	   char    ut_name[UT_NAMESIZE];
247	 *	   char    ut_host[UT_HOSTSIZE];
248	 *	   long    ut_time;
249	 * };
250	 * and appends line="|", name="date", host="", time for the OLD
251	 * and appends line="{", name="date", host="", time for the NEW
252	 * to _PATH_WTMP .
253	 *
254	 * Some OSes have utmp, some have utmpx.
255	 */
256
257	/*
258	 * Write old and new time entries in utmp and wtmp if step
259	 * adjustment is greater than one second.
260	 *
261	 * This might become even Uglier...
262	 */
263	if (oldtimetv.tv_sec != timetv.tv_sec)
264	{
265#ifdef HAVE_UTMP_H
266		struct utmp ut;
267#endif
268#ifdef HAVE_UTMPX_H
269		struct utmpx utx;
270#endif
271
272#ifdef HAVE_UTMP_H
273		memset((char *)&ut, 0, sizeof(ut));
274#endif
275#ifdef HAVE_UTMPX_H
276		memset((char *)&utx, 0, sizeof(utx));
277#endif
278
279		/* UTMP */
280
281#ifdef UPDATE_UTMP
282# ifdef HAVE_PUTUTLINE
283		ut.ut_type = OLD_TIME;
284		(void)strcpy(ut.ut_line, OTIME_MSG);
285		ut.ut_time = oldtimetv.tv_sec;
286		pututline(&ut);
287		setutent();
288		ut.ut_type = NEW_TIME;
289		(void)strcpy(ut.ut_line, NTIME_MSG);
290		ut.ut_time = timetv.tv_sec;
291		pututline(&ut);
292		endutent();
293# else /* not HAVE_PUTUTLINE */
294# endif /* not HAVE_PUTUTLINE */
295#endif /* UPDATE_UTMP */
296
297		/* UTMPX */
298
299#ifdef UPDATE_UTMPX
300# ifdef HAVE_PUTUTXLINE
301		utx.ut_type = OLD_TIME;
302		(void)strcpy(utx.ut_line, OTIME_MSG);
303		utx.ut_tv = oldtimetv;
304		pututxline(&utx);
305		setutxent();
306		utx.ut_type = NEW_TIME;
307		(void)strcpy(utx.ut_line, NTIME_MSG);
308		utx.ut_tv = timetv;
309		pututxline(&utx);
310		endutxent();
311# else /* not HAVE_PUTUTXLINE */
312# endif /* not HAVE_PUTUTXLINE */
313#endif /* UPDATE_UTMPX */
314
315		/* WTMP */
316
317#ifdef UPDATE_WTMP
318# ifdef HAVE_PUTUTLINE
319		utmpname(WTMP_FILE);
320		ut.ut_type = OLD_TIME;
321		(void)strcpy(ut.ut_line, OTIME_MSG);
322		ut.ut_time = oldtimetv.tv_sec;
323		pututline(&ut);
324		ut.ut_type = NEW_TIME;
325		(void)strcpy(ut.ut_line, NTIME_MSG);
326		ut.ut_time = timetv.tv_sec;
327		pututline(&ut);
328		endutent();
329# else /* not HAVE_PUTUTLINE */
330# endif /* not HAVE_PUTUTLINE */
331#endif /* UPDATE_WTMP */
332
333		/* WTMPX */
334
335#ifdef UPDATE_WTMPX
336# ifdef HAVE_PUTUTXLINE
337		utx.ut_type = OLD_TIME;
338		utx.ut_tv = oldtimetv;
339		(void)strcpy(utx.ut_line, OTIME_MSG);
340#  ifdef HAVE_UPDWTMPX
341		updwtmpx(WTMPX_FILE, &utx);
342#  else /* not HAVE_UPDWTMPX */
343#  endif /* not HAVE_UPDWTMPX */
344# else /* not HAVE_PUTUTXLINE */
345# endif /* not HAVE_PUTUTXLINE */
346# ifdef HAVE_PUTUTXLINE
347		utx.ut_type = NEW_TIME;
348		utx.ut_tv = timetv;
349		(void)strcpy(utx.ut_line, NTIME_MSG);
350#  ifdef HAVE_UPDWTMPX
351		updwtmpx(WTMPX_FILE, &utx);
352#  else /* not HAVE_UPDWTMPX */
353#  endif /* not HAVE_UPDWTMPX */
354# else /* not HAVE_PUTUTXLINE */
355# endif /* not HAVE_PUTUTXLINE */
356#endif /* UPDATE_WTMPX */
357
358	}
359	return (1);
360}
361
362#else /* SIM */
363/*
364 * Clock routines for the simulator - Harish Nair, with help
365 */
366/*
367 * get_systime - return the system time in NTP timestamp format
368 */
369void
370get_systime(
371        l_fp *now		/* current system time in l_fp */        )
372{
373	/*
374	 * To fool the code that determines the local clock precision,
375	 * we advance the clock a minimum of 200 nanoseconds on every
376	 * clock read. This is appropriate for a typical modern machine
377	 * with nanosecond clocks. Note we make no attempt here to
378	 * simulate reading error, since the error is so small. This may
379	 * change when the need comes to implement picosecond clocks.
380	 */
381	if (ntp_node.ntp_time == ntp_node.last_time)
382		ntp_node.ntp_time += 200e-9;
383	ntp_node.last_time = ntp_node.ntp_time;
384	DTOLFP(ntp_node.ntp_time, now);
385}
386
387
388/*
389 * adj_systime - advance or retard the system clock exactly like the
390 * real thng.
391 */
392int				/* always succeeds */
393adj_systime(
394        double now		/* time adjustment (s) */
395        )
396{
397	struct timeval adjtv;	/* new adjustment */
398	double	dtemp;
399	long	ticks;
400	int	isneg = 0;
401
402	/*
403	 * Most Unix adjtime() implementations adjust the system clock
404	 * in microsecond quanta, but some adjust in 10-ms quanta. We
405	 * carefully round the adjustment to the nearest quantum, then
406	 * adjust in quanta and keep the residue for later.
407	 */
408	dtemp = now + sys_residual;
409	if (dtemp < 0) {
410		isneg = 1;
411		dtemp = -dtemp;
412	}
413	adjtv.tv_sec = (long)dtemp;
414	dtemp -= adjtv.tv_sec;
415	ticks = (long)(dtemp / sys_tick + .5);
416	adjtv.tv_usec = (long)(ticks * sys_tick * 1e6);
417	dtemp -= adjtv.tv_usec / 1e6;
418	sys_residual = dtemp;
419
420	/*
421	 * Convert to signed seconds and microseconds for the Unix
422	 * adjtime() system call. Note we purposely lose the adjtime()
423	 * leftover.
424	 */
425	if (isneg) {
426		adjtv.tv_sec = -adjtv.tv_sec;
427		adjtv.tv_usec = -adjtv.tv_usec;
428		sys_residual = -sys_residual;
429	}
430	ntp_node.adj = now;
431	return (1);
432}
433
434
435/*
436 * step_systime - step the system clock. We are religious here.
437 */
438int				/* always succeeds */
439step_systime(
440        double now		/* step adjustment (s) */
441        )
442{
443#ifdef DEBUG
444	if (debug)
445		printf("step_systime: time %.6f adj %.6f\n",
446		   ntp_node.ntp_time, now);
447#endif
448	ntp_node.ntp_time += now;
449	return (1);
450}
451
452/*
453 * node_clock - update the clocks
454 */
455int				/* always succeeds */
456node_clock(
457	Node *n,		/* global node pointer */
458	double t		/* node time */
459	)
460{
461	double	dtemp;
462
463	/*
464	 * Advance client clock (ntp_time). Advance server clock
465	 * (clk_time) adjusted for systematic and random frequency
466	 * errors. The random error is a random walk computed as the
467	 * integral of samples from a Gaussian distribution.
468	 */
469	dtemp = t - n->ntp_time;
470	n->time = t;
471	n->ntp_time += dtemp;
472	n->ferr += gauss(0, dtemp * n->fnse);
473	n->clk_time += dtemp * (1 + n->ferr);
474
475	/*
476	 * Perform the adjtime() function. If the adjustment completed
477	 * in the previous interval, amortize the entire amount; if not,
478	 * carry the leftover to the next interval.
479	 */
480	dtemp *= n->slew;
481	if (dtemp < fabs(n->adj)) {
482		if (n->adj < 0) {
483			n->adj += dtemp;
484			n->ntp_time -= dtemp;
485		} else {
486			n->adj -= dtemp;
487			n->ntp_time += dtemp;
488		}
489	} else {
490		n->ntp_time += n->adj;
491		n->adj = 0;
492	}
493        return (0);
494}
495
496
497/*
498 * gauss() - returns samples from a gaussion distribution
499 */
500double				/* Gaussian sample */
501gauss(
502	double m,		/* sample mean */
503	double s		/* sample standard deviation (sigma) */
504	)
505{
506        double q1, q2;
507
508	/*
509	 * Roll a sample from a Gaussian distribution with mean m and
510	 * standard deviation s. For m = 0, s = 1, mean(y) = 0,
511	 * std(y) = 1.
512	 */
513	if (s == 0)
514		return (m);
515        while ((q1 = drand48()) == 0);
516        q2 = drand48();
517        return (m + s * sqrt(-2. * log(q1)) * cos(2. * PI * q2));
518}
519
520
521/*
522 * poisson() - returns samples from a network delay distribution
523 */
524double				/* delay sample (s) */
525poisson(
526	double m,		/* fixed propagation delay (s) */
527	double s		/* exponential parameter (mu) */
528	)
529{
530        double q1;
531
532	/*
533	 * Roll a sample from a composite distribution with propagation
534	 * delay m and exponential distribution time with parameter s.
535	 * For m = 0, s = 1, mean(y) = std(y) = 1.
536	 */
537	if (s == 0)
538		return (m);
539        while ((q1 = drand48()) == 0);
540        return (m - s * log(q1 * s));
541}
542#endif /* SIM */
543