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