xref: /freebsd/contrib/ntp/libntp/systime.c (revision 641a6cfb86023499caafe26a4d821a0b885cf00b)
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
43 double	sys_tick = 10e-3;	/* 10 ms tickadj() */
44 #else
45 double	sys_tick = 1e-6;	/* 1 us tickadj() */
46 #endif
47 double	sys_residual = 0;	/* adjustment residue (s) */
48 
49 #ifndef SIM
50 
51 /*
52  * get_systime - return system time in NTP timestamp format.
53  */
54 void
55 get_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
119 int				/* 0 okay, 1 error */
120 adj_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  */
172 int
173 step_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  */
369 void
370 get_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  */
392 int				/* always succeeds */
393 adj_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  */
438 int				/* always succeeds */
439 step_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  */
455 int				/* always succeeds */
456 node_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  */
500 double				/* Gaussian sample */
501 gauss(
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  */
524 double				/* delay sample (s) */
525 poisson(
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