ntp_timer.c revision 298699
1275970Scy/*
2275970Scy * ntp_timer.c - event timer support routines
3275970Scy */
4275970Scy#ifdef HAVE_CONFIG_H
5275970Scy# include <config.h>
6275970Scy#endif
7275970Scy
8275970Scy#include "ntp_machine.h"
9275970Scy#include "ntpd.h"
10275970Scy#include "ntp_stdlib.h"
11275970Scy#include "ntp_calendar.h"
12275970Scy#include "ntp_leapsec.h"
13275970Scy
14275970Scy#if defined(HAVE_IO_COMPLETION_PORT)
15275970Scy# include "ntp_iocompletionport.h"
16275970Scy# include "ntp_timer.h"
17275970Scy#endif
18275970Scy
19275970Scy#include <stdio.h>
20275970Scy#include <signal.h>
21275970Scy#ifdef HAVE_SYS_SIGNAL_H
22275970Scy# include <sys/signal.h>
23275970Scy#endif
24275970Scy#ifdef HAVE_UNISTD_H
25275970Scy# include <unistd.h>
26275970Scy#endif
27275970Scy
28275970Scy#ifdef KERNEL_PLL
29275970Scy#include "ntp_syscall.h"
30275970Scy#endif /* KERNEL_PLL */
31275970Scy
32275970Scy#ifdef AUTOKEY
33275970Scy#include <openssl/rand.h>
34275970Scy#endif	/* AUTOKEY */
35275970Scy
36275970Scy
37275970Scy/* TC_ERR represents the timer_create() error return value. */
38275970Scy#ifdef SYS_VXWORKS
39275970Scy#define	TC_ERR	ERROR
40275970Scy#else
41275970Scy#define	TC_ERR	(-1)
42275970Scy#endif
43275970Scy
44275970Scy
45275970Scystatic void check_leapsec(u_int32, const time_t*, int/*BOOL*/);
46275970Scy
47275970Scy/*
48275970Scy * These routines provide support for the event timer.  The timer is
49275970Scy * implemented by an interrupt routine which sets a flag once every
50275970Scy * second, and a timer routine which is called when the mainline code
51275970Scy * gets around to seeing the flag.  The timer routine dispatches the
52275970Scy * clock adjustment code if its time has come, then searches the timer
53275970Scy * queue for expiries which are dispatched to the transmit procedure.
54275970Scy * Finally, we call the hourly procedure to do cleanup and print a
55275970Scy * message.
56275970Scy */
57275970Scyvolatile int interface_interval;     /* init_io() sets def. 300s */
58275970Scy
59275970Scy/*
60275970Scy * Initializing flag.  All async routines watch this and only do their
61275970Scy * thing when it is clear.
62275970Scy */
63275970Scyint initializing;
64275970Scy
65275970Scy/*
66275970Scy * Alarm flag. The mainline code imports this.
67275970Scy */
68275970Scyvolatile int alarm_flag;
69275970Scy
70275970Scy/*
71275970Scy * The counters and timeouts
72275970Scy */
73275970Scystatic  u_long interface_timer;	/* interface update timer */
74275970Scystatic	u_long adjust_timer;	/* second timer */
75275970Scystatic	u_long stats_timer;	/* stats timer */
76275970Scystatic	u_long leapf_timer;	/* Report leapfile problems once/day */
77275970Scystatic	u_long huffpuff_timer;	/* huff-n'-puff timer */
78275970Scystatic	u_long worker_idle_timer;/* next check for idle intres */
79275970Scyu_long	leapsec;	        /* seconds to next leap (proximity class) */
80275970Scyint     leapdif;                /* TAI difference step at next leap second*/
81275970Scyu_long	orphwait; 		/* orphan wait time */
82275970Scy#ifdef AUTOKEY
83275970Scystatic	u_long revoke_timer;	/* keys revoke timer */
84275970Scystatic	u_long keys_timer;	/* session key timer */
85275970Scyu_long	sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
86275970Scyu_long	sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
87275970Scy#endif	/* AUTOKEY */
88275970Scy
89275970Scy/*
90275970Scy * Statistics counter for the interested.
91275970Scy */
92275970Scyvolatile u_long alarm_overflow;
93275970Scy
94275970Scyu_long current_time;		/* seconds since startup */
95275970Scy
96275970Scy/*
97275970Scy * Stats.  Number of overflows and number of calls to transmit().
98275970Scy */
99275970Scyu_long timer_timereset;
100275970Scyu_long timer_overflows;
101275970Scyu_long timer_xmtcalls;
102275970Scy
103275970Scy#if defined(VMS)
104275970Scystatic int vmstimer[2]; 	/* time for next timer AST */
105275970Scystatic int vmsinc[2];		/* timer increment */
106275970Scy#endif /* VMS */
107275970Scy
108275970Scy#ifdef SYS_WINNT
109275970ScyHANDLE WaitableTimerHandle;
110275970Scy#else
111275970Scystatic	RETSIGTYPE alarming (int);
112275970Scy#endif /* SYS_WINNT */
113275970Scy
114275970Scy#if !defined(VMS)
115275970Scy# if !defined SYS_WINNT || defined(SYS_CYGWIN32)
116275970Scy#  ifdef HAVE_TIMER_CREATE
117275970Scystatic timer_t timer_id;
118275970Scytypedef struct itimerspec intervaltimer;
119275970Scy#   define	itv_frac	tv_nsec
120275970Scy#  else
121275970Scytypedef struct itimerval intervaltimer;
122275970Scy#   define	itv_frac	tv_usec
123275970Scy#  endif
124275970Scyintervaltimer itimer;
125275970Scy# endif
126275970Scy#endif
127275970Scy
128275970Scy#if !defined(SYS_WINNT) && !defined(VMS)
129275970Scyvoid	set_timer_or_die(const intervaltimer *);
130275970Scy#endif
131275970Scy
132275970Scy
133275970Scy#if !defined(SYS_WINNT) && !defined(VMS)
134275970Scyvoid
135275970Scyset_timer_or_die(
136275970Scy	const intervaltimer *	ptimer
137275970Scy	)
138275970Scy{
139275970Scy	const char *	setfunc;
140275970Scy	int		rc;
141275970Scy
142275970Scy# ifdef HAVE_TIMER_CREATE
143275970Scy	setfunc = "timer_settime";
144275970Scy	rc = timer_settime(timer_id, 0, &itimer, NULL);
145275970Scy# else
146275970Scy	setfunc = "setitimer";
147275970Scy	rc = setitimer(ITIMER_REAL, &itimer, NULL);
148275970Scy# endif
149275970Scy	if (-1 == rc) {
150275970Scy		msyslog(LOG_ERR, "interval timer %s failed, %m",
151275970Scy			setfunc);
152275970Scy		exit(1);
153275970Scy	}
154275970Scy}
155275970Scy#endif	/* !SYS_WINNT && !VMS */
156275970Scy
157275970Scy
158275970Scy/*
159275970Scy * reinit_timer - reinitialize interval timer after a clock step.
160275970Scy */
161275970Scyvoid
162275970Scyreinit_timer(void)
163275970Scy{
164275970Scy#if !defined(SYS_WINNT) && !defined(VMS)
165275970Scy	ZERO(itimer);
166275970Scy# ifdef HAVE_TIMER_CREATE
167275970Scy	timer_gettime(timer_id, &itimer);
168275970Scy# else
169275970Scy	getitimer(ITIMER_REAL, &itimer);
170275970Scy# endif
171275970Scy	if (itimer.it_value.tv_sec < 0 ||
172275970Scy	    itimer.it_value.tv_sec > (1 << EVENT_TIMEOUT))
173275970Scy		itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
174275970Scy	if (itimer.it_value.itv_frac < 0)
175275970Scy		itimer.it_value.itv_frac = 0;
176275970Scy	if (0 == itimer.it_value.tv_sec &&
177275970Scy	    0 == itimer.it_value.itv_frac)
178275970Scy		itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
179275970Scy	itimer.it_interval.tv_sec = (1 << EVENT_TIMEOUT);
180275970Scy	itimer.it_interval.itv_frac = 0;
181275970Scy	set_timer_or_die(&itimer);
182275970Scy# endif /* VMS */
183275970Scy}
184275970Scy
185275970Scy
186275970Scy/*
187275970Scy * init_timer - initialize the timer data structures
188275970Scy */
189275970Scyvoid
190275970Scyinit_timer(void)
191275970Scy{
192275970Scy	/*
193275970Scy	 * Initialize...
194275970Scy	 */
195275970Scy	alarm_flag = FALSE;
196275970Scy	alarm_overflow = 0;
197275970Scy	adjust_timer = 1;
198275970Scy	stats_timer = SECSPERHR;
199275970Scy	leapf_timer = SECSPERDAY;
200275970Scy	huffpuff_timer = 0;
201275970Scy	interface_timer = 0;
202275970Scy	current_time = 0;
203275970Scy	timer_overflows = 0;
204275970Scy	timer_xmtcalls = 0;
205275970Scy	timer_timereset = 0;
206275970Scy
207275970Scy#ifndef SYS_WINNT
208275970Scy	/*
209275970Scy	 * Set up the alarm interrupt.	The first comes 2**EVENT_TIMEOUT
210275970Scy	 * seconds from now and they continue on every 2**EVENT_TIMEOUT
211275970Scy	 * seconds.
212275970Scy	 */
213275970Scy# ifndef VMS
214275970Scy#  ifdef HAVE_TIMER_CREATE
215275970Scy	if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) {
216275970Scy		msyslog(LOG_ERR, "timer_create failed, %m");
217275970Scy		exit(1);
218275970Scy	}
219275970Scy#  endif
220275970Scy	signal_no_reset(SIGALRM, alarming);
221275970Scy	itimer.it_interval.tv_sec =
222275970Scy		itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
223275970Scy	itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0;
224275970Scy	set_timer_or_die(&itimer);
225275970Scy# else	/* VMS follows */
226275970Scy	vmsinc[0] = 10000000;		/* 1 sec */
227275970Scy	vmsinc[1] = 0;
228275970Scy	lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
229275970Scy
230275970Scy	sys$gettim(&vmstimer);	/* that's "now" as abstime */
231275970Scy
232275970Scy	lib$addx(&vmsinc, &vmstimer, &vmstimer);
233275970Scy	sys$setimr(0, &vmstimer, alarming, alarming, 0);
234275970Scy# endif	/* VMS */
235275970Scy#else	/* SYS_WINNT follows */
236275970Scy	/*
237275970Scy	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
238275970Scy	 * Under Windows/NT,
239275970Scy	 */
240275970Scy
241275970Scy	WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
242275970Scy	if (WaitableTimerHandle == NULL) {
243275970Scy		msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
244275970Scy		exit(1);
245275970Scy	}
246275970Scy	else {
247275970Scy		DWORD		Period;
248275970Scy		LARGE_INTEGER	DueTime;
249275970Scy		BOOL		rc;
250275970Scy
251275970Scy		Period = (1 << EVENT_TIMEOUT) * 1000;
252275970Scy		DueTime.QuadPart = Period * 10000i64;
253275970Scy		rc = SetWaitableTimer(WaitableTimerHandle, &DueTime,
254275970Scy				      Period, NULL, NULL, FALSE);
255275970Scy		if (!rc) {
256275970Scy			msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
257275970Scy			exit(1);
258275970Scy		}
259275970Scy	}
260275970Scy
261275970Scy#endif	/* SYS_WINNT */
262275970Scy}
263275970Scy
264275970Scy
265275970Scy/*
266275970Scy * intres_timeout_req(s) is invoked in the parent to schedule an idle
267275970Scy * timeout to fire in s seconds, if not reset earlier by a call to
268275970Scy * intres_timeout_req(0), which clears any pending timeout.  When the
269275970Scy * timeout expires, worker_idle_timer_fired() is invoked (again, in the
270275970Scy * parent).
271275970Scy *
272275970Scy * sntp and ntpd each provide implementations adapted to their timers.
273275970Scy */
274275970Scyvoid
275275970Scyintres_timeout_req(
276275970Scy	u_int	seconds		/* 0 cancels */
277275970Scy	)
278275970Scy{
279275970Scy#if defined(HAVE_DROPROOT) && defined(NEED_EARLY_FORK)
280275970Scy	if (droproot) {
281275970Scy		worker_idle_timer = 0;
282275970Scy		return;
283275970Scy	}
284275970Scy#endif
285275970Scy	if (0 == seconds) {
286275970Scy		worker_idle_timer = 0;
287275970Scy		return;
288275970Scy	}
289275970Scy	worker_idle_timer = current_time + seconds;
290275970Scy}
291275970Scy
292275970Scy
293275970Scy/*
294275970Scy * timer - event timer
295275970Scy */
296275970Scyvoid
297275970Scytimer(void)
298275970Scy{
299275970Scy	struct peer *	p;
300275970Scy	struct peer *	next_peer;
301275970Scy	l_fp		now;
302275970Scy	time_t          tnow;
303275970Scy
304275970Scy	/*
305275970Scy	 * The basic timerevent is one second.  This is used to adjust the
306275970Scy	 * system clock in time and frequency, implement the kiss-o'-death
307275970Scy	 * function and the association polling function.
308275970Scy	 */
309275970Scy	current_time++;
310275970Scy	if (adjust_timer <= current_time) {
311275970Scy		adjust_timer += 1;
312275970Scy		adj_host_clock();
313275970Scy#ifdef REFCLOCK
314275970Scy		for (p = peer_list; p != NULL; p = next_peer) {
315275970Scy			next_peer = p->p_link;
316275970Scy			if (FLAG_REFCLOCK & p->flags)
317275970Scy				refclock_timer(p);
318275970Scy		}
319275970Scy#endif /* REFCLOCK */
320275970Scy	}
321275970Scy
322275970Scy	/*
323275970Scy	 * Now dispatch any peers whose event timer has expired. Be
324275970Scy	 * careful here, since the peer structure might go away as the
325275970Scy	 * result of the call.
326275970Scy	 */
327275970Scy	for (p = peer_list; p != NULL; p = next_peer) {
328275970Scy		next_peer = p->p_link;
329275970Scy
330275970Scy		/*
331275970Scy		 * Restrain the non-burst packet rate not more
332275970Scy		 * than one packet every 16 seconds. This is
333275970Scy		 * usually tripped using iburst and minpoll of
334275970Scy		 * 128 s or less.
335275970Scy		 */
336275970Scy		if (p->throttle > 0)
337275970Scy			p->throttle--;
338275970Scy		if (p->nextdate <= current_time) {
339275970Scy#ifdef REFCLOCK
340275970Scy			if (FLAG_REFCLOCK & p->flags)
341275970Scy				refclock_transmit(p);
342275970Scy			else
343275970Scy#endif	/* REFCLOCK */
344275970Scy				transmit(p);
345275970Scy		}
346275970Scy	}
347275970Scy
348275970Scy	/*
349275970Scy	 * Orphan mode is active when enabled and when no servers less
350275970Scy	 * than the orphan stratum are available. A server with no other
351275970Scy	 * synchronization source is an orphan. It shows offset zero and
352275970Scy	 * reference ID the loopback address.
353275970Scy	 */
354275970Scy	if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL &&
355275970Scy	    current_time > orphwait) {
356275970Scy		if (sys_leap == LEAP_NOTINSYNC) {
357275970Scy			set_sys_leap(LEAP_NOWARNING);
358275970Scy#ifdef AUTOKEY
359275970Scy			if (crypto_flags)
360275970Scy				crypto_update();
361275970Scy#endif	/* AUTOKEY */
362275970Scy		}
363275970Scy		sys_stratum = (u_char)sys_orphan;
364275970Scy		if (sys_stratum > 1)
365275970Scy			sys_refid = htonl(LOOPBACKADR);
366275970Scy		else
367275970Scy			memcpy(&sys_refid, "LOOP", 4);
368275970Scy		sys_offset = 0;
369275970Scy		sys_rootdelay = 0;
370275970Scy		sys_rootdisp = 0;
371275970Scy	}
372275970Scy
373275970Scy	get_systime(&now);
374275970Scy	time(&tnow);
375275970Scy
376275970Scy	/*
377275970Scy	 * Leapseconds. Get time and defer to worker if either something
378275970Scy	 * is imminent or every 8th second.
379275970Scy	 */
380275970Scy	if (leapsec > LSPROX_NOWARN || 0 == (current_time & 7))
381275970Scy		check_leapsec(now.l_ui, &tnow,
382275970Scy                                (sys_leap == LEAP_NOTINSYNC));
383275970Scy        if (sys_leap != LEAP_NOTINSYNC) {
384275970Scy                if (leapsec >= LSPROX_ANNOUNCE && leapdif) {
385275970Scy		        if (leapdif > 0)
386275970Scy			        set_sys_leap(LEAP_ADDSECOND);
387275970Scy		        else
388275970Scy			        set_sys_leap(LEAP_DELSECOND);
389275970Scy                } else {
390275970Scy                        set_sys_leap(LEAP_NOWARNING);
391275970Scy                }
392275970Scy	}
393275970Scy
394275970Scy	/*
395275970Scy	 * Update huff-n'-puff filter.
396275970Scy	 */
397275970Scy	if (huffpuff_timer <= current_time) {
398275970Scy		huffpuff_timer += HUFFPUFF;
399275970Scy		huffpuff();
400275970Scy	}
401275970Scy
402275970Scy#ifdef AUTOKEY
403275970Scy	/*
404275970Scy	 * Garbage collect expired keys.
405275970Scy	 */
406275970Scy	if (keys_timer <= current_time) {
407275970Scy		keys_timer += 1 << sys_automax;
408275970Scy		auth_agekeys();
409275970Scy	}
410275970Scy
411275970Scy	/*
412275970Scy	 * Generate new private value. This causes all associations
413275970Scy	 * to regenerate cookies.
414275970Scy	 */
415275970Scy	if (revoke_timer && revoke_timer <= current_time) {
416275970Scy		revoke_timer += 1 << sys_revoke;
417275970Scy		RAND_bytes((u_char *)&sys_private, 4);
418275970Scy	}
419275970Scy#endif	/* AUTOKEY */
420275970Scy
421275970Scy	/*
422275970Scy	 * Interface update timer
423275970Scy	 */
424275970Scy	if (interface_interval && interface_timer <= current_time) {
425275970Scy		timer_interfacetimeout(current_time +
426275970Scy		    interface_interval);
427275970Scy		DPRINTF(2, ("timer: interface update\n"));
428275970Scy		interface_update(NULL, NULL);
429275970Scy	}
430275970Scy
431275970Scy	if (worker_idle_timer && worker_idle_timer <= current_time)
432275970Scy		worker_idle_timer_fired();
433275970Scy
434275970Scy	/*
435275970Scy	 * Finally, write hourly stats and do the hourly
436275970Scy	 * and daily leapfile checks.
437275970Scy	 */
438275970Scy	if (stats_timer <= current_time) {
439275970Scy		stats_timer += SECSPERHR;
440275970Scy		write_stats();
441275970Scy		if (leapf_timer <= current_time) {
442275970Scy			leapf_timer += SECSPERDAY;
443275970Scy			check_leap_file(TRUE, now.l_ui, &tnow);
444275970Scy		} else {
445275970Scy			check_leap_file(FALSE, now.l_ui, &tnow);
446275970Scy		}
447275970Scy	}
448275970Scy}
449275970Scy
450275970Scy
451275970Scy#ifndef SYS_WINNT
452275970Scy/*
453275970Scy * alarming - tell the world we've been alarmed
454275970Scy */
455275970Scystatic RETSIGTYPE
456275970Scyalarming(
457275970Scy	int sig
458275970Scy	)
459275970Scy{
460275970Scy# ifdef DEBUG
461275970Scy	const char *msg = "alarming: initializing TRUE\n";
462275970Scy# endif
463275970Scy
464275970Scy	if (!initializing) {
465275970Scy		if (alarm_flag) {
466275970Scy			alarm_overflow++;
467275970Scy# ifdef DEBUG
468275970Scy			msg = "alarming: overflow\n";
469275970Scy# endif
470275970Scy		} else {
471275970Scy# ifndef VMS
472275970Scy			alarm_flag++;
473275970Scy# else
474275970Scy			/* VMS AST routine, increment is no good */
475275970Scy			alarm_flag = 1;
476275970Scy# endif
477275970Scy# ifdef DEBUG
478275970Scy			msg = "alarming: normal\n";
479275970Scy# endif
480275970Scy		}
481275970Scy	}
482275970Scy# ifdef VMS
483275970Scy	lib$addx(&vmsinc, &vmstimer, &vmstimer);
484275970Scy	sys$setimr(0, &vmstimer, alarming, alarming, 0);
485275970Scy# endif
486275970Scy# ifdef DEBUG
487275970Scy	if (debug >= 4)
488275970Scy		(void)(-1 == write(1, msg, strlen(msg)));
489275970Scy# endif
490275970Scy}
491275970Scy#endif /* SYS_WINNT */
492275970Scy
493275970Scy
494275970Scyvoid
495275970Scytimer_interfacetimeout(u_long timeout)
496275970Scy{
497275970Scy	interface_timer = timeout;
498275970Scy}
499275970Scy
500275970Scy
501275970Scy/*
502275970Scy * timer_clr_stats - clear timer module stat counters
503275970Scy */
504275970Scyvoid
505275970Scytimer_clr_stats(void)
506275970Scy{
507275970Scy	timer_overflows = 0;
508275970Scy	timer_xmtcalls = 0;
509275970Scy	timer_timereset = current_time;
510275970Scy}
511275970Scy
512275970Scy
513275970Scystatic void
514275970Scycheck_leap_sec_in_progress( const leap_result_t *lsdata ) {
515275970Scy	int prv_leap_sec_in_progress = leap_sec_in_progress;
516275970Scy	leap_sec_in_progress = lsdata->tai_diff && (lsdata->ddist < 3);
517275970Scy
518275970Scy	/* if changed we may have to update the leap status sent to clients */
519275970Scy	if (leap_sec_in_progress != prv_leap_sec_in_progress)
520275970Scy		set_sys_leap(sys_leap);
521275970Scy}
522275970Scy
523275970Scy
524275970Scystatic void
525275970Scycheck_leapsec(
526275970Scy	u_int32        now  ,
527275970Scy	const time_t * tpiv ,
528275970Scy        int/*BOOL*/    reset)
529275970Scy{
530275970Scy	static const char leapmsg_p_step[] =
531275970Scy	    "Positive leap second, stepped backward.";
532285612Sdelphij	static const char leapmsg_p_slew[] =
533275970Scy	    "Positive leap second, no step correction. "
534275970Scy	    "System clock will be inaccurate for a long time.";
535275970Scy
536275970Scy	static const char leapmsg_n_step[] =
537275970Scy	    "Negative leap second, stepped forward.";
538285612Sdelphij	static const char leapmsg_n_slew[] =
539275970Scy	    "Negative leap second, no step correction. "
540275970Scy	    "System clock will be inaccurate for a long time.";
541275970Scy
542275970Scy	leap_result_t lsdata;
543285612Sdelphij	u_int32       lsprox;
544285612Sdelphij#ifdef AUTOKEY
545285612Sdelphij	int/*BOOL*/   update_autokey = FALSE;
546275970Scy#endif
547275970Scy
548275970Scy#ifndef SYS_WINNT  /* WinNT port has its own leap second handling */
549275970Scy# ifdef KERNEL_PLL
550275970Scy	leapsec_electric(pll_control && kern_enable);
551275970Scy# else
552275970Scy	leapsec_electric(0);
553275970Scy# endif
554275970Scy#endif
555275970Scy#ifdef LEAP_SMEAR
556275970Scy	leap_smear.enabled = leap_smear_intv != 0;
557275970Scy#endif
558275970Scy	if (reset) {
559275970Scy		lsprox = LSPROX_NOWARN;
560275970Scy		leapsec_reset_frame();
561275970Scy		memset(&lsdata, 0, sizeof(lsdata));
562275970Scy	} else {
563275970Scy	  int fired;
564275970Scy
565275970Scy	  fired = leapsec_query(&lsdata, now, tpiv);
566275970Scy
567275970Scy	  DPRINTF(3, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n",
568275970Scy		  fired, now, now, lsdata.tai_diff, lsdata.ddist));
569275970Scy
570275970Scy#ifdef LEAP_SMEAR
571275970Scy	  leap_smear.in_progress = 0;
572275970Scy	  leap_smear.doffset = 0.0;
573275970Scy
574275970Scy	  if (leap_smear.enabled) {
575275970Scy		if (lsdata.tai_diff) {
576275970Scy			if (leap_smear.interval == 0) {
577275970Scy				leap_smear.interval = leap_smear_intv;
578275970Scy				leap_smear.intv_end = lsdata.ttime.Q_s;
579275970Scy				leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval;
580275970Scy				DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n",
581275970Scy					leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end));
582275970Scy			}
583275970Scy		} else {
584275970Scy			if (leap_smear.interval)
585275970Scy				DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n"));
586275970Scy			leap_smear.interval = 0;
587275970Scy		}
588275970Scy
589275970Scy		if (leap_smear.interval) {
590275970Scy			double dtemp = now;
591275970Scy			if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) {
592275970Scy				double leap_smear_time = dtemp - leap_smear.intv_start;
593275970Scy				/*
594275970Scy				 * For now we just do a linear interpolation over the smear interval
595275970Scy				 */
596275970Scy#if 0
597275970Scy				// linear interpolation
598275970Scy				leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval);
599275970Scy#else
600275970Scy				// Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0
601275970Scy				leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0;
602275970Scy#endif
603275970Scy				/*
604275970Scy				 * TODO see if we're inside an inserted leap second, so we need to compute
605275970Scy				 * leap_smear.doffset = 1.0 - leap_smear.doffset
606275970Scy				 */
607275970Scy				leap_smear.in_progress = 1;
608275970Scy#if 0 && defined( DEBUG )
609275970Scy				msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n",
610275970Scy					leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval,
611275970Scy					now, leap_smear_time, leap_smear.doffset);
612275970Scy#else
613275970Scy				DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n",
614275970Scy					leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval,
615275970Scy					now, leap_smear_time, leap_smear.doffset));
616275970Scy#endif
617275970Scy
618275970Scy			}
619275970Scy		}
620275970Scy	  }
621275970Scy	  else
622275970Scy		leap_smear.interval = 0;
623275970Scy
624275970Scy	  /*
625275970Scy	   * Update the current leap smear offset, eventually 0.0 if outside smear interval.
626275970Scy	   */
627275970Scy	  DTOLFP(leap_smear.doffset, &leap_smear.offset);
628275970Scy
629275970Scy#endif	/* LEAP_SMEAR */
630275970Scy
631275970Scy	  if (fired) {
632275970Scy		/* Full hit. Eventually step the clock, but always
633275970Scy		 * announce the leap event has happened.
634275970Scy		 */
635275970Scy		const char *leapmsg = NULL;
636275970Scy		double      lswarp  = lsdata.warped;
637275970Scy		if (lswarp < 0.0) {
638275970Scy			if (clock_max_back > 0.0 &&
639275970Scy			    clock_max_back < -lswarp) {
640275970Scy				step_systime(lswarp);
641275970Scy				leapmsg = leapmsg_p_step;
642275970Scy			} else {
643275970Scy				leapmsg = leapmsg_p_slew;
644275970Scy			}
645275970Scy		} else 	if (lswarp > 0.0) {
646275970Scy			if (clock_max_fwd > 0.0 &&
647275970Scy			    clock_max_fwd < lswarp) {
648275970Scy				step_systime(lswarp);
649275970Scy				leapmsg = leapmsg_n_step;
650275970Scy			} else {
651275970Scy				leapmsg = leapmsg_n_slew;
652275970Scy			}
653275970Scy		}
654275970Scy		if (leapmsg)
655275970Scy			msyslog(LOG_NOTICE, "%s", leapmsg);
656275970Scy		report_event(EVNT_LEAP, NULL, NULL);
657275970Scy#ifdef AUTOKEY
658275970Scy		update_autokey = TRUE;
659275970Scy#endif
660275970Scy		lsprox  = LSPROX_NOWARN;
661275970Scy		leapsec = LSPROX_NOWARN;
662275970Scy		sys_tai = lsdata.tai_offs;
663275970Scy	  } else {
664275970Scy#ifdef AUTOKEY
665275970Scy		  update_autokey = (sys_tai != (u_int)lsdata.tai_offs);
666275970Scy#endif
667275970Scy		  lsprox  = lsdata.proximity;
668275970Scy		  sys_tai = lsdata.tai_offs;
669275970Scy	  }
670275970Scy	}
671275970Scy
672275970Scy	/* We guard against panic alarming during the red alert phase.
673275970Scy	 * Strange and evil things might happen if we go from stone cold
674275970Scy	 * to piping hot in one step. If things are already that wobbly,
675275970Scy	 * we let the normal clock correction take over, even if a jump
676275970Scy	 * is involved.
677275970Scy         * Also make sure the alarming events are edge-triggered, that is,
678275970Scy         * ceated only when the threshold is crossed.
679275970Scy         */
680275970Scy	if (  (leapsec > 0 || lsprox < LSPROX_ALERT)
681275970Scy	    && leapsec < lsprox                     ) {
682275970Scy		if (  leapsec < LSPROX_SCHEDULE
683275970Scy                   && lsprox >= LSPROX_SCHEDULE) {
684275970Scy			if (lsdata.dynamic)
685275970Scy				report_event(PEVNT_ARMED, sys_peer, NULL);
686275970Scy			else
687275970Scy				report_event(EVNT_ARMED, NULL, NULL);
688275970Scy		}
689275970Scy		leapsec = lsprox;
690275970Scy	}
691275970Scy	if (leapsec > lsprox) {
692275970Scy		if (  leapsec >= LSPROX_SCHEDULE
693275970Scy                   && lsprox   < LSPROX_SCHEDULE) {
694275970Scy			report_event(EVNT_DISARMED, NULL, NULL);
695275970Scy		}
696275970Scy		leapsec = lsprox;
697275970Scy	}
698275970Scy
699275970Scy	if (leapsec >= LSPROX_SCHEDULE)
700275970Scy		leapdif = lsdata.tai_diff;
701275970Scy	else
702275970Scy		leapdif = 0;
703275970Scy
704275970Scy	check_leap_sec_in_progress(&lsdata);
705275970Scy
706275970Scy#ifdef AUTOKEY
707275970Scy	if (update_autokey)
708275970Scy		crypto_update_taichange();
709275970Scy#endif
710275970Scy}
711275970Scy