Annotation of embedaddon/mrouted/main.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * The mrouted program is covered by the license in the accompanying file
                      3:  * named "LICENSE".  Use of the mrouted program represents acceptance of
                      4:  * the terms and conditions listed in that file.
                      5:  *
                      6:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
                      7:  * Leland Stanford Junior University.
                      8:  */
                      9: 
                     10: /*
                     11:  * Written by Steve Deering, Stanford University, February 1989.
                     12:  *
                     13:  * (An earlier version of DVMRP was implemented by David Waitzman of
                     14:  *  BBN STC by extending Berkeley's routed program.  Some of Waitzman's
                     15:  *  extensions have been incorporated into mrouted, but none of the
                     16:  *  original routed code has been adopted.)
                     17:  */
                     18: 
                     19: #include "defs.h"
                     20: #include <err.h>
                     21: #include <getopt.h>
                     22: #include <paths.h>
                     23: #include <fcntl.h>
                     24: #include <stdarg.h>
                     25: #include <sys/stat.h>
                     26: 
                     27: #ifdef SNMP
                     28: #include "snmp.h"
                     29: #endif
                     30: 
                     31: extern char *configfilename;
                     32: char versionstring[MAX_VERSION_LEN];
                     33: 
                     34: static const char dumpfilename[] = _PATH_MROUTED_DUMP;
                     35: static const char cachefilename[] = _PATH_MROUTED_CACHE;
                     36: static const char genidfilename[] = _PATH_MROUTED_GENID;
                     37: 
                     38: static int haveterminal = 1;
                     39: int did_final_init = 0;
                     40: 
                     41: static int sighandled = 0;
                     42: #define        GOT_SIGINT      0x01
                     43: #define        GOT_SIGHUP      0x02
                     44: #define        GOT_SIGUSR1     0x04
                     45: #define        GOT_SIGUSR2     0x08
                     46: 
                     47: int cache_lifetime     = DEFAULT_CACHE_LIFETIME;
                     48: int prune_lifetime     = AVERAGE_PRUNE_LIFETIME;
                     49: 
                     50: int debug = 0;
                     51: extern char *__progname;
                     52: time_t mrouted_init_time;
                     53: 
                     54: #ifdef SNMP
                     55: #define NHANDLERS      34
                     56: #else
                     57: #define NHANDLERS      2
                     58: #endif
                     59: 
                     60: static struct ihandler {
                     61:     int fd;                    /* File descriptor               */
                     62:     ihfunc_t func;             /* Function to call with &fd_set */
                     63: } ihandlers[NHANDLERS];
                     64: static int nhandlers = 0;
                     65: 
                     66: static struct debugname {
                     67:     char       *name;
                     68:     u_int32_t   level;
                     69:     size_t      nchars;
                     70: } debugnames[] = {
                     71:     {  "packet",       DEBUG_PKT,      2       },
                     72:     {  "pkt",          DEBUG_PKT,      3       },
                     73:     {  "pruning",      DEBUG_PRUNE,    1       },
                     74:     {  "prunes",       DEBUG_PRUNE,    1       },
                     75:     {  "routing",      DEBUG_ROUTE,    1       },
                     76:     {  "routes",       DEBUG_ROUTE,    1       },
                     77:     {   "route_detail",        DEBUG_RTDETAIL, 6       },
                     78:     {   "rtdetail",    DEBUG_RTDETAIL, 2       },
                     79:     {  "peers",        DEBUG_PEER,     2       },
                     80:     {  "neighbors",    DEBUG_PEER,     1       },
                     81:     {  "cache",        DEBUG_CACHE,    1       },
                     82:     {  "timeout",      DEBUG_TIMEOUT,  1       },
                     83:     {  "callout",      DEBUG_TIMEOUT,  2       },
                     84:     {  "interface",    DEBUG_IF,       2       },
                     85:     {  "vif",          DEBUG_IF,       1       },
                     86:     {  "membership",   DEBUG_MEMBER,   1       },
                     87:     {  "groups",       DEBUG_MEMBER,   1       },
                     88:     {  "traceroute",   DEBUG_TRACE,    2       },
                     89:     {  "mtrace",       DEBUG_TRACE,    2       },
                     90:     {  "igmp",         DEBUG_IGMP,     1       },
                     91:     {  "icmp",         DEBUG_ICMP,     2       },
                     92:     {  "rsrr",         DEBUG_RSRR,     2       },
                     93:     {  "3",            0xffffffff,     1       }       /* compat. */
                     94: };
                     95: 
                     96: /*
                     97:  * Forward declarations.
                     98:  */
                     99: static void final_init(void *);
                    100: static void fasttimer(void*);
                    101: static void timer(void*);
                    102: #if UNUSED_CODE
                    103: static void dump(void);
                    104: #endif
                    105: static void dump_version(FILE *);
                    106: static void fdump(void);
                    107: static void cdump(void);
                    108: static void restart(void);
                    109: static void handler(int);
                    110: static void cleanup(void);
                    111: static void resetlogging(void *);
                    112: 
                    113: int register_input_handler(int fd, ihfunc_t func)
                    114: {
                    115:     if (nhandlers >= NHANDLERS)
                    116:        return -1;
                    117: 
                    118:     ihandlers[nhandlers].fd = fd;
                    119:     ihandlers[nhandlers++].func = func;
                    120: 
                    121:     return 0;
                    122: }
                    123: 
                    124: static void do_randomize(void)
                    125: {
                    126: #define rol32(data,shift) ((data) >> (shift)) | ((data) << (32 - (shift)))
                    127:    int fd;
                    128:    unsigned int seed;
                    129: 
                    130:    /* Setup a fallback seed based on quasi random. */
                    131: #ifdef SYSV
                    132:    seed = time(NULL);
                    133: #else
                    134:    seed = time(NULL) ^ gethostid();
                    135: #endif
                    136:    seed = rol32(seed, seed);
                    137: 
                    138:    fd = open("/dev/urandom", O_RDONLY);
                    139:    if (fd >= 0) {
                    140:        if (-1 == read(fd, &seed, sizeof(seed)))
                    141:           warn("Failed reading entropy from /dev/urandom");
                    142:        close(fd);
                    143:   }
                    144: 
                    145: #ifdef SYSV
                    146:    srand48(seed);
                    147: #else
                    148:    srandom(seed);
                    149: #endif
                    150: }
                    151: 
                    152: /* Figure out the PID of a running daemon. */
                    153: static pid_t daemon_pid(void)
                    154: {
                    155:     int result;
                    156:     char *path = NULL;
                    157:     FILE *fp;
                    158:     pid_t pid = -1;
                    159: 
                    160:     result = asprintf(&path, "%s%s.pid", _PATH_VARRUN, __progname);
                    161:     if (result == -1 || path == NULL)
                    162:        return -1;
                    163: 
                    164:     fp = fopen(path, "r");
                    165:     if (!fp) {
                    166:        free(path);
                    167:        return -1;
                    168:     }
                    169: 
                    170:     result = fscanf(fp, "%d", &pid);
                    171:     fclose(fp);
                    172:     free(path);
                    173: 
                    174:     return pid;
                    175: }
                    176: 
                    177: /* Send signal to running daemon and the show resulting file. */
                    178: static void killshow(int signo, char *file)
                    179: {
                    180:     pid_t pid = daemon_pid();
                    181:     char buf[100];
                    182: 
                    183:     if (pid > 0) {
                    184:        if (file)
                    185:            remove(file);
                    186:        kill(pid, signo);
                    187:        if (file) {
                    188:            int result;
                    189: 
                    190:            usleep(200);
                    191:            snprintf(buf, sizeof(buf), "cat %s", file);
                    192:            result = system(buf);
                    193:        }
                    194:     }
                    195: }
                    196: 
                    197: static void usage(void)
                    198: {
                    199:     size_t i, j, k;
                    200:     struct debugname *d;
                    201: 
                    202:     fprintf(stderr, "Usage: %s [-fhpv] [-c file] [-d [level[,level...]]]\n\n", __progname);
                    203:     fputs("  -c, --config=FILE    Configuration file to use, default /etc/mrouted.conf\n", stderr);
                    204:     fputs("  -d, --debug[=LEVEL]  Debug level, see below for valid levels\n", stderr);
                    205:     fputs("  -f, --foreground     Run in foreground, do not detach from calling terminal\n", stderr);
                    206:     fputs("  -h, --help           Show this help text\n", stderr);
                    207:     fputs("  -p                   Disable pruning.  Deprecated, compatibility option\n", stderr);
                    208:     fputs("  -r, --show-routes    Show state of VIFs and multicast routing tables\n", stderr);
                    209:     fprintf(stderr, "  -v, --version        Show %s version\n", __progname);
                    210:     fputs("\n", stderr);
                    211: 
                    212:     j = 0xffffffff;
                    213:     k = 0;
                    214:     fputs("Valid debug levels:\n  ", stderr);
                    215:     for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) {
                    216:        if ((j & d->level) == d->level) {
                    217:            if (k++)
                    218:                fputs(", ", stderr);
                    219:            if (!(k % 6))
                    220:                fputs("\n  ", stderr);
                    221: 
                    222:            fputs(d->name, stderr);
                    223:            j &= ~d->level;
                    224:        }
                    225:     }
                    226:     fputc('\n', stderr);
                    227: 
                    228:     exit(1);
                    229: }
                    230: 
                    231: int main(int argc, char *argv[])
                    232: {
                    233:     register int recvlen;
                    234:     socklen_t dummy;
                    235:     FILE *fp;
                    236:     struct timeval tv, difftime, curtime, lasttime, *timeout;
                    237:     u_int32 prev_genid;
                    238:     int vers, foreground = 0;
                    239:     fd_set rfds, readers;
                    240:     int nfds, n, i, secs, ch;
                    241:     extern char todaysversion[];
                    242:     struct sigaction sa;
                    243: #ifdef SNMP
                    244:     const char *errstr;
                    245:     struct timeval  timeout, *tvp = &timeout;
                    246:     struct timeval  sched, *svp = &sched, now, *nvp = &now;
                    247:     int index, block;
                    248: #endif
                    249:     struct option long_options[] = {
                    250:        {"config", 1, 0, 'c'},
                    251:        {"debug", 2, 0, 'd'},
                    252:        {"foreground", 0, 0, 'f'},
                    253:        {"help", 0, 0, 'h'},
                    254:        {"version", 0, 0, 'v'},
                    255:        {"show-routes", 0, 0, 'r'},
                    256:        {0, 0, 0, 0}
                    257:     };
                    258: 
                    259:     snprintf(versionstring, sizeof(versionstring), "mrouted version %s", todaysversion);
                    260: 
                    261:     while ((ch = getopt_long(argc, argv, "c:d::fhpP::rv", long_options, NULL)) != EOF) {
                    262:        switch (ch) {
                    263:            case 'c':
                    264:                configfilename = optarg;
                    265:                break;
                    266: 
                    267:            case 'd':
                    268:                if (!optarg)
                    269:                    debug = DEFAULT_DEBUG;
                    270:                else {
                    271:                    char *p,*q;
                    272:                    size_t i, len;
                    273:                    struct debugname *d;
                    274: 
                    275:                    debug = 0;
                    276:                    p = optarg; q = NULL;
                    277:                    while (p) {
                    278:                        q = strchr(p, ',');
                    279:                        if (q)
                    280:                            *q++ = '\0';
                    281:                        len = strlen(p);
                    282:                        for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++)
                    283:                            if (len >= d->nchars && strncmp(d->name, p, len) == 0)
                    284:                                break;
                    285: 
                    286:                        if (i == ARRAY_LEN(debugnames))
                    287:                            usage();
                    288: 
                    289:                        debug |= d->level;
                    290:                        p = q;
                    291:                    }
                    292:                }
                    293:                break;
                    294: 
                    295:            case 'f':
                    296:                foreground = 1;
                    297:                break;
                    298: 
                    299:            case 'h':
                    300:                usage();
                    301:                break;
                    302: 
                    303:            case 'p':
                    304:                warnx("Disabling pruning is no longer supported.");
                    305:                break;
                    306: 
                    307:            case 'P':
                    308: #ifdef SNMP
                    309:                if (!optarg)
                    310:                    dest_port = DEFAULT_PORT;
                    311:                else {
                    312:                    dest_port = strtonum(optarg, 1, 65535, &errstr);
                    313:                    if (errstr) {
                    314:                        warnx("destination port %s", errstr);
                    315:                        dest_port = DEFAULT_PORT;
                    316:                    }
                    317:                }
                    318: #else
                    319:                warnx("SNMP support missing, please feel free to submit a patch.");
                    320: #endif
                    321:                break;
                    322: 
                    323:            case 'r':
                    324:                killshow(SIGUSR1, _PATH_MROUTED_DUMP);
                    325:                return 0;
                    326: 
                    327:            case 'v':
                    328:                printf("%s\n", versionstring);
                    329:                return 0;
                    330: 
                    331:            default:
                    332:                usage();
                    333:        }
                    334:     }
                    335: 
                    336:     argc -= optind;
                    337:     argv += optind;
                    338: 
                    339:     if (argc > 0)
                    340:        usage();
                    341: 
                    342:     if (geteuid() != 0) {
                    343:        fprintf(stderr, "%s: must be root\n", __progname);
                    344:        exit(1);
                    345:     }
                    346:     setlinebuf(stderr);
                    347: 
                    348:     if (debug != 0) {
                    349:        struct debugname *d;
                    350:        char c;
                    351:        int tmpd = debug;
                    352: 
                    353:        fprintf(stderr, "debug level 0x%x ", debug);
                    354:        c = '(';
                    355:        for (d = debugnames; d < debugnames + ARRAY_LEN(debugnames); d++) {
                    356:            if ((tmpd & d->level) == d->level) {
                    357:                tmpd &= ~d->level;
                    358:                fprintf(stderr, "%c%s", c, d->name);
                    359:                c = ',';
                    360:            }
                    361:        }
                    362:        fprintf(stderr, ")\n");
                    363:     }
                    364: 
                    365:     /*
                    366:      * Create directory for runtime files
                    367:      */
                    368:     mkdir(_PATH_MROUTED_RUNDIR, 0755);
                    369: 
                    370:     /*
                    371:      * Setup logging
                    372:      */
                    373: #ifdef LOG_DAEMON
                    374:     (void)openlog("mrouted", LOG_PID, LOG_DAEMON);
                    375:     (void)setlogmask(LOG_UPTO(LOG_NOTICE));
                    376: #else
                    377:     (void)openlog("mrouted", LOG_PID);
                    378: #endif
                    379: 
                    380:     logit(LOG_DEBUG, 0, "%s starting", versionstring);
                    381: 
                    382:     do_randomize();
                    383: 
                    384:     /*
                    385:      * Get generation id
                    386:      */
                    387:     gettimeofday(&tv, 0);
                    388:     dvmrp_genid = tv.tv_sec;
                    389: 
                    390:     fp = fopen(genidfilename, "r");
                    391:     if (fp != NULL) {
                    392:        int ret = fscanf(fp, "%u", &prev_genid);
                    393:        if (ret == 1 && prev_genid == dvmrp_genid)
                    394:            dvmrp_genid++;
                    395:        (void) fclose(fp);
                    396:     }
                    397: 
                    398:     fp = fopen(genidfilename, "w");
                    399:     if (fp != NULL) {
                    400:        fprintf(fp, "%d", dvmrp_genid);
                    401:        (void) fclose(fp);
                    402:     }
                    403: 
                    404:     /* Start up the log rate-limiter */
                    405:     resetlogging(NULL);
                    406: 
                    407:     callout_init();
                    408:     init_igmp();
                    409:     init_icmp();
                    410:     init_ipip();
                    411:     init_routes();
                    412:     init_ktable();
                    413: #ifndef OLD_KERNEL
                    414:     /*
                    415:      * Unfortunately, you can't k_get_version() unless you've
                    416:      * k_init_dvmrp()'d.  Now that we want to move the
                    417:      * k_init_dvmrp() to later in the initialization sequence,
                    418:      * we have to do the disgusting hack of initializing,
                    419:      * getting the version, then stopping the kernel multicast
                    420:      * forwarding.
                    421:      */
                    422:     k_init_dvmrp();
                    423:     vers = k_get_version();
                    424:     k_stop_dvmrp();
                    425:     /*XXX
                    426:      * This function must change whenever the kernel version changes
                    427:      */
                    428:     if ((((vers >> 8) & 0xff) != 3) ||
                    429:         ((vers & 0xff) != 5))
                    430:        logit(LOG_ERR, 0, "kernel (v%d.%d)/mrouted (v%d.%d) version mismatch",
                    431:                (vers >> 8) & 0xff, vers & 0xff,
                    432:                PROTOCOL_VERSION, MROUTED_VERSION);
                    433: #endif
                    434: 
                    435: #ifdef SNMP
                    436:     if (i = snmp_init())
                    437:        return i;
                    438: 
                    439:     gettimeofday(nvp, 0);
                    440:     if (nvp->tv_usec < 500000L){
                    441:            svp->tv_usec = nvp->tv_usec + 500000L;
                    442:            svp->tv_sec = nvp->tv_sec;
                    443:     } else {
                    444:            svp->tv_usec = nvp->tv_usec - 500000L;
                    445:            svp->tv_sec = nvp->tv_sec + 1;
                    446:     }
                    447: #endif /* SNMP */
                    448: 
                    449:     init_vifs();
                    450: 
                    451: #ifdef RSRR
                    452:     rsrr_init();
                    453: #endif /* RSRR */
                    454: 
                    455:     sa.sa_handler = handler;
                    456:     sa.sa_flags = 0;   /* Interrupt system calls */
                    457:     sigemptyset(&sa.sa_mask);
                    458:     sigaction(SIGHUP, &sa, NULL);
                    459:     sigaction(SIGTERM, &sa, NULL);
                    460:     sigaction(SIGINT, &sa, NULL);
                    461:     sigaction(SIGUSR1, &sa, NULL);
                    462:     sigaction(SIGUSR2, &sa, NULL);
                    463: 
                    464:     FD_ZERO(&readers);
                    465:     if (igmp_socket >= (int)FD_SETSIZE)
                    466:        logit(LOG_ERR, 0, "Descriptor too big");
                    467:     FD_SET(igmp_socket, &readers);
                    468:     nfds = igmp_socket + 1;
                    469:     for (i = 0; i < nhandlers; i++) {
                    470:        if (ihandlers[i].fd >= (int)FD_SETSIZE)
                    471:            logit(LOG_ERR, 0, "Descriptor too big");
                    472:        FD_SET(ihandlers[i].fd, &readers);
                    473:        if (ihandlers[i].fd >= nfds)
                    474:            nfds = ihandlers[i].fd + 1;
                    475:     }
                    476: 
                    477:     IF_DEBUG(DEBUG_IF)
                    478:        dump_vifs(stderr);
                    479:     IF_DEBUG(DEBUG_ROUTE)
                    480:        dump_routes(stderr);
                    481: 
                    482:     /* schedule first timer interrupt */
                    483:     timer_setTimer(1, fasttimer, NULL);
                    484:     timer_setTimer(TIMER_INTERVAL, timer, NULL);
                    485: 
                    486:     if (!debug && !foreground) {
                    487:        /* Detach from the terminal */
                    488:        haveterminal = 0;
                    489:        if (fork())
                    490:            exit(0);
                    491:        (void)close(0);
                    492:        (void)close(1);
                    493:        (void)close(2);
                    494:        (void)open("/", 0);
                    495:        (void)dup2(0, 1);
                    496:        (void)dup2(0, 2);
                    497: #ifdef SYSV
                    498:        (void)setpgrp();
                    499: #else
                    500: #ifdef TIOCNOTTY
                    501:        n = open("/dev/tty", 2);
                    502:        if (n >= 0) {
                    503:            (void)ioctl(n, TIOCNOTTY, (char *)0);
                    504:            (void)close(n);
                    505:        }
                    506: #else
                    507:        if (setsid() < 0)
                    508:            perror("setsid");
                    509: #endif
                    510: #endif
                    511:     }
                    512: 
                    513:     if (pidfile(NULL)) {
                    514:        warn("Cannot create pidfile");
                    515:     }
                    516: 
                    517:     /* XXX HACK
                    518:      * This will cause black holes for the first few seconds after startup,
                    519:      * since we are exchanging routes but not actually forwarding.
                    520:      * However, it eliminates much of the startup transient.
                    521:      *
                    522:      * It's possible that we can set a flag which says not to report any
                    523:      * routes (just accept reports) until this timer fires, and then
                    524:      * do a report_to_all_neighbors(ALL_ROUTES) immediately before
                    525:      * turning on DVMRP.
                    526:      */
                    527:     timer_setTimer(10, final_init, NULL);
                    528: 
                    529:     /*
                    530:      * Main receive loop.
                    531:      */
                    532:     dummy = 0;
                    533:     difftime.tv_usec = 0;
                    534:     gettimeofday(&curtime, NULL);
                    535:     lasttime = curtime;
                    536:     for(;;) {
                    537:        memmove ((char *)&rfds, (char *)&readers, sizeof(rfds));
                    538:        secs = timer_nextTimer();
                    539:        if (secs == -1)
                    540:            timeout = NULL;
                    541:        else {
                    542:            timeout = &tv;
                    543:            timeout->tv_sec = secs;
                    544:            timeout->tv_usec = 0;
                    545:        }
                    546: #ifdef SNMP
                    547:    THIS IS BROKEN
                    548:    if (nvp->tv_sec > svp->tv_sec
                    549:        || (nvp->tv_sec == svp->tv_sec && nvp->tv_usec > svp->tv_usec)){
                    550:        alarmTimer(nvp);
                    551:        eventTimer(nvp);
                    552:        if (nvp->tv_usec < 500000L){
                    553:       svp->tv_usec = nvp->tv_usec + 500000L;
                    554:       svp->tv_sec = nvp->tv_sec;
                    555:        } else {
                    556:       svp->tv_usec = nvp->tv_usec - 500000L;
                    557:       svp->tv_sec = nvp->tv_sec + 1;
                    558:        }
                    559:    }
                    560: 
                    561:        tvp =  &timeout;
                    562:        tvp->tv_sec = 0;
                    563:        tvp->tv_usec = 500000L;
                    564: 
                    565:        block = 0;
                    566:        snmp_select_info(&nfds, &rfds, tvp, &block);
                    567:        if (block == 1)
                    568:                tvp = NULL; /* block without timeout */
                    569:        if ((n = select(nfds, &rfds, NULL, NULL, tvp)) < 0)
                    570: #endif
                    571:        if (sighandled) {
                    572:            if (sighandled & GOT_SIGINT) {
                    573:                sighandled &= ~GOT_SIGINT;
                    574:                break;
                    575:            }
                    576:            if (sighandled & GOT_SIGHUP) {
                    577:                sighandled &= ~GOT_SIGHUP;
                    578:                restart();
                    579:            }
                    580:            if (sighandled & GOT_SIGUSR1) {
                    581:                sighandled &= ~GOT_SIGUSR1;
                    582:                fdump();
                    583:            }
                    584:            if (sighandled & GOT_SIGUSR2) {
                    585:                sighandled &= ~GOT_SIGUSR2;
                    586:                cdump();
                    587:            }
                    588:        }
                    589:        if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) {
                    590:            if (errno != EINTR)
                    591:                logit(LOG_WARNING, errno, "select failed");
                    592:            continue;
                    593:        }
                    594: 
                    595:        if (n > 0) {
                    596:            if (FD_ISSET(igmp_socket, &rfds)) {
                    597:                recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy);
                    598:                if (recvlen < 0) {
                    599:                    if (errno != EINTR) logit(LOG_ERR, errno, "recvfrom");
                    600:                    continue;
                    601:                }
                    602:                accept_igmp(recvlen);
                    603:            }
                    604: 
                    605:            for (i = 0; i < nhandlers; i++) {
                    606:                if (FD_ISSET(ihandlers[i].fd, &rfds)) {
                    607:                    (*ihandlers[i].func)(ihandlers[i].fd, &rfds);
                    608:                }
                    609:            }
                    610:        }
                    611: 
                    612: #ifdef SNMP
                    613:        THIS IS BROKEN
                    614:        snmp_read(&rfds);
                    615:        snmp_timeout(); /* poll */
                    616: #endif
                    617:        /*
                    618:         * Handle timeout queue.
                    619:         *
                    620:         * If select + packet processing took more than 1 second,
                    621:         * or if there is a timeout pending, age the timeout queue.
                    622:         *
                    623:         * If not, collect usec in difftime to make sure that the
                    624:         * time doesn't drift too badly.
                    625:         *
                    626:         * If the timeout handlers took more than 1 second,
                    627:         * age the timeout queue again.  XXX This introduces the
                    628:         * potential for infinite loops!
                    629:         */
                    630:        do {
                    631:            /*
                    632:             * If the select timed out, then there's no other
                    633:             * activity to account for and we don't need to
                    634:             * call gettimeofday.
                    635:             */
                    636:            if (n == 0) {
                    637:                curtime.tv_sec = lasttime.tv_sec + secs;
                    638:                curtime.tv_usec = lasttime.tv_usec;
                    639:                n = -1; /* don't do this next time through the loop */
                    640:            } else
                    641:                gettimeofday(&curtime, NULL);
                    642:            difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
                    643:            difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
                    644:            while (difftime.tv_usec > 1000000) {
                    645:                difftime.tv_sec++;
                    646:                difftime.tv_usec -= 1000000;
                    647:            }
                    648:            if (difftime.tv_usec < 0) {
                    649:                difftime.tv_sec--;
                    650:                difftime.tv_usec += 1000000;
                    651:            }
                    652:            lasttime = curtime;
                    653:            if (secs == 0 || difftime.tv_sec > 0)
                    654:                age_callout_queue(difftime.tv_sec);
                    655:            secs = -1;
                    656:        } while (difftime.tv_sec > 0);
                    657:     }
                    658:     logit(LOG_NOTICE, 0, "%s exiting", versionstring);
                    659:     cleanup();
                    660:     exit(0);
                    661: }
                    662: 
                    663: static void final_init(void *i)
                    664: {
                    665:     char *s = (char *)i;
                    666: 
                    667:     logit(LOG_NOTICE, 0, "%s%s", versionstring, s ? s : "");
                    668:     if (s)
                    669:        free(s);
                    670: 
                    671:     k_init_dvmrp();            /* enable DVMRP routing in kernel */
                    672: 
                    673:     /*
                    674:      * Install the vifs in the kernel as late as possible in the
                    675:      * initialization sequence.
                    676:      */
                    677:     init_installvifs();
                    678: 
                    679:     time(&mrouted_init_time);
                    680:     did_final_init = 1;
                    681: }
                    682: 
                    683: /*
                    684:  * routine invoked every second.  Its main goal is to cycle through
                    685:  * the routing table and send partial updates to all neighbors at a
                    686:  * rate that will cause the entire table to be sent in ROUTE_REPORT_INTERVAL
                    687:  * seconds.  Also, every TIMER_INTERVAL seconds it calls timer() to
                    688:  * do all the other time-based processing.
                    689:  */
                    690: static void fasttimer(void UNUSED *arg)
                    691: {
                    692:     static unsigned int tlast;
                    693:     static unsigned int nsent;
                    694:     unsigned int t = tlast + 1;
                    695:     int n;
                    696: 
                    697:     /*
                    698:      * if we're in the last second, send everything that's left.
                    699:      * otherwise send at least the fraction we should have sent by now.
                    700:      */
                    701:     if (t >= ROUTE_REPORT_INTERVAL) {
                    702:        register int nleft = nroutes - nsent;
                    703:        while (nleft > 0) {
                    704:            if ((n = report_next_chunk()) <= 0)
                    705:                break;
                    706:            nleft -= n;
                    707:        }
                    708:        tlast = 0;
                    709:        nsent = 0;
                    710:     } else {
                    711:        register unsigned int ncum = nroutes * t / ROUTE_REPORT_INTERVAL;
                    712:        while (nsent < ncum) {
                    713:            if ((n = report_next_chunk()) <= 0)
                    714:                break;
                    715:            nsent += n;
                    716:        }
                    717:        tlast = t;
                    718:     }
                    719: 
                    720:     timer_setTimer(1, fasttimer, NULL);
                    721: }
                    722: 
                    723: /*
                    724:  * The 'virtual_time' variable is initialized to a value that will cause the
                    725:  * first invocation of timer() to send a probe or route report to all vifs
                    726:  * and send group membership queries to all subnets for which this router is
                    727:  * querier.  This first invocation occurs approximately TIMER_INTERVAL seconds
                    728:  * after the router starts up.   Note that probes for neighbors and queries
                    729:  * for group memberships are also sent at start-up time, as part of initial-
                    730:  * ization.  This repetition after a short interval is desirable for quickly
                    731:  * building up topology and membership information in the presence of possible
                    732:  * packet loss.
                    733:  *
                    734:  * 'virtual_time' advances at a rate that is only a crude approximation of
                    735:  * real time, because it does not take into account any time spent processing,
                    736:  * and because the timer intervals are sometimes shrunk by a random amount to
                    737:  * avoid unwanted synchronization with other routers.
                    738:  */
                    739: 
                    740: u_long virtual_time = 0;
                    741: 
                    742: 
                    743: /*
                    744:  * Timer routine.  Performs periodic neighbor probing, route reporting, and
                    745:  * group querying duties, and drives various timers in routing entries and
                    746:  * virtual interface data structures.
                    747:  */
                    748: static void timer(void UNUSED *arg)
                    749: {
                    750:     age_routes();      /* Advance the timers in the route entries     */
                    751:     age_vifs();                /* Advance the timers for neighbors */
                    752:     age_table_entry(); /* Advance the timers for the cache entries */
                    753: 
                    754:     if (virtual_time % IGMP_QUERY_INTERVAL == 0) {
                    755:        /*
                    756:         * Time to query the local group memberships on all subnets
                    757:         * for which this router is the elected querier.
                    758:         */
                    759:        query_groups();
                    760:     }
                    761: 
                    762:     if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) {
                    763:        /*
                    764:         * Time to send a probe on all vifs from which no neighbors have
                    765:         * been heard.  Also, check if any inoperative interfaces have now
                    766:         * come up.  (If they have, they will also be probed as part of
                    767:         * their initialization.)
                    768:         */
                    769:        probe_for_neighbors();
                    770: 
                    771:        if (vifs_down)
                    772:            check_vif_state();
                    773:     }
                    774: 
                    775:     delay_change_reports = FALSE;
                    776:     if (routes_changed) {
                    777:        /*
                    778:         * Some routes have changed since the last timer interrupt, but
                    779:         * have not been reported yet.  Report the changed routes to all
                    780:         * neighbors.
                    781:         */
                    782:        report_to_all_neighbors(CHANGED_ROUTES);
                    783:     }
                    784: 
                    785: #ifdef SNMP
                    786:     sync_timer();
                    787: #endif
                    788: 
                    789:     /*
                    790:      * Advance virtual time
                    791:      */
                    792:     virtual_time += TIMER_INTERVAL;
                    793:     timer_setTimer(TIMER_INTERVAL, timer, NULL);
                    794: }
                    795: 
                    796: 
                    797: static void cleanup(void)
                    798: {
                    799:     static int in_cleanup = 0;
                    800: 
                    801:     if (!in_cleanup) {
                    802:        in_cleanup++;
                    803: #ifdef RSRR
                    804:        rsrr_clean();
                    805: #endif /* RSRR */
                    806:        expire_all_routes();
                    807:        report_to_all_neighbors(ALL_ROUTES);
                    808:        if (did_final_init)
                    809:            k_stop_dvmrp();
                    810:     }
                    811: }
                    812: 
                    813: /*
                    814:  * Signal handler.  Take note of the fact that the signal arrived
                    815:  * so that the main loop can take care of it.
                    816:  */
                    817: static void handler(int sig)
                    818: {
                    819:     switch (sig) {
                    820:        case SIGINT:
                    821:        case SIGTERM:
                    822:            sighandled |= GOT_SIGINT;
                    823:            break;
                    824: 
                    825:        case SIGHUP:
                    826:            sighandled |= GOT_SIGHUP;
                    827:            break;
                    828: 
                    829:        case SIGUSR1:
                    830:            sighandled |= GOT_SIGUSR1;
                    831:            break;
                    832: 
                    833:        case SIGUSR2:
                    834:            sighandled |= GOT_SIGUSR2;
                    835:            break;
                    836:     }
                    837: }
                    838: 
                    839: #if UNUSED_CODE
                    840: /*
                    841:  * Dump internal data structures to stderr.
                    842:  */
                    843: static void dump(void)
                    844: {
                    845:     dump_vifs(stderr);
                    846:     dump_routes(stderr);
                    847: }
                    848: #endif
                    849: 
                    850: static void dump_version(FILE *fp)
                    851: {
                    852:     time_t t;
                    853: 
                    854:     time(&t);
                    855:     fprintf(fp, "%s ", versionstring);
                    856:     if (did_final_init)
                    857:            fprintf(fp, "up %s",
                    858:                    scaletime(t - mrouted_init_time));
                    859:     else
                    860:            fprintf(fp, "(not yet initialized)");
                    861:     fprintf(fp, " %s\n", ctime(&t));
                    862: }
                    863: 
                    864: /*
                    865:  * Dump internal data structures to a file.
                    866:  */
                    867: static void fdump(void)
                    868: {
                    869:     FILE *fp;
                    870: 
                    871:     fp = fopen(dumpfilename, "w");
                    872:     if (fp != NULL) {
                    873:        dump_version(fp);
                    874:        dump_vifs(fp);
                    875:        dump_routes(fp);
                    876:        (void) fclose(fp);
                    877:     }
                    878: }
                    879: 
                    880: 
                    881: /*
                    882:  * Dump local cache contents to a file.
                    883:  */
                    884: static void cdump(void)
                    885: {
                    886:     FILE *fp;
                    887: 
                    888:     fp = fopen(cachefilename, "w");
                    889:     if (fp != NULL) {
                    890:        dump_version(fp);
                    891:        dump_cache(fp);
                    892:        (void) fclose(fp);
                    893:     }
                    894: }
                    895: 
                    896: 
                    897: /*
                    898:  * Restart mrouted
                    899:  */
                    900: static void restart(void)
                    901: {
                    902:     char *s;
                    903: 
                    904:     s = strdup (" restart");
                    905:     if (s == NULL)
                    906:        logit(LOG_ERR, 0, "out of memory");
                    907: 
                    908:     /*
                    909:      * reset all the entries
                    910:      */
                    911:     free_all_prunes();
                    912:     free_all_routes();
                    913:     free_all_callouts();
                    914:     stop_all_vifs();
                    915:     k_stop_dvmrp();
                    916:     close(igmp_socket);
                    917:     close(udp_socket);
                    918:     did_final_init = 0;
                    919: 
                    920:     /*
                    921:      * start processing again
                    922:      */
                    923:     dvmrp_genid++;
                    924: 
                    925:     init_igmp();
                    926:     init_routes();
                    927:     init_ktable();
                    928:     init_vifs();
                    929:     /*XXX Schedule final_init() as main does? */
                    930:     final_init(s);
                    931: 
                    932:     /* schedule timer interrupts */
                    933:     timer_setTimer(1, fasttimer, NULL);
                    934:     timer_setTimer(TIMER_INTERVAL, timer, NULL);
                    935: }
                    936: 
                    937: #define LOG_MAX_MSGS   20      /* if > 20/minute then shut up for a while */
                    938: #define LOG_SHUT_UP    600     /* shut up for 10 minutes */
                    939: static int log_nmsgs = 0;
                    940: 
                    941: static void resetlogging(void *arg)
                    942: {
                    943:     int nxttime = 60;
                    944:     void *narg = NULL;
                    945: 
                    946:     if (arg == NULL && log_nmsgs > LOG_MAX_MSGS) {
                    947:        nxttime = LOG_SHUT_UP;
                    948:        narg = (void *)&log_nmsgs;      /* just need some valid void * */
                    949:        syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
                    950:                        LOG_SHUT_UP / 60);
                    951:     } else {
                    952:        log_nmsgs = 0;
                    953:     }
                    954: 
                    955:     timer_setTimer(nxttime, resetlogging, narg);
                    956: }
                    957: 
                    958: #define SCALETIMEBUFLEN 20
                    959: char *scaletime(u_long t)
                    960: {
                    961:     static char buf1[SCALETIMEBUFLEN];
                    962:     static char buf2[SCALETIMEBUFLEN];
                    963:     static char *buf = buf1;
                    964:     char *p;
                    965: 
                    966:     p = buf;
                    967:     if (buf == buf1)
                    968:        buf = buf2;
                    969:     else
                    970:        buf = buf1;
                    971: 
                    972:     snprintf(p, SCALETIMEBUFLEN, "%2ld:%02ld:%02ld", t / 3600, (t % 3600) / 60, t % 60);
                    973: 
                    974:     return p;
                    975: }
                    976: 
                    977: #ifdef RINGBUFFER
                    978: #define NLOGMSGS 10000
                    979: #define LOGMSGSIZE 200
                    980: char *logmsg[NLOGMSGS];
                    981: static int logmsgno = 0;
                    982: 
                    983: void printringbuf(void)
                    984: {
                    985:     FILE *f;
                    986:     int i;
                    987: 
                    988:     f = fopen("/var/tmp/mrouted.log", "a");
                    989:     if (f == NULL) {
                    990:        logit(LOG_ERR, errno, "Cannot open /var/tmp/mrouted.log");
                    991:        /*NOTREACHED*/
                    992:     }
                    993:     fprintf(f, "--------------------------------------------\n");
                    994: 
                    995:     i = (logmsgno + 1) % NLOGMSGS;
                    996: 
                    997:     while (i != logmsgno) {
                    998:        if (*logmsg[i]) {
                    999:            fprintf(f, "%s\n", logmsg[i]);
                   1000:            *logmsg[i] = '\0';
                   1001:        }
                   1002:        i = (i + 1) % NLOGMSGS;
                   1003:     }
                   1004: 
                   1005:     fclose(f);
                   1006: }
                   1007: #endif
                   1008: 
                   1009: /*
                   1010:  * Log errors and other messages to the system log daemon and to stderr,
                   1011:  * according to the severity of the message and the current debug level.
                   1012:  * For errors of severity LOG_ERR or worse, terminate the program.
                   1013:  */
                   1014: void logit(int severity, int syserr, const char *format, ...)
                   1015: {
                   1016:     va_list ap;
                   1017:     static char fmt[211] = "warning - ";
                   1018:     char *msg;
                   1019:     struct timeval now;
                   1020:     time_t now_sec;
                   1021:     struct tm *thyme;
                   1022: #ifdef RINGBUFFER
                   1023:     static int ringbufinit = 0;
                   1024: #endif
                   1025: 
                   1026:     va_start(ap, format);
                   1027:     vsnprintf(&fmt[10], sizeof(fmt) - 10, format, ap);
                   1028:     va_end(ap);
                   1029:     msg = (severity == LOG_WARNING) ? fmt : &fmt[10];
                   1030: 
                   1031: #ifdef RINGBUFFER
                   1032:     if (!ringbufinit) {
                   1033:        int i;
                   1034: 
                   1035:        for (i = 0; i < NLOGMSGS; i++) {
                   1036:            logmsg[i] = malloc(LOGMSGSIZE);
                   1037:            if (logmsg[i] == 0) {
                   1038:                syslog(LOG_ERR, "Out of memory");
                   1039:                exit(1);
                   1040:            }
                   1041:            *logmsg[i] = 0;
                   1042:        }
                   1043:        ringbufinit = 1;
                   1044:     }
                   1045:     gettimeofday(&now,NULL);
                   1046:     now_sec = now.tv_sec;
                   1047:     thyme = localtime(&now_sec);
                   1048:     snprintf(logmsg[logmsgno++], LOGMSGSIZE, "%02d:%02d:%02d.%03ld %s err %d",
                   1049:             thyme->tm_hour, thyme->tm_min, thyme->tm_sec,
                   1050:             now.tv_usec / 1000, msg, syserr);
                   1051:     logmsgno %= NLOGMSGS;
                   1052:     if (severity <= LOG_NOTICE)
                   1053: #endif
                   1054:     /*
                   1055:      * Log to stderr if we haven't forked yet and it's a warning or worse,
                   1056:      * or if we're debugging.
                   1057:      */
                   1058:     if (haveterminal && (debug || severity <= LOG_WARNING)) {
                   1059:        gettimeofday(&now,NULL);
                   1060:        now_sec = now.tv_sec;
                   1061:        thyme = localtime(&now_sec);
                   1062:        if (!debug)
                   1063:            fprintf(stderr, "%s: ", __progname);
                   1064:        fprintf(stderr, "%02d:%02d:%02d.%03ld %s", thyme->tm_hour,
                   1065:                    thyme->tm_min, thyme->tm_sec, now.tv_usec / 1000, msg);
                   1066:        if (syserr == 0)
                   1067:            fprintf(stderr, "\n");
                   1068:        else
                   1069:            fprintf(stderr, ": %s\n", strerror(syserr));
                   1070:     }
                   1071: 
                   1072:     /*
                   1073:      * Always log things that are worse than warnings, no matter what
                   1074:      * the log_nmsgs rate limiter says.
                   1075:      * Only count things worse than debugging in the rate limiter
                   1076:      * (since if you put daemon.debug in syslog.conf you probably
                   1077:      * actually want to log the debugging messages so they shouldn't
                   1078:      * be rate-limited)
                   1079:      */
                   1080:     if ((severity < LOG_WARNING) || (log_nmsgs < LOG_MAX_MSGS)) {
                   1081:        if (severity < LOG_DEBUG)
                   1082:            log_nmsgs++;
                   1083:        if (syserr != 0) {
                   1084:            errno = syserr;
                   1085:            syslog(severity, "%s: %m", msg);
                   1086:        } else
                   1087:            syslog(severity, "%s", msg);
                   1088:     }
                   1089: 
                   1090:     if (severity <= LOG_ERR) exit(1);
                   1091: }
                   1092: 
                   1093: #ifdef DEBUG_MFC
                   1094: void md_log(int what, u_int32 origin, u_int32 mcastgrp)
                   1095: {
                   1096:     static FILE *f = NULL;
                   1097:     struct timeval tv;
                   1098:     u_int32 buf[4];
                   1099: 
                   1100:     if (!f) {
                   1101:        if ((f = fopen("/tmp/mrouted.clog", "w")) == NULL) {
                   1102:            logit(LOG_ERR, errno, "open /tmp/mrouted.clog");
                   1103:        }
                   1104:     }
                   1105: 
                   1106:     gettimeofday(&tv, NULL);
                   1107:     buf[0] = tv.tv_sec;
                   1108:     buf[1] = what;
                   1109:     buf[2] = origin;
                   1110:     buf[3] = mcastgrp;
                   1111: 
                   1112:     fwrite(buf, sizeof(u_int32), 4, f);
                   1113: }
                   1114: #endif
                   1115: 
                   1116: /**
                   1117:  * Local Variables:
                   1118:  *  version-control: t
                   1119:  *  indent-tabs-mode: t
                   1120:  *  c-file-style: "ellemtel"
                   1121:  *  c-basic-offset: 4
                   1122:  * End:
                   1123:  */

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