Annotation of embedaddon/ntp/ntpd/ntp_timer.c, revision 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>