PageRenderTime 36ms CodeModel.GetById 15ms app.highlight 17ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/ntp/ntpd/ntp_timer.c

https://bitbucket.org/freebsd/freebsd-head/
C | 407 lines | 283 code | 42 blank | 82 comment | 60 complexity | 11a832ddbdc6c696ad9a46d0f21b0a01 MD5 | raw file
  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
 37volatile int interface_interval = 300;     /* update interface every 5 minutes as default */
 38	  
 39/*
 40 * Alarm flag.	The mainline code imports this.
 41 */
 42volatile int alarm_flag;
 43
 44/*
 45 * The counters
 46 */
 47static	u_long adjust_timer;		/* second timer */
 48static	u_long keys_timer;		/* minute timer */
 49static	u_long stats_timer;		/* stats timer */
 50static	u_long huffpuff_timer;		/* huff-n'-puff timer */
 51static  u_long interface_timer;	        /* interface update timer */
 52#ifdef OPENSSL
 53static	u_long revoke_timer;		/* keys revoke timer */
 54u_char	sys_revoke = KEY_REVOKE;	/* keys revoke timeout (log2 s) */
 55#endif /* OPENSSL */
 56
 57/*
 58 * Statistics counter for the interested.
 59 */
 60volatile u_long alarm_overflow;
 61
 62#define MINUTE	60
 63#define HOUR	(60*60)
 64
 65u_long current_time;
 66
 67/*
 68 * Stats.  Number of overflows and number of calls to transmit().
 69 */
 70u_long timer_timereset;
 71u_long timer_overflows;
 72u_long timer_xmtcalls;
 73
 74#if defined(VMS)
 75static int vmstimer[2]; 	/* time for next timer AST */
 76static int vmsinc[2];		/* timer increment */
 77#endif /* VMS */
 78
 79#if defined SYS_WINNT
 80static HANDLE WaitableTimerHandle = NULL;
 81#else
 82static	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 */
 99void 
100reinit_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 */
140void
141init_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)
248extern HANDLE 
249get_timer_handle(void)
250{
251	return WaitableTimerHandle;
252}
253#endif
254
255/*
256 * timer - dispatch anyone who needs to be
257 */
258void
259timer(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 */
367static RETSIGTYPE
368alarming(
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
390void
391timer_interfacetimeout(u_long timeout)
392{
393	interface_timer = timeout;
394}
395
396
397/*
398 * timer_clr_stats - clear timer module stat counters
399 */
400void
401timer_clr_stats(void)
402{
403	timer_overflows = 0;
404	timer_xmtcalls = 0;
405	timer_timereset = current_time;
406}
407