Annotation of embedaddon/mrouted/main.c, revision 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>