/* * ntp_timer.c - event timer support routines */ #ifdef HAVE_CONFIG_H # include #endif #include "ntp_machine.h" #include "ntpd.h" #include "ntp_stdlib.h" #include #include #ifdef HAVE_SYS_SIGNAL_H # include #endif #ifdef HAVE_UNISTD_H # include #endif #if defined(HAVE_IO_COMPLETION_PORT) # include "ntp_iocompletionport.h" # include "ntp_timer.h" #endif #ifdef KERNEL_PLL #include "ntp_syscall.h" #endif /* KERNEL_PLL */ /* * These routines provide support for the event timer. The timer is * implemented by an interrupt routine which sets a flag once every * 2**EVENT_TIMEOUT seconds (currently 4), and a timer routine which * is called when the mainline code gets around to seeing the flag. * The timer routine dispatches the clock adjustment code if its time * has come, then searches the timer queue for expiries which are * dispatched to the transmit procedure. Finally, we call the hourly * procedure to do cleanup and print a message. */ volatile int interface_interval = 300; /* update interface every 5 minutes as default */ /* * Alarm flag. The mainline code imports this. */ volatile int alarm_flag; /* * The counters and timeouts */ static u_long adjust_timer; /* second timer */ static u_long stats_timer; /* stats timer */ static u_long huffpuff_timer; /* huff-n'-puff timer */ static u_long interface_timer; /* interface update timer */ #ifdef OPENSSL static u_long revoke_timer; /* keys revoke timer */ u_long sys_revoke = KEY_REVOKE; /* keys revoke timeout */ static u_long keys_timer; /* session key timer */ u_long sys_automax = NTP_AUTOMAX; /* session key timeout */ #endif /* OPENSSL */ /* * Statistics counter for the interested. */ volatile u_long alarm_overflow; #define MINUTE 60 #define HOUR (60 * MINUTE) #define DAY (24 * HOUR) u_long current_time; /* seconds since startup */ /* * Stats. Number of overflows and number of calls to transmit(). */ u_long timer_timereset; u_long timer_overflows; u_long timer_xmtcalls; #if defined(VMS) static int vmstimer[2]; /* time for next timer AST */ static int vmsinc[2]; /* timer increment */ #endif /* VMS */ #if defined SYS_WINNT static HANDLE WaitableTimerHandle = NULL; #else static RETSIGTYPE alarming (int); #endif /* SYS_WINNT */ #if !defined(VMS) # if !defined SYS_WINNT || defined(SYS_CYGWIN32) # ifndef HAVE_TIMER_SETTIME struct itimerval itimer; # else static timer_t ntpd_timerid; struct itimerspec itimer; # endif /* HAVE_TIMER_SETTIME */ # endif /* SYS_WINNT */ #endif /* VMS */ /* * reinit_timer - reinitialize interval timer. */ void reinit_timer(void) { #if !defined(SYS_WINNT) && !defined(VMS) # if defined(HAVE_TIMER_CREATE) && defined(HAVE_TIMER_SETTIME) timer_gettime(ntpd_timerid, &itimer); if (itimer.it_value.tv_sec < 0 || itimer.it_value.tv_sec > (1< (1<next; if (peer->flags & FLAG_REFCLOCK) refclock_timer(peer); } } #endif /* REFCLOCK */ } /* * Now dispatch any peers whose event timer has expired. Be * careful here, since the peer structure might go away as the * result of the call. */ for (n = 0; n < NTP_HASH_SIZE; n++) { for (peer = peer_hash[n]; peer != 0; peer = next_peer) { next_peer = peer->next; if (peer->action && peer->nextaction <= current_time) peer->action(peer); if (peer->nextdate <= current_time) { #ifdef REFCLOCK if (peer->flags & FLAG_REFCLOCK) refclock_transmit(peer); else transmit(peer); #else /* REFCLOCK */ transmit(peer); #endif /* REFCLOCK */ } } } /* * Leapseconds. When the time remaining decrements to zero, * increment the TAI offset. If the kernel code is not available * or disabled, Do the leap crudely. There are of course races * here, cheerfully ignored. */ if (leap_sec > 0) { leap_sec--; if (leap_sec == 0) { sys_leap = LEAP_NOWARNING; if (sys_tai > 0) sys_tai++; #ifdef KERNEL_PLL if (!(pll_control && kern_enable)) step_systime(-1.0); #else /* KERNEL_PLL */ step_systime(-1.0); #endif /* KERNEL_PLL */ get_systime(&now); msyslog(LOG_NOTICE, "timer: leap second at %u TAI %d s", now.l_ui); } } /* * Update huff-n'-puff filter. */ if (huffpuff_timer <= current_time) { huffpuff_timer += HUFFPUFF; huffpuff(); } #ifdef OPENSSL /* * Garbage collect expired keys. */ if (keys_timer <= current_time) { keys_timer += sys_automax; auth_agekeys(); } /* * Garbage collect key list and generate new private value. The * timer runs only after initial synchronization and fires about * once per day. */ if (revoke_timer <= current_time && sys_leap != LEAP_NOTINSYNC) { revoke_timer += sys_revoke; expire_all(); } #endif /* OPENSSL */ /* * Interface update timer */ if (interface_interval && interface_timer <= current_time) { timer_interfacetimeout(current_time + interface_interval); #ifdef DEBUG if (debug > 1) printf("timer: interface update\n"); #endif interface_update(NULL, NULL); } /* * Finally, write stats once per hour. */ if (stats_timer <= current_time) { stats_timer += HOUR; write_stats(); } } #ifndef SYS_WINNT /* * alarming - tell the world we've been alarmed */ static RETSIGTYPE alarming( int sig ) { #if !defined(VMS) if (initializing) return; if (alarm_flag) alarm_overflow++; else alarm_flag++; #else /* VMS AST routine */ if (!initializing) { if (alarm_flag) alarm_overflow++; else alarm_flag = 1; /* increment is no good */ } lib$addx(&vmsinc,&vmstimer,&vmstimer); sys$setimr(0,&vmstimer,alarming,alarming,0); #endif /* VMS */ } #endif /* SYS_WINNT */ void timer_interfacetimeout(u_long timeout) { interface_timer = timeout; } /* * timer_clr_stats - clear timer module stat counters */ void timer_clr_stats(void) { timer_overflows = 0; timer_xmtcalls = 0; timer_timereset = current_time; }