xref: /freebsd/contrib/ntp/ntpd/ntp_timer.c (revision 8d20be1e22095c27faf8fe8b2f0d089739cc742e)
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 
12 #include <stdio.h>
13 #include <signal.h>
14 #ifdef HAVE_SYS_SIGNAL_H
15 # include <sys/signal.h>
16 #endif
17 #ifdef HAVE_UNISTD_H
18 # include <unistd.h>
19 #endif
20 
21 #if defined(HAVE_IO_COMPLETION_PORT)
22 # include "ntp_iocompletionport.h"
23 # include "ntp_timer.h"
24 #endif
25 
26 /*
27  * These routines provide support for the event timer.	The timer is
28  * implemented by an interrupt routine which sets a flag once every
29  * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
30  * is called when the mainline code gets around to seeing the flag.
31  * The timer routine dispatches the clock adjustment code if its time
32  * has come, then searches the timer queue for expiries which are
33  * dispatched to the transmit procedure.  Finally, we call the hourly
34  * procedure to do cleanup and print a message.
35  */
36 
37 volatile int interface_interval = 300;     /* update interface every 5 minutes as default */
38 
39 /*
40  * Alarm flag.	The mainline code imports this.
41  */
42 volatile int alarm_flag;
43 
44 /*
45  * The counters
46  */
47 static	u_long adjust_timer;		/* second timer */
48 static	u_long keys_timer;		/* minute timer */
49 static	u_long stats_timer;		/* stats timer */
50 static	u_long huffpuff_timer;		/* huff-n'-puff timer */
51 static  u_long interface_timer;	        /* interface update timer */
52 #ifdef OPENSSL
53 static	u_long revoke_timer;		/* keys revoke timer */
54 u_char	sys_revoke = KEY_REVOKE;	/* keys revoke timeout (log2 s) */
55 #endif /* OPENSSL */
56 
57 /*
58  * Statistics counter for the interested.
59  */
60 volatile u_long alarm_overflow;
61 
62 #define MINUTE	60
63 #define HOUR	(60*60)
64 
65 u_long current_time;
66 
67 /*
68  * Stats.  Number of overflows and number of calls to transmit().
69  */
70 u_long timer_timereset;
71 u_long timer_overflows;
72 u_long timer_xmtcalls;
73 
74 #if defined(VMS)
75 static int vmstimer[2]; 	/* time for next timer AST */
76 static int vmsinc[2];		/* timer increment */
77 #endif /* VMS */
78 
79 #if defined SYS_WINNT
80 static HANDLE WaitableTimerHandle = NULL;
81 #else
82 static	RETSIGTYPE alarming P((int));
83 #endif /* SYS_WINNT */
84 
85 #if !defined(VMS)
86 # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
87 #  ifndef HAVE_TIMER_SETTIME
88 	struct itimerval itimer;
89 #  else
90 	static timer_t ntpd_timerid;
91 	struct itimerspec itimer;
92 #  endif /* HAVE_TIMER_SETTIME */
93 # endif /* SYS_WINNT */
94 #endif /* VMS */
95 
96 /*
97  * reinit_timer - reinitialize interval timer.
98  */
99 void
100 reinit_timer(void)
101 {
102 #if !defined(SYS_WINNT) && !defined(VMS)
103 #  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
104 	timer_gettime(ntpd_timerid, &itimer);
105 	if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
106 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
107 	}
108 	if (itimer.it_value.tv_nsec < 0 ) {
109 		itimer.it_value.tv_nsec = 0;
110 	}
111 	if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
112 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
113 		itimer.it_value.tv_nsec = 0;
114 	}
115 	itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
116 	itimer.it_interval.tv_nsec = 0;
117 	timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
118 #  else
119 	getitimer(ITIMER_REAL, &itimer);
120 	if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
121 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
122 	}
123 	if (itimer.it_value.tv_usec < 0 ) {
124 		itimer.it_value.tv_usec = 0;
125 	}
126 	if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
127 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
128 		itimer.it_value.tv_usec = 0;
129 	}
130 	itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
131 	itimer.it_interval.tv_usec = 0;
132 	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
133 #  endif
134 # endif /* VMS */
135 }
136 
137 /*
138  * init_timer - initialize the timer data structures
139  */
140 void
141 init_timer(void)
142 {
143 # if defined SYS_WINNT & !defined(SYS_CYGWIN32)
144 	HANDLE hToken = INVALID_HANDLE_VALUE;
145 	TOKEN_PRIVILEGES tkp;
146 # endif /* SYS_WINNT */
147 
148 	/*
149 	 * Initialize...
150 	 */
151 	alarm_flag = 0;
152 	alarm_overflow = 0;
153 	adjust_timer = 1;
154 	stats_timer = 0;
155 	huffpuff_timer = 0;
156 	interface_timer = 0;
157 	current_time = 0;
158 	timer_overflows = 0;
159 	timer_xmtcalls = 0;
160 	timer_timereset = 0;
161 
162 #if !defined(SYS_WINNT)
163 	/*
164 	 * Set up the alarm interrupt.	The first comes 2**EVENT_TIMEOUT
165 	 * seconds from now and they continue on every 2**EVENT_TIMEOUT
166 	 * seconds.
167 	 */
168 # if !defined(VMS)
169 #  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
170 	if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
171 #	ifdef SYS_VXWORKS
172 		ERROR
173 #	else
174 		-1
175 #	endif
176 	   )
177 	{
178 		fprintf (stderr, "timer create FAILED\n");
179 		exit (0);
180 	}
181 	(void) signal_no_reset(SIGALRM, alarming);
182 	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
183 	itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
184 	timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
185 #  else
186 	(void) signal_no_reset(SIGALRM, alarming);
187 	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
188 	itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
189 	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
190 #  endif
191 # else /* VMS */
192 	vmsinc[0] = 10000000;		/* 1 sec */
193 	vmsinc[1] = 0;
194 	lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
195 
196 	sys$gettim(&vmstimer);	/* that's "now" as abstime */
197 
198 	lib$addx(&vmsinc, &vmstimer, &vmstimer);
199 	sys$setimr(0, &vmstimer, alarming, alarming, 0);
200 # endif /* VMS */
201 #else /* SYS_WINNT */
202 	_tzset();
203 
204 	/*
205 	 * Get privileges needed for fiddling with the clock
206 	 */
207 
208 	/* get the current process token handle */
209 	if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) {
210 		msyslog(LOG_ERR, "OpenProcessToken failed: %m");
211 		exit(1);
212 	}
213 	/* get the LUID for system-time privilege. */
214 	LookupPrivilegeValue(NULL, SE_SYSTEMTIME_NAME, &tkp.Privileges[0].Luid);
215 	tkp.PrivilegeCount = 1;  /* one privilege to set */
216 	tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
217 	/* get set-time privilege for this process. */
218 	AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0);
219 	/* cannot test return value of AdjustTokenPrivileges. */
220 	if (GetLastError() != ERROR_SUCCESS) {
221 		msyslog(LOG_ERR, "AdjustTokenPrivileges failed: %m");
222 	}
223 
224 	/*
225 	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
226 	 * Under Windows/NT,
227 	 */
228 
229 	WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
230 	if (WaitableTimerHandle == NULL) {
231 		msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
232 		exit(1);
233 	}
234 	else {
235 		DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
236 		LARGE_INTEGER DueTime;
237 		DueTime.QuadPart = Period * 10000i64;
238 		if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
239 			msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
240 			exit(1);
241 		}
242 	}
243 
244 #endif /* SYS_WINNT */
245 }
246 
247 #if defined(SYS_WINNT)
248 extern HANDLE
249 get_timer_handle(void)
250 {
251 	return WaitableTimerHandle;
252 }
253 #endif
254 
255 /*
256  * timer - dispatch anyone who needs to be
257  */
258 void
259 timer(void)
260 {
261 	register struct peer *peer, *next_peer;
262 #ifdef OPENSSL
263 	char	statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
264 #endif /* OPENSSL */
265 	u_int n;
266 
267 	current_time += (1<<EVENT_TIMEOUT);
268 
269 	/*
270 	 * Adjustment timeout first.
271 	 */
272 	if (adjust_timer <= current_time) {
273 		adjust_timer += 1;
274 		adj_host_clock();
275 		kod_proto();
276 #ifdef REFCLOCK
277 		for (n = 0; n < NTP_HASH_SIZE; n++) {
278 			for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
279 				next_peer = peer->next;
280 				if (peer->flags & FLAG_REFCLOCK)
281 					refclock_timer(peer);
282 			}
283 		}
284 #endif /* REFCLOCK */
285 	}
286 
287 	/*
288 	 * Now dispatch any peers whose event timer has expired. Be careful
289 	 * here, since the peer structure might go away as the result of
290 	 * the call.
291 	 */
292 	for (n = 0; n < NTP_HASH_SIZE; n++) {
293 		for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
294 			next_peer = peer->next;
295 			if (peer->action && peer->nextaction <= current_time)
296 	  			peer->action(peer);
297 			if (peer->nextdate <= current_time) {
298 #ifdef REFCLOCK
299 				if (peer->flags & FLAG_REFCLOCK)
300 					refclock_transmit(peer);
301 				else
302 					transmit(peer);
303 #else /* REFCLOCK */
304 				transmit(peer);
305 #endif /* REFCLOCK */
306 			}
307 		}
308 	}
309 
310 	/*
311 	 * Garbage collect expired keys.
312 	 */
313 	if (keys_timer <= current_time) {
314 		keys_timer += MINUTE;
315 		auth_agekeys();
316 	}
317 
318 	/*
319 	 * Huff-n'-puff filter
320 	 */
321 	if (huffpuff_timer <= current_time) {
322 		huffpuff_timer += HUFFPUFF;
323 		huffpuff();
324 	}
325 
326 #ifdef OPENSSL
327 	/*
328 	 * Garbage collect old keys and generate new private value
329 	 */
330 	if (revoke_timer <= current_time) {
331 		revoke_timer += RANDPOLL(sys_revoke);
332 		expire_all();
333 		sprintf(statstr, "refresh ts %u", ntohl(hostval.tstamp));
334 		record_crypto_stats(NULL, statstr);
335 #ifdef DEBUG
336 		if (debug)
337 			printf("timer: %s\n", statstr);
338 #endif
339 	}
340 #endif /* OPENSSL */
341 
342 	/*
343 	 * interface update timer
344 	 */
345 	if (interface_interval && interface_timer <= current_time) {
346 
347 		timer_interfacetimeout(current_time + interface_interval);
348 		DPRINTF(1, ("timer: interface update\n"));
349 		interface_update(NULL, NULL);
350 	}
351 
352 	/*
353 	 * Finally, periodically write stats.
354 	 */
355 	if (stats_timer <= current_time) {
356 	     if (stats_timer != 0)
357 		  write_stats();
358 	     stats_timer += stats_write_period;
359 	}
360 }
361 
362 
363 #ifndef SYS_WINNT
364 /*
365  * alarming - tell the world we've been alarmed
366  */
367 static RETSIGTYPE
368 alarming(
369 	int sig
370 	)
371 {
372 #if !defined(VMS)
373 	if (initializing)
374 		return;
375 	if (alarm_flag)
376 		alarm_overflow++;
377 	else
378 		alarm_flag++;
379 #else /* VMS AST routine */
380 	if (!initializing) {
381 		if (alarm_flag) alarm_overflow++;
382 		else alarm_flag = 1;	/* increment is no good */
383 	}
384 	lib$addx(&vmsinc,&vmstimer,&vmstimer);
385 	sys$setimr(0,&vmstimer,alarming,alarming,0);
386 #endif /* VMS */
387 }
388 #endif /* SYS_WINNT */
389 
390 void
391 timer_interfacetimeout(u_long timeout)
392 {
393 	interface_timer = timeout;
394 }
395 
396 
397 /*
398  * timer_clr_stats - clear timer module stat counters
399  */
400 void
401 timer_clr_stats(void)
402 {
403 	timer_overflows = 0;
404 	timer_xmtcalls = 0;
405 	timer_timereset = current_time;
406 }
407 
408