File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / ntp / ntpd / ntp_timer.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue May 29 12:08:38 2012 UTC (12 years, 2 months ago) by misho
Branches: ntp, MAIN
CVS tags: v4_2_6p5p0, v4_2_6p5, HEAD
ntp 4.2.6p5

    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: #ifdef KERNEL_PLL
   27: #include "ntp_syscall.h"
   28: #endif /* KERNEL_PLL */
   29: 
   30: #ifdef OPENSSL
   31: #include <openssl/rand.h>
   32: #endif /* OPENSSL */
   33: 
   34: /*
   35:  * These routines provide support for the event timer.	The timer is
   36:  * implemented by an interrupt routine which sets a flag once every
   37:  * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which
   38:  * is called when the mainline code gets around to seeing the flag.
   39:  * The timer routine dispatches the clock adjustment code if its time
   40:  * has come, then searches the timer queue for expiries which are
   41:  * dispatched to the transmit procedure.  Finally, we call the hourly
   42:  * procedure to do cleanup and print a message.
   43:  */
   44: volatile int interface_interval = 300;     /* update interface every 5 minutes as default */
   45: 	  
   46: /*
   47:  * Alarm flag. The mainline code imports this.
   48:  */
   49: volatile int alarm_flag;
   50: 
   51: /*
   52:  * The counters and timeouts
   53:  */
   54: static  u_long interface_timer;	/* interface update timer */
   55: static	u_long adjust_timer;	/* second timer */
   56: static	u_long stats_timer;	/* stats timer */
   57: static	u_long huffpuff_timer;	/* huff-n'-puff timer */
   58: u_long	leapsec;		/* leapseconds countdown */
   59: l_fp	sys_time;		/* current system time */
   60: #ifdef OPENSSL
   61: static	u_long revoke_timer;	/* keys revoke timer */
   62: static	u_long keys_timer;	/* session key timer */
   63: u_long	sys_revoke = KEY_REVOKE; /* keys revoke timeout (log2 s) */
   64: u_long	sys_automax = NTP_AUTOMAX; /* key list timeout (log2 s) */
   65: #endif /* OPENSSL */
   66: 
   67: /*
   68:  * Statistics counter for the interested.
   69:  */
   70: volatile u_long alarm_overflow;
   71: 
   72: #define MINUTE	60
   73: #define HOUR	(60 * MINUTE)
   74: #define	DAY	(24 * HOUR)
   75: 
   76: u_long current_time;		/* seconds since startup */
   77: 
   78: /*
   79:  * Stats.  Number of overflows and number of calls to transmit().
   80:  */
   81: u_long timer_timereset;
   82: u_long timer_overflows;
   83: u_long timer_xmtcalls;
   84: 
   85: #if defined(VMS)
   86: static int vmstimer[2]; 	/* time for next timer AST */
   87: static int vmsinc[2];		/* timer increment */
   88: #endif /* VMS */
   89: 
   90: #if defined SYS_WINNT
   91: static HANDLE WaitableTimerHandle = NULL;
   92: #else
   93: static	RETSIGTYPE alarming (int);
   94: #endif /* SYS_WINNT */
   95: 
   96: #if !defined(VMS)
   97: # if !defined SYS_WINNT || defined(SYS_CYGWIN32)
   98: #  ifndef HAVE_TIMER_SETTIME
   99: 	struct itimerval itimer;
  100: #  else 
  101: 	static timer_t ntpd_timerid;
  102: 	struct itimerspec itimer;
  103: #  endif /* HAVE_TIMER_SETTIME */
  104: # endif /* SYS_WINNT */
  105: #endif /* VMS */
  106: 
  107: /*
  108:  * reinit_timer - reinitialize interval timer.
  109:  */
  110: void 
  111: reinit_timer(void)
  112: {
  113: #if !defined(SYS_WINNT) && !defined(VMS)
  114: #  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
  115: 	timer_gettime(ntpd_timerid, &itimer);
  116: 	if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
  117: 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
  118: 	}
  119: 	if (itimer.it_value.tv_nsec < 0 ) {
  120: 		itimer.it_value.tv_nsec = 0;
  121: 	}
  122: 	if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec == 0) {
  123: 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
  124: 		itimer.it_value.tv_nsec = 0;
  125: 	}
  126: 	itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
  127: 	itimer.it_interval.tv_nsec = 0;
  128: 	timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
  129: #  else
  130: 	getitimer(ITIMER_REAL, &itimer);
  131: 	if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1<<EVENT_TIMEOUT)) {
  132: 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
  133: 	}
  134: 	if (itimer.it_value.tv_usec < 0 ) {
  135: 		itimer.it_value.tv_usec = 0;
  136: 	}
  137: 	if (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_usec == 0) {
  138: 		itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
  139: 		itimer.it_value.tv_usec = 0;
  140: 	}
  141: 	itimer.it_interval.tv_sec = (1<<EVENT_TIMEOUT);
  142: 	itimer.it_interval.tv_usec = 0;
  143: 	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
  144: #  endif
  145: # endif /* VMS */
  146: }
  147: 
  148: /*
  149:  * init_timer - initialize the timer data structures
  150:  */
  151: void
  152: init_timer(void)
  153: {
  154: 	/*
  155: 	 * Initialize...
  156: 	 */
  157: 	alarm_flag = 0;
  158: 	alarm_overflow = 0;
  159: 	adjust_timer = 1;
  160: 	stats_timer = 0;
  161: 	huffpuff_timer = 0;
  162: 	interface_timer = 0;
  163: 	current_time = 0;
  164: 	timer_overflows = 0;
  165: 	timer_xmtcalls = 0;
  166: 	timer_timereset = 0;
  167: 
  168: #if !defined(SYS_WINNT)
  169: 	/*
  170: 	 * Set up the alarm interrupt.	The first comes 2**EVENT_TIMEOUT
  171: 	 * seconds from now and they continue on every 2**EVENT_TIMEOUT
  172: 	 * seconds.
  173: 	 */
  174: # if !defined(VMS)
  175: #  if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME)
  176: 	if (timer_create (CLOCK_REALTIME, NULL, &ntpd_timerid) ==
  177: #	ifdef SYS_VXWORKS
  178: 		ERROR
  179: #	else
  180: 		-1
  181: #	endif
  182: 	   )
  183: 	{
  184: 		fprintf (stderr, "timer create FAILED\n");
  185: 		exit (0);
  186: 	}
  187: 	(void) signal_no_reset(SIGALRM, alarming);
  188: 	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
  189: 	itimer.it_interval.tv_nsec = itimer.it_value.tv_nsec = 0;
  190: 	timer_settime(ntpd_timerid, 0 /*!TIMER_ABSTIME*/, &itimer, NULL);
  191: #  else
  192: 	(void) signal_no_reset(SIGALRM, alarming);
  193: 	itimer.it_interval.tv_sec = itimer.it_value.tv_sec = (1<<EVENT_TIMEOUT);
  194: 	itimer.it_interval.tv_usec = itimer.it_value.tv_usec = 0;
  195: 	setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
  196: #  endif
  197: # else /* VMS */
  198: 	vmsinc[0] = 10000000;		/* 1 sec */
  199: 	vmsinc[1] = 0;
  200: 	lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);
  201: 
  202: 	sys$gettim(&vmstimer);	/* that's "now" as abstime */
  203: 
  204: 	lib$addx(&vmsinc, &vmstimer, &vmstimer);
  205: 	sys$setimr(0, &vmstimer, alarming, alarming, 0);
  206: # endif /* VMS */
  207: #else /* SYS_WINNT */
  208: 	/*
  209: 	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
  210: 	 * Under Windows/NT, 
  211: 	 */
  212: 
  213: 	WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
  214: 	if (WaitableTimerHandle == NULL) {
  215: 		msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
  216: 		exit(1);
  217: 	}
  218: 	else {
  219: 		DWORD Period = (1<<EVENT_TIMEOUT) * 1000;
  220: 		LARGE_INTEGER DueTime;
  221: 		DueTime.QuadPart = Period * 10000i64;
  222: 		if (!SetWaitableTimer(WaitableTimerHandle, &DueTime, Period, NULL, NULL, FALSE) != NO_ERROR) {
  223: 			msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
  224: 			exit(1);
  225: 		}
  226: 	}
  227: 
  228: #endif /* SYS_WINNT */
  229: }
  230: 
  231: #if defined(SYS_WINNT)
  232: extern HANDLE 
  233: get_timer_handle(void)
  234: {
  235: 	return WaitableTimerHandle;
  236: }
  237: #endif
  238: 
  239: /*
  240:  * timer - event timer
  241:  */
  242: void
  243: timer(void)
  244: {
  245: 	register struct peer *peer, *next_peer;
  246: 	u_int	n;
  247: 
  248: 	/*
  249: 	 * The basic timerevent is one second. This is used to adjust
  250: 	 * the system clock in time and frequency, implement the
  251: 	 * kiss-o'-deatch function and implement the association
  252: 	 * polling function..
  253: 	 */
  254: 	current_time++;
  255: 	get_systime(&sys_time);
  256: 	if (adjust_timer <= current_time) {
  257: 		adjust_timer += 1;
  258: 		adj_host_clock();
  259: #ifdef REFCLOCK
  260: 		for (n = 0; n < NTP_HASH_SIZE; n++) {
  261: 			for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
  262: 				next_peer = peer->next;
  263: 				if (peer->flags & FLAG_REFCLOCK)
  264: 					refclock_timer(peer);
  265: 			}
  266: 		}
  267: #endif /* REFCLOCK */
  268: 	}
  269: 
  270: 	/*
  271: 	 * Now dispatch any peers whose event timer has expired. Be
  272: 	 * careful here, since the peer structure might go away as the
  273: 	 * result of the call.
  274: 	 */
  275: 	for (n = 0; n < NTP_HASH_SIZE; n++) {
  276: 		for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
  277: 			next_peer = peer->next;
  278: 			if (peer->action && peer->nextaction <=
  279: 			    current_time)
  280: 				peer->action(peer);
  281: 
  282: 			/*
  283: 			 * Restrain the non-burst packet rate not more
  284: 			 * than one packet every 16 seconds. This is
  285: 			 * usually tripped using iburst and minpoll of
  286: 			 * 128 s or less.
  287: 			 */
  288: 			if (peer->throttle > 0)
  289: 				peer->throttle--;
  290: 			if (peer->nextdate <= current_time) {
  291: #ifdef REFCLOCK
  292: 				if (peer->flags & FLAG_REFCLOCK)
  293: 					refclock_transmit(peer);
  294: 				else
  295: 					transmit(peer);
  296: #else /* REFCLOCK */
  297: 				transmit(peer);
  298: #endif /* REFCLOCK */
  299: 			}
  300: 		}
  301: 	}
  302: 
  303: 	/*
  304: 	 * Orphan mode is active when enabled and when no servers less
  305: 	 * than the orphan stratum are available. A server with no other
  306: 	 * synchronization source is an orphan. It shows offset zero and
  307: 	 * reference ID the loopback address.
  308: 	 */
  309: 	if (sys_orphan < STRATUM_UNSPEC && sys_peer == NULL) {
  310: 		if (sys_leap == LEAP_NOTINSYNC) {
  311: 			sys_leap = LEAP_NOWARNING;
  312: #ifdef OPENSSL
  313: 			if (crypto_flags)	
  314: 				crypto_update();
  315: #endif /* OPENSSL */
  316: 		}
  317: 		sys_stratum = (u_char)sys_orphan;
  318: 		if (sys_stratum > 1)
  319: 			sys_refid = htonl(LOOPBACKADR);
  320: 		else
  321: 			memcpy(&sys_refid, "LOOP", 4);
  322: 		sys_offset = 0;
  323: 		sys_rootdelay = 0;
  324: 		sys_rootdisp = 0;
  325: 	}
  326: 
  327: 	/*
  328: 	 * Leapseconds. If a leap is pending, decrement the time
  329: 	 * remaining. If less than one day remains, set the leap bits.
  330: 	 * When no time remains, clear the leap bits and increment the
  331: 	 * TAI. If kernel suppport is not available, do the leap
  332: 	 * crudely. Note a leap cannot be pending unless the clock is
  333: 	 * set.
  334: 	 */
  335: 	if (leapsec > 0) {
  336: 		leapsec--;
  337: 		if (leapsec == 0) {
  338: 			sys_leap = LEAP_NOWARNING;
  339: 			sys_tai = leap_tai;
  340: #ifdef KERNEL_PLL
  341: 			if (!(pll_control && kern_enable))
  342: 				step_systime(-1.0);
  343: #else /* KERNEL_PLL */
  344: #ifndef SYS_WINNT /* WinNT port has its own leap second handling */
  345: 			step_systime(-1.0);
  346: #endif /* SYS_WINNT */
  347: #endif /* KERNEL_PLL */
  348: 			report_event(EVNT_LEAP, NULL, NULL);
  349: 		} else {
  350: 			if (leapsec < DAY)
  351: 				sys_leap = LEAP_ADDSECOND;
  352: 			if (leap_tai > 0)
  353: 				sys_tai = leap_tai - 1;
  354: 		}
  355: 	}
  356: 
  357: 	/*
  358: 	 * Update huff-n'-puff filter.
  359: 	 */
  360: 	if (huffpuff_timer <= current_time) {
  361: 		huffpuff_timer += HUFFPUFF;
  362: 		huffpuff();
  363: 	}
  364: 
  365: #ifdef OPENSSL
  366: 	/*
  367: 	 * Garbage collect expired keys.
  368: 	 */
  369: 	if (keys_timer <= current_time) {
  370: 		keys_timer += 1 << sys_automax;
  371: 		auth_agekeys();
  372: 	}
  373: 
  374: 	/*
  375: 	 * Garbage collect key list and generate new private value. The
  376: 	 * timer runs only after initial synchronization and fires about
  377: 	 * once per day.
  378: 	 */
  379: 	if (revoke_timer <= current_time && sys_leap !=
  380: 	    LEAP_NOTINSYNC) {
  381: 		revoke_timer += 1 << sys_revoke;
  382: 		RAND_bytes((u_char *)&sys_private, 4);
  383: 	}
  384: #endif /* OPENSSL */
  385: 
  386: 	/*
  387: 	 * Interface update timer
  388: 	 */
  389: 	if (interface_interval && interface_timer <= current_time) {
  390: 
  391: 		timer_interfacetimeout(current_time +
  392: 		    interface_interval);
  393: 		DPRINTF(2, ("timer: interface update\n"));
  394: 		interface_update(NULL, NULL);
  395: 	}
  396: 	
  397: 	/*
  398: 	 * Finally, write hourly stats.
  399: 	 */
  400: 	if (stats_timer <= current_time) {
  401: 		stats_timer += HOUR;
  402: 		write_stats();
  403: 		if (sys_tai != 0 && sys_time.l_ui > leap_expire)
  404: 			report_event(EVNT_LEAPVAL, NULL, NULL);
  405: 	}
  406: }
  407: 
  408: 
  409: #ifndef SYS_WINNT
  410: /*
  411:  * alarming - tell the world we've been alarmed
  412:  */
  413: static RETSIGTYPE
  414: alarming(
  415: 	int sig
  416: 	)
  417: {
  418: #if !defined(VMS)
  419: 	if (initializing)
  420: 		return;
  421: 	if (alarm_flag)
  422: 		alarm_overflow++;
  423: 	else
  424: 		alarm_flag++;
  425: #else /* VMS AST routine */
  426: 	if (!initializing) {
  427: 		if (alarm_flag) alarm_overflow++;
  428: 		else alarm_flag = 1;	/* increment is no good */
  429: 	}
  430: 	lib$addx(&vmsinc,&vmstimer,&vmstimer);
  431: 	sys$setimr(0,&vmstimer,alarming,alarming,0);
  432: #endif /* VMS */
  433: }
  434: #endif /* SYS_WINNT */
  435: 
  436: void
  437: timer_interfacetimeout(u_long timeout)
  438: {
  439: 	interface_timer = timeout;
  440: }
  441: 
  442: 
  443: /*
  444:  * timer_clr_stats - clear timer module stat counters
  445:  */
  446: void
  447: timer_clr_stats(void)
  448: {
  449: 	timer_overflows = 0;
  450: 	timer_xmtcalls = 0;
  451: 	timer_timereset = current_time;
  452: }
  453: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>