Annotation of embedaddon/ntp/ntpd/ntp_timer.c, revision 1.1.1.1

1.1       misho       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>