154359Sroberto/*
254359Sroberto * ntp_timer.c - event timer support routines
354359Sroberto */
454359Sroberto#ifdef HAVE_CONFIG_H
554359Sroberto# include <config.h>
654359Sroberto#endif
754359Sroberto
882498Sroberto#include "ntp_machine.h"
982498Sroberto#include "ntpd.h"
1082498Sroberto#include "ntp_stdlib.h"
1182498Sroberto
1254359Sroberto#include <stdio.h>
1354359Sroberto#include <signal.h>
14106163Sroberto#ifdef HAVE_SYS_SIGNAL_H
15106163Sroberto# include <sys/signal.h>
16106163Sroberto#endif
1782498Sroberto#ifdef HAVE_UNISTD_H
1882498Sroberto# include <unistd.h>
1982498Sroberto#endif
2054359Sroberto
2154359Sroberto#if defined(HAVE_IO_COMPLETION_PORT)
2254359Sroberto# include "ntp_iocompletionport.h"
2354359Sroberto# include "ntp_timer.h"
2454359Sroberto#endif
2554359Sroberto
2654359Sroberto/*
2754359Sroberto * These routines provide support for the event timer.	The timer is
2854359Sroberto * implemented by an interrupt routine which sets a flag once every
2954359Sroberto * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
3054359Sroberto * is called when the mainline code gets around to seeing the flag.
3154359Sroberto * The timer routine dispatches the clock adjustment code if its time
3254359Sroberto * has come, then searches the timer queue for expiries which are
3354359Sroberto * dispatched to the transmit procedure.  Finally, we call the hourly
3454359Sroberto * procedure to do cleanup and print a message.
3554359Sroberto */
3654359Sroberto
37182007Srobertovolatile int interface_interval = 300;     /* update interface every 5 minutes as default */
38182007Sroberto
3954359Sroberto/*
4054359Sroberto * Alarm flag.	The mainline code imports this.
4154359Sroberto */
4254359Srobertovolatile int alarm_flag;
4354359Sroberto
4454359Sroberto/*
4554359Sroberto * The counters
4654359Sroberto */
4754359Srobertostatic	u_long adjust_timer;		/* second timer */
4854359Srobertostatic	u_long keys_timer;		/* minute timer */
49182007Srobertostatic	u_long stats_timer;		/* stats timer */
5082498Srobertostatic	u_long huffpuff_timer;		/* huff-n'-puff timer */
51182007Srobertostatic  u_long interface_timer;	        /* interface update timer */
52132451Sroberto#ifdef OPENSSL
5354359Srobertostatic	u_long revoke_timer;		/* keys revoke timer */
54132451Srobertou_char	sys_revoke = KEY_REVOKE;	/* keys revoke timeout (log2 s) */
55132451Sroberto#endif /* OPENSSL */
5654359Sroberto
5754359Sroberto/*
5854359Sroberto * Statistics counter for the interested.
5954359Sroberto */
6054359Srobertovolatile u_long alarm_overflow;
6154359Sroberto
6254359Sroberto#define MINUTE	60
6354359Sroberto#define HOUR	(60*60)
6454359Sroberto
6554359Srobertou_long current_time;
6654359Sroberto
6754359Sroberto/*
6854359Sroberto * Stats.  Number of overflows and number of calls to transmit().
6954359Sroberto */
7054359Srobertou_long timer_timereset;
7154359Srobertou_long timer_overflows;
7254359Srobertou_long timer_xmtcalls;
7354359Sroberto
7454359Sroberto#if defined(VMS)
7554359Srobertostatic int vmstimer[2]; 	/* time for next timer AST */
7654359Srobertostatic int vmsinc[2];		/* timer increment */
7754359Sroberto#endif /* VMS */
7854359Sroberto
7954359Sroberto#if defined SYS_WINNT
8054359Srobertostatic HANDLE WaitableTimerHandle = NULL;
8154359Sroberto#else
8254359Srobertostatic	RETSIGTYPE alarming P((int));
8354359Sroberto#endif /* SYS_WINNT */
8454359Sroberto
85132451Sroberto#if !defined(VMS)
86132451Sroberto# if !defined SYS_WINNT || defined(SYS_CYGWIN32)
87132451Sroberto#  ifndef HAVE_TIMER_SETTIME
88132451Sroberto	struct itimerval itimer;
89132451Sroberto#  else
90132451Sroberto	static timer_t ntpd_timerid;
91132451Sroberto	struct itimerspec itimer;
92132451Sroberto#  endif /* HAVE_TIMER_SETTIME */
93132451Sroberto# endif /* SYS_WINNT */
94132451Sroberto#endif /* VMS */
9554359Sroberto
9654359Sroberto/*
97132451Sroberto * reinit_timer - reinitialize interval timer.
98132451Sroberto */
99132451Srobertovoid
100132451Srobertoreinit_timer(void)
101132451Sroberto{
102132451Sroberto#if !defined(SYS_WINNT) && !defined(VMS)
103132451Sroberto#  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
104132451Sroberto	timer_gettime(ntpd_timerid, &itimer);
105132451Sroberto	if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
106132451Sroberto		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
107132451Sroberto	}
108132451Sroberto	if (itimer.it_value.tv_nsec < 0 ) {
109132451Sroberto		itimer.it_value.tv_nsec = 0;
110132451Sroberto	}
111132451Sroberto	if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
112132451Sroberto		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
113132451Sroberto		itimer.it_value.tv_nsec = 0;
114132451Sroberto	}
115132451Sroberto	itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
116132451Sroberto	itimer.it_interval.tv_nsec = 0;
117132451Sroberto	timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
118132451Sroberto#  else
119132451Sroberto	getitimer(ITIMER_REAL, &itimer);
120132451Sroberto	if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
121132451Sroberto		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
122132451Sroberto	}
123132451Sroberto	if (itimer.it_value.tv_usec < 0 ) {
124132451Sroberto		itimer.it_value.tv_usec = 0;
125132451Sroberto	}
126132451Sroberto	if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
127132451Sroberto		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
128132451Sroberto		itimer.it_value.tv_usec = 0;
129132451Sroberto	}
130132451Sroberto	itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
131132451Sroberto	itimer.it_interval.tv_usec = 0;
132132451Sroberto	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
133132451Sroberto#  endif
134132451Sroberto# endif /* VMS */
135132451Sroberto}
136132451Sroberto
137132451Sroberto/*
13854359Sroberto * init_timer - initialize the timer data structures
13954359Sroberto */
14054359Srobertovoid
14154359Srobertoinit_timer(void)
14254359Sroberto{
143132451Sroberto# if defined SYS_WINNT & !defined(SYS_CYGWIN32)
144182007Sroberto	HANDLE hToken = INVALID_HANDLE_VALUE;
14554359Sroberto	TOKEN_PRIVILEGES tkp;
14654359Sroberto# endif /* SYS_WINNT */
14754359Sroberto
14854359Sroberto	/*
14954359Sroberto	 * Initialize...
15054359Sroberto	 */
15154359Sroberto	alarm_flag = 0;
15254359Sroberto	alarm_overflow = 0;
15354359Sroberto	adjust_timer = 1;
154182007Sroberto	stats_timer = 0;
15582498Sroberto	huffpuff_timer = 0;
156182007Sroberto	interface_timer = 0;
15754359Sroberto	current_time = 0;
15854359Sroberto	timer_overflows = 0;
15954359Sroberto	timer_xmtcalls = 0;
16054359Sroberto	timer_timereset = 0;
16154359Sroberto
16254359Sroberto#if !defined(SYS_WINNT)
16354359Sroberto	/*
16454359Sroberto	 * Set up the alarm interrupt.	The first comes 2**EVENT_TIMEOUT
16554359Sroberto	 * seconds from now and they continue on every 2**EVENT_TIMEOUT
16654359Sroberto	 * seconds.
16754359Sroberto	 */
16854359Sroberto# if !defined(VMS)
16954359Sroberto#  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
17054359Sroberto	if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
17154359Sroberto#	ifdef SYS_VXWORKS
17254359Sroberto		ERROR
17354359Sroberto#	else
17454359Sroberto		-1
17554359Sroberto#	endif
17654359Sroberto	   )
17754359Sroberto	{
17854359Sroberto		fprintf (stderr, "timer create FAILED\n");
17954359Sroberto		exit (0);
18054359Sroberto	}
18154359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
18254359Sroberto	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
18354359Sroberto	itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
18454359Sroberto	timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
18554359Sroberto#  else
18654359Sroberto	(void) signal_no_reset(SIGALRM, alarming);
18754359Sroberto	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
18854359Sroberto	itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
18954359Sroberto	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
19054359Sroberto#  endif
19154359Sroberto# else /* VMS */
19254359Sroberto	vmsinc[0] = 10000000;		/* 1 sec */
19354359Sroberto	vmsinc[1] = 0;
19454359Sroberto	lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
19554359Sroberto
19654359Sroberto	sys$gettim(&vmstimer);	/* that's "now" as abstime */
19754359Sroberto
19854359Sroberto	lib$addx(&vmsinc, &vmstimer, &vmstimer);
19954359Sroberto	sys$setimr(0, &vmstimer, alarming, alarming, 0);
20054359Sroberto# endif /* VMS */
20154359Sroberto#else /* SYS_WINNT */
20254359Sroberto	_tzset();
20354359Sroberto
20454359Sroberto	/*
20554359Sroberto	 * Get privileges needed for fiddling with the clock
20654359Sroberto	 */
20754359Sroberto
20854359Sroberto	/* get the current process token handle */
20954359Sroberto	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
21054359Sroberto		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
21154359Sroberto		exit(1);
21254359Sroberto	}
21354359Sroberto	/* get the LUID for system-time privilege. */
21454359Sroberto	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
21554359Sroberto	tkp.PrivilegeCount = 1;  /* one privilege to set */
21654359Sroberto	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
21754359Sroberto	/* get set-time privilege for this process. */
21854359Sroberto	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
21954359Sroberto	/* cannot test return value of AdjustTokenPrivileges. */
22054359Sroberto	if (GetLastError() != ERROR_SUCCESS) {
22154359Sroberto		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
22254359Sroberto	}
22354359Sroberto
22454359Sroberto	/*
22554359Sroberto	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
22654359Sroberto	 * Under Windows/NT,
22754359Sroberto	 */
22854359Sroberto
22954359Sroberto	WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
23054359Sroberto	if (WaitableTimerHandle == NULL) {
23154359Sroberto		msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
23254359Sroberto		exit(1);
23354359Sroberto	}
23454359Sroberto	else {
23554359Sroberto		DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
23654359Sroberto		LARGE_INTEGER DueTime;
23754359Sroberto		DueTime.QuadPart = Period * 10000i64;
23854359Sroberto		if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
23954359Sroberto			msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
24054359Sroberto			exit(1);
24154359Sroberto		}
24254359Sroberto	}
24354359Sroberto
24454359Sroberto#endif /* SYS_WINNT */
24554359Sroberto}
24654359Sroberto
24754359Sroberto#if defined(SYS_WINNT)
24854359Srobertoextern HANDLE
24954359Srobertoget_timer_handle(void)
25054359Sroberto{
25154359Sroberto	return WaitableTimerHandle;
25254359Sroberto}
25354359Sroberto#endif
25454359Sroberto
25554359Sroberto/*
25654359Sroberto * timer - dispatch anyone who needs to be
25754359Sroberto */
25854359Srobertovoid
25954359Srobertotimer(void)
26054359Sroberto{
26154359Sroberto	register struct peer *peer, *next_peer;
262132451Sroberto#ifdef OPENSSL
263132451Sroberto	char	statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
264132451Sroberto#endif /* OPENSSL */
26582498Sroberto	u_int n;
26654359Sroberto
26754359Sroberto	current_time += (1<<EVENT_TIMEOUT);
26854359Sroberto
26954359Sroberto	/*
27054359Sroberto	 * Adjustment timeout first.
27154359Sroberto	 */
27254359Sroberto	if (adjust_timer <= current_time) {
27354359Sroberto		adjust_timer += 1;
27454359Sroberto		adj_host_clock();
275132451Sroberto		kod_proto();
276182007Sroberto#ifdef REFCLOCK
277182007Sroberto		for (n = 0; n < NTP_HASH_SIZE; n++) {
278182007Sroberto			for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
279182007Sroberto				next_peer = peer->next;
280182007Sroberto				if (peer->flags & FLAG_REFCLOCK)
281182007Sroberto					refclock_timer(peer);
282182007Sroberto			}
283182007Sroberto		}
284182007Sroberto#endif /* REFCLOCK */
28554359Sroberto	}
28654359Sroberto
28754359Sroberto	/*
28854359Sroberto	 * Now dispatch any peers whose event timer has expired. Be careful
28954359Sroberto	 * here, since the peer structure might go away as the result of
29054359Sroberto	 * the call.
29154359Sroberto	 */
292182007Sroberto	for (n = 0; n < NTP_HASH_SIZE; n++) {
29354359Sroberto		for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
29454359Sroberto			next_peer = peer->next;
29554359Sroberto			if (peer->action && peer->nextaction <= current_time)
29654359Sroberto	  			peer->action(peer);
29754359Sroberto			if (peer->nextdate <= current_time) {
29854359Sroberto#ifdef REFCLOCK
29954359Sroberto				if (peer->flags & FLAG_REFCLOCK)
30054359Sroberto					refclock_transmit(peer);
30154359Sroberto				else
30254359Sroberto					transmit(peer);
30354359Sroberto#else /* REFCLOCK */
30454359Sroberto				transmit(peer);
30554359Sroberto#endif /* REFCLOCK */
30654359Sroberto			}
30754359Sroberto		}
30854359Sroberto	}
30954359Sroberto
31054359Sroberto	/*
31154359Sroberto	 * Garbage collect expired keys.
31254359Sroberto	 */
31354359Sroberto	if (keys_timer <= current_time) {
31454359Sroberto		keys_timer += MINUTE;
31554359Sroberto		auth_agekeys();
31654359Sroberto	}
31754359Sroberto
31854359Sroberto	/*
31982498Sroberto	 * Huff-n'-puff filter
32054359Sroberto	 */
32182498Sroberto	if (huffpuff_timer <= current_time) {
32282498Sroberto		huffpuff_timer += HUFFPUFF;
32382498Sroberto		huffpuff();
32482498Sroberto	}
32582498Sroberto
326132451Sroberto#ifdef OPENSSL
32782498Sroberto	/*
32882498Sroberto	 * Garbage collect old keys and generate new private value
32982498Sroberto	 */
33054359Sroberto	if (revoke_timer <= current_time) {
331132451Sroberto		revoke_timer += RANDPOLL(sys_revoke);
33282498Sroberto		expire_all();
333132451Sroberto		sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
334132451Sroberto		record_crypto_stats(NULL, statstr);
33582498Sroberto#ifdef DEBUG
33682498Sroberto		if (debug)
337132451Sroberto			printf("timer: %s\n", statstr);
33882498Sroberto#endif
33954359Sroberto	}
340132451Sroberto#endif /* OPENSSL */
34154359Sroberto
34254359Sroberto	/*
343182007Sroberto	 * interface update timer
34454359Sroberto	 */
345182007Sroberto	if (interface_interval && interface_timer <= current_time) {
346200576Sroberto
347182007Sroberto		timer_interfacetimeout(current_time + interface_interval);
348200576Sroberto		DPRINTF(1, ("timer: interface update\n"));
349200576Sroberto		interface_update(NULL, NULL);
35054359Sroberto	}
351182007Sroberto
352182007Sroberto	/*
353182007Sroberto	 * Finally, periodically write stats.
354182007Sroberto	 */
355182007Sroberto	if (stats_timer <= current_time) {
356182007Sroberto	     if (stats_timer != 0)
357182007Sroberto		  write_stats();
358182007Sroberto	     stats_timer += stats_write_period;
359182007Sroberto	}
36054359Sroberto}
36154359Sroberto
36254359Sroberto
36354359Sroberto#ifndef SYS_WINNT
36454359Sroberto/*
36554359Sroberto * alarming - tell the world we've been alarmed
36654359Sroberto */
36754359Srobertostatic RETSIGTYPE
36854359Srobertoalarming(
36954359Sroberto	int sig
37054359Sroberto	)
37154359Sroberto{
37254359Sroberto#if !defined(VMS)
37354359Sroberto	if (initializing)
37454359Sroberto		return;
37554359Sroberto	if (alarm_flag)
37654359Sroberto		alarm_overflow++;
37754359Sroberto	else
37854359Sroberto		alarm_flag++;
37954359Sroberto#else /* VMS AST routine */
38054359Sroberto	if (!initializing) {
38154359Sroberto		if (alarm_flag) alarm_overflow++;
38254359Sroberto		else alarm_flag = 1;	/* increment is no good */
38354359Sroberto	}
38454359Sroberto	lib$addx(&vmsinc,&vmstimer,&vmstimer);
38554359Sroberto	sys$setimr(0,&vmstimer,alarming,alarming,0);
38654359Sroberto#endif /* VMS */
38754359Sroberto}
38854359Sroberto#endif /* SYS_WINNT */
38954359Sroberto
390182007Srobertovoid
391182007Srobertotimer_interfacetimeout(u_long timeout)
392182007Sroberto{
393182007Sroberto	interface_timer = timeout;
394182007Sroberto}
39554359Sroberto
396182007Sroberto
39754359Sroberto/*
39854359Sroberto * timer_clr_stats - clear timer module stat counters
39954359Sroberto */
40054359Srobertovoid
40154359Srobertotimer_clr_stats(void)
40254359Sroberto{
40354359Sroberto	timer_overflows = 0;
40454359Sroberto	timer_xmtcalls = 0;
40554359Sroberto	timer_timereset = current_time;
40654359Sroberto}
40754359Sroberto
408