xref: /netbsd-src/external/bsd/ntp/dist/ntpd/ntp_timer.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: ntp_timer.c,v 1.1.1.3 2013/12/27 23:31:03 christos Exp $	*/
2 
3 /*
4  * ntp_timer.c - event timer support routines
5  */
6 #ifdef HAVE_CONFIG_H
7 # include <config.h>
8 #endif
9 
10 #include "ntp_machine.h"
11 #include "ntpd.h"
12 #include "ntp_stdlib.h"
13 #include "ntp_calendar.h"
14 #include "ntp_leapsec.h"
15 
16 #if defined(HAVE_IO_COMPLETION_PORT)
17 # include "ntp_iocompletionport.h"
18 # include "ntp_timer.h"
19 #endif
20 
21 #include <stdio.h>
22 #include <signal.h>
23 #ifdef HAVE_SYS_SIGNAL_H
24 # include <sys/signal.h>
25 #endif
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 
30 #ifdef KERNEL_PLL
31 #include "ntp_syscall.h"
32 #endif /* KERNEL_PLL */
33 
34 #ifdef AUTOKEY
35 #include <openssl/rand.h>
36 #endif	/* AUTOKEY */
37 
38 
39 /* TC_ERR represents the timer_create() error return value. */
40 #ifdef SYS_VXWORKS
41 #define	TC_ERR	ERROR
42 #else
43 #define	TC_ERR	(-1)
44 #endif
45 
46 extern char *leapseconds_file;	/* name of the leapseconds file */
47 
48 static void check_leapsec(u_int32, const time_t*, int/*BOOL*/);
49 
50 /*
51  * These routines provide support for the event timer.  The timer is
52  * implemented by an interrupt routine which sets a flag once every
53  * second, and a timer routine which is called when the mainline code
54  * gets around to seeing the flag.  The timer routine dispatches the
55  * clock adjustment code if its time has come, then searches the timer
56  * queue for expiries which are dispatched to the transmit procedure.
57  * Finally, we call the hourly procedure to do cleanup and print a
58  * message.
59  */
60 volatile int interface_interval;     /* init_io() sets def. 300s */
61 
62 /*
63  * Alarm flag. The mainline code imports this.
64  */
65 volatile int alarm_flag;
66 
67 /*
68  * The counters and timeouts
69  */
70 static  u_long interface_timer;	/* interface update timer */
71 static	u_long adjust_timer;	/* second timer */
72 static	u_long stats_timer;	/* stats timer */
73 static	u_long check_leapfile;	/* Report leapfile problems once/day */
74 static	u_long huffpuff_timer;	/* huff-n'-puff timer */
75 static	u_long worker_idle_timer;/* next check for idle intres */
76 u_long	leapsec;	        /* seconds to next leap (proximity class) */
77 int     leapdif;                /* TAI difference step at next leap second*/
78 u_long	orphwait; 		/* orphan wait time */
79 #ifdef AUTOKEY
80 static	u_long revoke_timer;	/* keys revoke timer */
81 static	u_long keys_timer;	/* session key timer */
82 u_long	sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
83 u_long	sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
84 #endif	/* AUTOKEY */
85 
86 /*
87  * Statistics counter for the interested.
88  */
89 volatile u_long alarm_overflow;
90 
91 u_long current_time;		/* seconds since startup */
92 
93 /*
94  * Stats.  Number of overflows and number of calls to transmit().
95  */
96 u_long timer_timereset;
97 u_long timer_overflows;
98 u_long timer_xmtcalls;
99 
100 #if defined(VMS)
101 static int vmstimer[2]; 	/* time for next timer AST */
102 static int vmsinc[2];		/* timer increment */
103 #endif /* VMS */
104 
105 #ifdef SYS_WINNT
106 HANDLE WaitableTimerHandle;
107 #else
108 static	RETSIGTYPE alarming (int);
109 #endif /* SYS_WINNT */
110 
111 #if !defined(VMS)
112 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
113 #  ifdef HAVE_TIMER_CREATE
114 static timer_t timer_id;
115 typedef struct itimerspec intervaltimer;
116 #   define	itv_frac	tv_nsec
117 #  else
118 typedef struct itimerval intervaltimer;
119 #   define	itv_frac	tv_usec
120 #  endif
121 intervaltimer itimer;
122 # endif
123 #endif
124 
125 #if !defined(SYS_WINNT) && !defined(VMS)
126 void	set_timer_or_die(const intervaltimer *);
127 #endif
128 
129 
130 #if !defined(SYS_WINNT) && !defined(VMS)
131 void
132 set_timer_or_die(
133 	const intervaltimer *	ptimer
134 	)
135 {
136 	const char *	setfunc;
137 	int		rc;
138 
139 # ifdef HAVE_TIMER_CREATE
140 	setfunc = "timer_settime";
141 	rc = timer_settime(timer_id, 0, &itimer, NULL);
142 # else
143 	setfunc = "setitimer";
144 	rc = setitimer(ITIMER_REAL, &itimer, NULL);
145 # endif
146 	if (-1 == rc) {
147 		msyslog(LOG_ERR, "interval timer %s failed, %m",
148 			setfunc);
149 		exit(1);
150 	}
151 }
152 #endif	/* !SYS_WINNT && !VMS */
153 
154 
155 /*
156  * reinit_timer - reinitialize interval timer after a clock step.
157  */
158 void
159 reinit_timer(void)
160 {
161 #if !defined(SYS_WINNT) && !defined(VMS)
162 	ZERO(itimer);
163 # ifdef HAVE_TIMER_CREATE
164 	timer_gettime(timer_id, &itimer);
165 # else
166 	getitimer(ITIMER_REAL, &itimer);
167 # endif
168 	if (itimer.it_value.tv_sec < 0 ||
169 	    itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT))
170 		itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
171 	if (itimer.it_value.itv_frac < 0)
172 		itimer.it_value.itv_frac = 0;
173 	if (0 == itimer.it_value.tv_sec &&
174 	    0 == itimer.it_value.itv_frac)
175 		itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
176 	itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT);
177 	itimer.it_interval.itv_frac = 0;
178 	set_timer_or_die(&itimer);
179 # endif /* VMS */
180 }
181 
182 
183 /*
184  * init_timer - initialize the timer data structures
185  */
186 void
187 init_timer(void)
188 {
189 	/*
190 	 * Initialize...
191 	 */
192 	alarm_flag = FALSE;
193 	alarm_overflow = 0;
194 	adjust_timer = 1;
195 	stats_timer = SECSPERHR;
196 	check_leapfile = 0;
197 	huffpuff_timer = 0;
198 	interface_timer = 0;
199 	current_time = 0;
200 	timer_overflows = 0;
201 	timer_xmtcalls = 0;
202 	timer_timereset = 0;
203 
204 #ifndef SYS_WINNT
205 	/*
206 	 * Set up the alarm interrupt.	The first comes 2**EVENT_TIMEOUT
207 	 * seconds from now and they continue on every 2**EVENT_TIMEOUT
208 	 * seconds.
209 	 */
210 # ifndef VMS
211 #  ifdef HAVE_TIMER_CREATE
212 	if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) {
213 		msyslog(LOG_ERR, "timer_create failed, %m");
214 		exit(1);
215 	}
216 #  endif
217 	signal_no_reset(SIGALRM, alarming);
218 	itimer.it_interval.tv_sec =
219 		itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
220 	itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0;
221 	set_timer_or_die(&itimer);
222 # else	/* VMS follows */
223 	vmsinc[0] = 10000000;		/* 1 sec */
224 	vmsinc[1] = 0;
225 	lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
226 
227 	sys$gettim(&vmstimer);	/* that's "now" as abstime */
228 
229 	lib$addx(&vmsinc, &vmstimer, &vmstimer);
230 	sys$setimr(0, &vmstimer, alarming, alarming, 0);
231 # endif	/* VMS */
232 #else	/* SYS_WINNT follows */
233 	/*
234 	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
235 	 * Under Windows/NT,
236 	 */
237 
238 	WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
239 	if (WaitableTimerHandle == NULL) {
240 		msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
241 		exit(1);
242 	}
243 	else {
244 		DWORD		Period;
245 		LARGE_INTEGER	DueTime;
246 		BOOL		rc;
247 
248 		Period = (1 << EVENT_TIMEOUT) * 1000;
249 		DueTime.QuadPart = Period * 10000i64;
250 		rc = SetWaitableTimer(WaitableTimerHandle, &DueTime,
251 				      Period, NULL, NULL, FALSE);
252 		if (!rc) {
253 			msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
254 			exit(1);
255 		}
256 	}
257 
258 #endif	/* SYS_WINNT */
259 }
260 
261 
262 /*
263  * intres_timeout_req(s) is invoked in the parent to schedule an idle
264  * timeout to fire in s seconds, if not reset earlier by a call to
265  * intres_timeout_req(0), which clears any pending timeout.  When the
266  * timeout expires, worker_idle_timer_fired() is invoked (again, in the
267  * parent).
268  *
269  * sntp and ntpd each provide implementations adapted to their timers.
270  */
271 void
272 intres_timeout_req(
273 	u_int	seconds		/* 0 cancels */
274 	)
275 {
276 	if (0 == seconds) {
277 		worker_idle_timer = 0;
278 		return;
279 	}
280 	worker_idle_timer = current_time + seconds;
281 }
282 
283 
284 /*
285  * timer - event timer
286  */
287 void
288 timer(void)
289 {
290 	struct peer *	p;
291 	struct peer *	next_peer;
292 	l_fp		now;
293 	time_t          tnow;
294 
295 	/*
296 	 * The basic timerevent is one second.  This is used to adjust the
297 	 * system clock in time and frequency, implement the kiss-o'-death
298 	 * function and the association polling function.
299 	 */
300 	current_time++;
301 	if (adjust_timer <= current_time) {
302 		adjust_timer += 1;
303 		adj_host_clock();
304 #ifdef REFCLOCK
305 		for (p = peer_list; p != NULL; p = next_peer) {
306 			next_peer = p->p_link;
307 			if (FLAG_REFCLOCK & p->flags)
308 				refclock_timer(p);
309 		}
310 #endif /* REFCLOCK */
311 	}
312 
313 	/*
314 	 * Now dispatch any peers whose event timer has expired. Be
315 	 * careful here, since the peer structure might go away as the
316 	 * result of the call.
317 	 */
318 	for (p = peer_list; p != NULL; p = next_peer) {
319 		next_peer = p->p_link;
320 
321 		/*
322 		 * Restrain the non-burst packet rate not more
323 		 * than one packet every 16 seconds. This is
324 		 * usually tripped using iburst and minpoll of
325 		 * 128 s or less.
326 		 */
327 		if (p->throttle > 0)
328 			p->throttle--;
329 		if (p->nextdate <= current_time) {
330 #ifdef REFCLOCK
331 			if (FLAG_REFCLOCK & p->flags)
332 				refclock_transmit(p);
333 			else
334 #endif	/* REFCLOCK */
335 				transmit(p);
336 		}
337 	}
338 
339 	/*
340 	 * Orphan mode is active when enabled and when no servers less
341 	 * than the orphan stratum are available. A server with no other
342 	 * synchronization source is an orphan. It shows offset zero and
343 	 * reference ID the loopback address.
344 	 */
345 	if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL &&
346 	    current_time > orphwait) {
347 		if (sys_leap == LEAP_NOTINSYNC) {
348 			sys_leap = LEAP_NOWARNING;
349 #ifdef AUTOKEY
350 			if (crypto_flags)
351 				crypto_update();
352 #endif	/* AUTOKEY */
353 		}
354 		sys_stratum = (u_char)sys_orphan;
355 		if (sys_stratum > 1)
356 			sys_refid = htonl(LOOPBACKADR);
357 		else
358 			memcpy(&sys_refid, "LOOP", 4);
359 		sys_offset = 0;
360 		sys_rootdelay = 0;
361 		sys_rootdisp = 0;
362 	}
363 
364 	get_systime(&now);
365 	time(&tnow);
366 
367 	/*
368 	 * Leapseconds. Get time and defer to worker if either something
369 	 * is imminent or every 8th second.
370 	 */
371 	if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7))
372 		check_leapsec(now.l_ui, &tnow,
373                                 (sys_leap == LEAP_NOTINSYNC));
374         if (sys_leap != LEAP_NOTINSYNC) {
375                 if (leapsec >= LSPROX_ANNOUNCE && leapdif) {
376 		        if (leapdif > 0)
377 			        sys_leap = LEAP_ADDSECOND;
378 		        else
379 			        sys_leap = LEAP_DELSECOND;
380                 } else {
381                         sys_leap = LEAP_NOWARNING;
382                 }
383 	}
384 
385 	/*
386 	 * Update huff-n'-puff filter.
387 	 */
388 	if (huffpuff_timer <= current_time) {
389 		huffpuff_timer += HUFFPUFF;
390 		huffpuff();
391 	}
392 
393 #ifdef AUTOKEY
394 	/*
395 	 * Garbage collect expired keys.
396 	 */
397 	if (keys_timer <= current_time) {
398 		keys_timer += 1 << sys_automax;
399 		auth_agekeys();
400 	}
401 
402 	/*
403 	 * Generate new private value. This causes all associations
404 	 * to regenerate cookies.
405 	 */
406 	if (revoke_timer && revoke_timer <= current_time) {
407 		revoke_timer += 1 << sys_revoke;
408 		RAND_bytes((u_char *)&sys_private, 4);
409 	}
410 #endif	/* AUTOKEY */
411 
412 	/*
413 	 * Interface update timer
414 	 */
415 	if (interface_interval && interface_timer <= current_time) {
416 		timer_interfacetimeout(current_time +
417 		    interface_interval);
418 		DPRINTF(2, ("timer: interface update\n"));
419 		interface_update(NULL, NULL);
420 	}
421 
422 	if (worker_idle_timer && worker_idle_timer <= current_time)
423 		worker_idle_timer_fired();
424 
425 	/*
426 	 * Finally, write hourly stats and do the hourly
427 	 * and daily leapfile checks.
428 	 */
429 	if (stats_timer <= current_time) {
430 		stats_timer += SECSPERHR;
431 		write_stats();
432 		if (sys_tai != 0 && leapsec_expired(now.l_ui, &tnow)) {
433 			int clf = check_leap_file();
434 
435 			/*
436 			** check_leap_file() returns -1 on a problem,
437 			** 0 on an expired leapsecond file, or the number
438 			** of days until the leapsecond file expires.
439 			**
440 			** We only want to log stuff once/day.
441 			*/
442 			if (check_leapfile < current_time) {
443 				check_leapfile += SECSPERDAY;
444 				if (-1 == clf) {
445 					/* nothing to do */
446 				} else if (0 == clf) {
447 					report_event(EVNT_LEAPVAL, NULL, NULL);
448 					msyslog(LOG_WARNING,
449 						"timer: leapseconds data file <%s> has expired!",
450 						leapseconds_file);
451 				} else if (clf < 31) {
452 					msyslog(LOG_WARNING,
453 						"timer: leapseconds data file <%s> will expire in less than %d days' time.", leapseconds_file, clf);
454 				}
455 			}
456 		}
457 	}
458 }
459 
460 
461 #ifndef SYS_WINNT
462 /*
463  * alarming - tell the world we've been alarmed
464  */
465 static RETSIGTYPE
466 alarming(
467 	int sig
468 	)
469 {
470 # ifdef DEBUG
471 	const char *msg = "alarming: initializing TRUE\n";
472 # endif
473 
474 	if (!initializing) {
475 		if (alarm_flag) {
476 			alarm_overflow++;
477 # ifdef DEBUG
478 			msg = "alarming: overflow\n";
479 # endif
480 		} else {
481 # ifndef VMS
482 			alarm_flag++;
483 # else
484 			/* VMS AST routine, increment is no good */
485 			alarm_flag = 1;
486 # endif
487 # ifdef DEBUG
488 			msg = "alarming: normal\n";
489 # endif
490 		}
491 	}
492 # ifdef VMS
493 	lib$addx(&vmsinc, &vmstimer, &vmstimer);
494 	sys$setimr(0, &vmstimer, alarming, alarming, 0);
495 # endif
496 # ifdef DEBUG
497 	if (debug >= 4)
498 		write(1, msg, strlen(msg));
499 # endif
500 }
501 #endif /* SYS_WINNT */
502 
503 
504 void
505 timer_interfacetimeout(u_long timeout)
506 {
507 	interface_timer = timeout;
508 }
509 
510 
511 /*
512  * timer_clr_stats - clear timer module stat counters
513  */
514 void
515 timer_clr_stats(void)
516 {
517 	timer_overflows = 0;
518 	timer_xmtcalls = 0;
519 	timer_timereset = current_time;
520 }
521 
522 static void
523 check_leapsec(
524 	u_int32        now  ,
525 	const time_t * tpiv ,
526         int/*BOOL*/    reset)
527 {
528 	leap_result_t lsdata;
529 	u_int32       lsprox;
530 
531 #ifndef SYS_WINNT  /* WinNT port has its own leap second handling */
532 # ifdef KERNEL_PLL
533 	leapsec_electric(pll_control && kern_enable);
534 # else
535 	leapsec_electric(0);
536 # endif
537 #endif
538 	if (reset)	{
539 		lsprox = LSPROX_NOWARN;
540 		leapsec_reset_frame();
541 		memset(&lsdata, 0, sizeof(lsdata));
542 	} else if (leapsec_query(&lsdata, now, tpiv)) {
543 		/* Full hit. Eventually step the clock, but always
544 		 * announce the leap event has happened.
545 		 */
546 		if (lsdata.warped < 0) {
547 			step_systime(lsdata.warped);
548 			msyslog(LOG_NOTICE, "Inserting positive leap second.");
549 		} else 	if (lsdata.warped > 0) {
550 			step_systime(lsdata.warped);
551 			msyslog(LOG_NOTICE, "Inserting negative leap second.");
552 		}
553 		report_event(EVNT_LEAP, NULL, NULL);
554 		lsprox  = LSPROX_NOWARN;
555 		leapsec = LSPROX_NOWARN;
556 		sys_tai = lsdata.tai_offs;
557 	} else {
558 		lsprox  = lsdata.proximity;
559 		sys_tai = lsdata.tai_offs;
560 	}
561 
562 	/* We guard against panic alarming during the red alert phase.
563 	 * Strange and evil things might happen if we go from stone cold
564 	 * to piping hot in one step. If things are already that wobbly,
565 	 * we let the normal clock correction take over, even if a jump
566 	 * is involved.
567          * Also make sure the alarming events are edge-triggered, that is,
568          * ceated only when the threshold is crossed.
569          */
570 	if (  (leapsec > 0 || lsprox < LSPROX_ALERT)
571 	    && leapsec < lsprox                     ) {
572 		if (  leapsec < LSPROX_SCHEDULE
573                    && lsprox >= LSPROX_SCHEDULE) {
574 			if (lsdata.dynamic)
575 				report_event(PEVNT_ARMED, sys_peer, NULL);
576 			else
577 				report_event(EVNT_ARMED, NULL, NULL);
578 		}
579 		leapsec = lsprox;
580 	}
581 	if (leapsec > lsprox) {
582 		if (  leapsec >= LSPROX_SCHEDULE
583                    && lsprox   < LSPROX_SCHEDULE) {
584 			report_event(EVNT_DISARMED, NULL, NULL);
585 		}
586 		leapsec = lsprox;
587 	}
588 
589         if (leapsec >= LSPROX_SCHEDULE)
590                 leapdif = lsdata.tai_diff;
591         else
592                 leapdif = 0;
593 }
594