Annotation of embedaddon/pimd/main.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 1998-2001
        !             3:  * University of Southern California/Information Sciences Institute.
        !             4:  * All rights reserved.
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  * 3. Neither the name of the project nor the names of its contributors
        !            15:  *    may be used to endorse or promote products derived from this software
        !            16:  *    without specific prior written permission.
        !            17:  *
        !            18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
        !            19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
        !            22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            28:  * SUCH DAMAGE.
        !            29:  */
        !            30: /*
        !            31:  *  $Id: main.c,v 1.19 2003/02/12 21:56:04 pavlin Exp $
        !            32:  */
        !            33: /*
        !            34:  * Part of this program has been derived from mrouted.
        !            35:  * The mrouted program is covered by the license in the accompanying file
        !            36:  * named "LICENSE.mrouted".
        !            37:  *
        !            38:  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
        !            39:  * Leland Stanford Junior University.
        !            40:  *
        !            41:  */
        !            42: 
        !            43: 
        !            44: #include "defs.h"
        !            45: #include <err.h>
        !            46: #include <getopt.h>
        !            47: #include <sys/stat.h>
        !            48: 
        !            49: char versionstring[100];
        !            50: int disable_all_by_default = 0;
        !            51: int haveterminal = 1;
        !            52: struct rp_hold *g_rp_hold = NULL;
        !            53: int mrt_table_id = 0;
        !            54: 
        !            55: char *config_file = _PATH_PIMD_CONF;
        !            56: 
        !            57: extern int loglevel;
        !            58: extern char todaysversion[];
        !            59: 
        !            60: static int sighandled = 0;
        !            61: #define GOT_SIGINT      0x01
        !            62: #define GOT_SIGHUP      0x02
        !            63: #define GOT_SIGUSR1     0x04
        !            64: #define GOT_SIGUSR2     0x08
        !            65: #define GOT_SIGALRM     0x10
        !            66: 
        !            67: #define NHANDLERS       3
        !            68: static struct ihandler {
        !            69:     int fd;                    /* File descriptor               */
        !            70:     ihfunc_t func;             /* Function to call with &fd_set */
        !            71: } ihandlers[NHANDLERS];
        !            72: static int nhandlers = 0;
        !            73: 
        !            74: static struct debugname {
        !            75:     char       *name;
        !            76:     uint32_t    level;
        !            77:     size_t      nchars;
        !            78: } debugnames[] = {
        !            79:     {   "dvmrp_detail",            DEBUG_DVMRP_DETAIL,   5         },
        !            80:     {   "dvmrp_prunes",            DEBUG_DVMRP_PRUNE,    8         },
        !            81:     {   "dvmrp_pruning",    DEBUG_DVMRP_PRUNE,    8        },
        !            82:     {   "dvmrp_routes",            DEBUG_DVMRP_ROUTE,    7         },
        !            83:     {   "dvmrp_routing",    DEBUG_DVMRP_ROUTE,    7        },
        !            84:     {  "dvmrp_mrt",        DEBUG_DVMRP_ROUTE,    7         },
        !            85:     {  "dvmrp_neighbors",  DEBUG_DVMRP_PEER,     7         },
        !            86:     {  "dvmrp_peers",      DEBUG_DVMRP_PEER,     8         },
        !            87:     {  "dvmrp_hello",      DEBUG_DVMRP_PEER,     7         },
        !            88:     {  "dvmrp_timers",     DEBUG_DVMRP_TIMER,    7         },
        !            89:     {  "dvmrp",            DEBUG_DVMRP,          1         },
        !            90:     {  "igmp_proto",       DEBUG_IGMP_PROTO,     6         },
        !            91:     {  "igmp_timers",      DEBUG_IGMP_TIMER,     6         },
        !            92:     {  "igmp_members",     DEBUG_IGMP_MEMBER,    6         },
        !            93:     {  "groups",           DEBUG_MEMBER,         1         },
        !            94:     {  "membership",       DEBUG_MEMBER,         2         },
        !            95:     {  "igmp",             DEBUG_IGMP,           1         },
        !            96:     {  "trace",            DEBUG_TRACE,          2         },
        !            97:     {  "mtrace",           DEBUG_TRACE,          2         },
        !            98:     {  "traceroute",       DEBUG_TRACE,          2         },
        !            99:     {  "timeout",          DEBUG_TIMEOUT,        2         },
        !           100:     {  "callout",          DEBUG_TIMEOUT,        3         },
        !           101:     {  "packets",          DEBUG_PKT,            2         },
        !           102:     {  "pkt",              DEBUG_PKT,            2         },
        !           103:     {  "interfaces",       DEBUG_IF,             2         },
        !           104:     {  "vif",              DEBUG_IF,             1         },
        !           105:     {  "kernel",           DEBUG_KERN,           2         },
        !           106:     {  "cache",            DEBUG_MFC,            1         },
        !           107:     {  "mfc",              DEBUG_MFC,            2         },
        !           108:     {  "k_cache",          DEBUG_MFC,            2         },
        !           109:     {  "k_mfc",            DEBUG_MFC,            2         },
        !           110:     {  "rsrr",             DEBUG_RSRR,           2         },
        !           111:     {  "pim_detail",       DEBUG_PIM_DETAIL,     5         },
        !           112:     {  "pim_hello",        DEBUG_PIM_HELLO,      5         },
        !           113:     {  "pim_neighbors",    DEBUG_PIM_HELLO,      5         },
        !           114:     {  "pim_peers",        DEBUG_PIM_HELLO,      5         },
        !           115:     {  "pim_register",     DEBUG_PIM_REGISTER,   5         },
        !           116:     {  "registers",        DEBUG_PIM_REGISTER,   2         },
        !           117:     {  "pim_join_prune",   DEBUG_PIM_JOIN_PRUNE, 5         },
        !           118:     {  "pim_j_p",          DEBUG_PIM_JOIN_PRUNE, 5         },
        !           119:     {  "pim_jp",           DEBUG_PIM_JOIN_PRUNE, 5         },
        !           120:     {  "pim_bootstrap",    DEBUG_PIM_BOOTSTRAP,  5         },
        !           121:     {  "pim_bsr",          DEBUG_PIM_BOOTSTRAP,  5         },
        !           122:     {  "bsr",              DEBUG_PIM_BOOTSTRAP,  1         },
        !           123:     {  "bootstrap",        DEBUG_PIM_BOOTSTRAP,  1         },
        !           124:     {  "pim_asserts",      DEBUG_PIM_ASSERT,     5         },
        !           125:     {  "pim_cand_rp",      DEBUG_PIM_CAND_RP,    5         },
        !           126:     {  "pim_c_rp",         DEBUG_PIM_CAND_RP,    5         },
        !           127:     {  "pim_rp",           DEBUG_PIM_CAND_RP,    6         },
        !           128:     {  "rp",               DEBUG_PIM_CAND_RP,    2         },
        !           129:     {  "pim_routes",       DEBUG_PIM_MRT,        6         },
        !           130:     {  "pim_routing",      DEBUG_PIM_MRT,        6         },
        !           131:     {  "pim_mrt",          DEBUG_PIM_MRT,        5         },
        !           132:     {  "pim_timers",       DEBUG_PIM_TIMER,      5         },
        !           133:     {  "pim_rpf",          DEBUG_PIM_RPF,        6         },
        !           134:     {  "rpf",              DEBUG_RPF,            3         },
        !           135:     {  "pim",              DEBUG_PIM,            1         },
        !           136:     {  "routes",           DEBUG_MRT,            1         },
        !           137:     {  "routing",          DEBUG_MRT,            1         },
        !           138:     {  "mrt",              DEBUG_MRT,            1         },
        !           139:     {  "neighbors",        DEBUG_NEIGHBORS,      1         },
        !           140:     {  "routers",          DEBUG_NEIGHBORS,      6         },
        !           141:     {  "mrouters",         DEBUG_NEIGHBORS,      7         },
        !           142:     {  "peers",            DEBUG_NEIGHBORS,      1         },
        !           143:     {  "timers",           DEBUG_TIMER,          1         },
        !           144:     {  "asserts",          DEBUG_ASSERT,         1         },
        !           145:     {  "all",              DEBUG_ALL,            2         },
        !           146:     {  "3",                0xffffffff,           1         }    /* compat. */
        !           147: };
        !           148: 
        !           149: 
        !           150: /*
        !           151:  * Forward declarations.
        !           152:  */
        !           153: static void handler      (int);
        !           154: static void timer       (void *);
        !           155: static void cleanup      (void);
        !           156: static void restart      (int);
        !           157: static void resetlogging (void *);
        !           158: 
        !           159: int register_input_handler(int fd, ihfunc_t func)
        !           160: {
        !           161:     if (nhandlers >= NHANDLERS)
        !           162:        return -1;
        !           163: 
        !           164:     ihandlers[nhandlers].fd = fd;
        !           165:     ihandlers[nhandlers++].func = func;
        !           166: 
        !           167:     return 0;
        !           168: }
        !           169: 
        !           170: static void do_randomize(void)
        !           171: {
        !           172: #define rol32(data,shift) ((data) >> (shift)) | ((data) << (32 - (shift)))
        !           173:    int fd;
        !           174:    unsigned int seed;
        !           175: 
        !           176:    /* Setup a fallback seed based on quasi random. */
        !           177: #ifdef SYSV
        !           178:    seed = time(NULL);
        !           179: #else
        !           180:    seed = time(NULL) ^ gethostid();
        !           181: #endif
        !           182:    seed = rol32(seed, seed);
        !           183: 
        !           184:    fd = open("/dev/urandom", O_RDONLY);
        !           185:    if (fd >= 0) {
        !           186:        if (-1 == read(fd, &seed, sizeof(seed)))
        !           187:           warn("Failed reading entropy from /dev/urandom");
        !           188:        close(fd);
        !           189:   }
        !           190: 
        !           191: #ifdef SYSV
        !           192:    srand48(seed);
        !           193: #else
        !           194:    srandom(seed);
        !           195: #endif
        !           196: }
        !           197: 
        !           198: /* Figure out the PID of a running daemon. */
        !           199: static pid_t daemon_pid(void)
        !           200: {
        !           201:     int result;
        !           202:     char *path = NULL;
        !           203:     FILE *fp;
        !           204:     pid_t pid = -1;
        !           205: 
        !           206:     result = asprintf(&path, "%s%s.pid", _PATH_VARRUN, __progname);
        !           207:     if (result == -1 || path == NULL)
        !           208:        return -1;
        !           209: 
        !           210:     fp = fopen(path, "r");
        !           211:     if (!fp) {
        !           212:        free(path);
        !           213:        return -1;
        !           214:     }
        !           215: 
        !           216:     result = fscanf(fp, "%d", &pid);
        !           217:     fclose(fp);
        !           218:     free(path);
        !           219: 
        !           220:     return pid;
        !           221: }
        !           222: 
        !           223: /* Send signal to running daemon and the show resulting file. */
        !           224: static int killshow(int signo, char *file)
        !           225: {
        !           226:     pid_t pid = daemon_pid();
        !           227:     char buf[100];
        !           228: 
        !           229:     if (pid > 0) {
        !           230:        if (file && -1 == remove(file) && errno != ENOENT)
        !           231:            warn("Failed removing %s, may be showing stale information", file);
        !           232: 
        !           233:        kill(pid, signo);
        !           234:        if (file) {
        !           235:            usleep(200);
        !           236:            snprintf(buf, sizeof(buf), "cat %s", file);
        !           237:            if (-1 == system(buf)) {
        !           238:                warnx("Failed listing file %s\n", file);
        !           239:            }
        !           240:        }
        !           241:     }
        !           242: 
        !           243:     return 0;
        !           244: }
        !           245: 
        !           246: static int usage(int code)
        !           247: {
        !           248:     size_t i;
        !           249:     char line[76] = "  ";
        !           250:     struct debugname *d;
        !           251: 
        !           252:     printf("\nUsage: %s [-fhlNqrv] [-c FILE] [-d [SYS][,SYS...]] [-s LEVEL]\n\n", __progname);
        !           253:     printf(" -c, --config=FILE   Configuration file to use, default %s\n", _PATH_PIMD_CONF);
        !           254:     printf(" -d, --debug[=SYS]   Debug subsystem, see below for valid systems, default all\n");
        !           255:     printf(" -f, --foreground    Run in foreground, do not detach from calling terminal\n");
        !           256:     printf(" -h, --help          Show this help text\n");
        !           257:     /* printf("  -i, --show-cache     Show internal cache tables\n"); */
        !           258:     printf(" -l, --reload-config Tell a running pimd to reload its configuration\n");
        !           259:     printf(" -N, --disable-vifs  Disable all virtual interfaces (phyint) by default\n");
        !           260:     /* printf("  -p,--show-debug     Show debug dump, only if debug is enabled\n"); */
        !           261:     printf(" -q, --quit-daemon   Send SIGTERM to a running pimd\n");
        !           262:     printf(" -r, --show-routes   Show state of VIFs and multicast routing tables\n");
        !           263:     printf(" -t, --table-id=ID   Set multicast routing table ID.  Allowed table ID#:\n"
        !           264:           "                      0 .. 999999999.  Default: 0 (use default table)\n");
        !           265:     printf(" -s, --loglevel=LVL  Set log level: none, err, info, notice (default), debug\n");
        !           266:     printf(" -v, --version       Show %s version\n", __progname);
        !           267:     printf("\n");
        !           268: 
        !           269:     /* From pimd v2.3.0 we show *all* the debug levels again */
        !           270:     printf("Available subsystems for debug:\n");
        !           271:     for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) {
        !           272:        if (strlen(line) + strlen(d->name) + 3 >= sizeof(line)) {
        !           273:            /* Finish this line and send to console */
        !           274:            strlcat(line, "\n", sizeof(line));
        !           275:            printf("%s", line);
        !           276: 
        !           277:            /* Prepare for next line */
        !           278:            strlcpy(line, "  ", sizeof(line));
        !           279:        }
        !           280: 
        !           281:        strlcat(line, d->name, sizeof(line));
        !           282: 
        !           283:        if (i + 1 < ARRAY_LEN(debugnames))
        !           284:            strlcat(line, ", ", sizeof(line));
        !           285:     }
        !           286:     /* Flush remaining line. */
        !           287:     strlcat(line, "\n", sizeof(line));
        !           288:     printf("%s", line);
        !           289: 
        !           290:     printf("\nBug report address: %-40s\n\n", PACKAGE_BUGREPORT);
        !           291: 
        !           292:     return code;
        !           293: }
        !           294: 
        !           295: int main(int argc, char *argv[])
        !           296: {
        !           297:     int dummysigalrm, foreground = 0;
        !           298:     struct timeval tv, difftime, curtime, lasttime, *timeout;
        !           299:     fd_set rfds, readers;
        !           300:     int nfds, n, i, secs, ch;
        !           301:     struct sigaction sa;
        !           302:     time_t boottime;
        !           303:     struct option long_options[] = {
        !           304:        {"config", 1, 0, 'c'},
        !           305:        {"debug", 2, 0, 'd'},
        !           306:        {"foreground", 0, 0, 'f'},
        !           307:        {"disable-vifs", 0, 0, 'N'},
        !           308:        {"help", 0, 0, 'h'},
        !           309:        {"version", 0, 0, 'v'},
        !           310:        {"quit-daemon", 0, 0, 'q'},
        !           311:        {"reload-config", 0, 0, 'l'},
        !           312:        {"show-routes", 0, 0, 'r'},
        !           313:        {"table-id", 1, 0, 't'},
        !           314:        {"syslog-level", 1, 0, 's'},   /* Compat */
        !           315:        {"loglevel", 1, 0, 's'},
        !           316:        /* {"show-cache", 0, 0, 'i'}, */
        !           317:        /* {"show-debug", 0, 0, 'p'}, */
        !           318:        {0, 0, 0, 0}
        !           319:     };
        !           320: 
        !           321:     snprintf(versionstring, sizeof (versionstring), "pimd version %s", todaysversion);
        !           322: 
        !           323:     while ((ch = getopt_long(argc, argv, "c:d::fhlNvqrt:s:", long_options, NULL)) != EOF) {
        !           324:        const char *errstr;
        !           325: 
        !           326:        switch (ch) {
        !           327:            case 'c':
        !           328:                if (optarg)
        !           329:                    config_file = optarg;
        !           330:                break;
        !           331: 
        !           332:            case 'd':
        !           333:                if (!optarg) {
        !           334:                    debug = DEBUG_DEFAULT;
        !           335:                } else {
        !           336:                    char *p,*q;
        !           337:                    size_t i, len;
        !           338:                    struct debugname *d;
        !           339: 
        !           340:                    debug = 0;
        !           341:                    p = optarg; q = NULL;
        !           342:                    while (p) {
        !           343:                        q = strchr(p, ',');
        !           344:                        if (q)
        !           345:                            *q++ = '\0';
        !           346:                        len = strlen(p);
        !           347:                        for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) {
        !           348:                            if (len >= d->nchars && strncmp(d->name, p, len) == 0)
        !           349:                                break;
        !           350:                        }
        !           351: 
        !           352:                        if (i == ARRAY_LEN(debugnames))
        !           353:                            return usage(1);
        !           354: 
        !           355:                        debug |= d->level;
        !           356:                        p = q;
        !           357:                    }
        !           358:                }
        !           359:                break;
        !           360: 
        !           361:            case 'f':
        !           362:                foreground = 1;
        !           363:                break;
        !           364: 
        !           365:            case 'h':
        !           366:                return usage(0);
        !           367: 
        !           368:            case 'l':
        !           369:                return killshow(SIGHUP, NULL);
        !           370: 
        !           371:            case 'N':
        !           372:                disable_all_by_default = 1;
        !           373:                break;
        !           374: 
        !           375:            case 'v':
        !           376:                printf("%s\n", versionstring);
        !           377:                return 0;
        !           378: 
        !           379:            case 'q':
        !           380:                return killshow(SIGTERM, NULL);
        !           381: 
        !           382:            case 'r':
        !           383:                return killshow(SIGUSR1, _PATH_PIMD_DUMP);
        !           384: 
        !           385:            case 's':
        !           386:                if (!optarg) {
        !           387:                        fprintf(stderr, "Missing loglevel argument!\n");
        !           388:                        return usage(1);
        !           389:                }
        !           390: 
        !           391:                loglevel = loglvl(optarg);
        !           392:                if (-1 == loglevel)
        !           393:                    return usage(1);
        !           394:                break;
        !           395: 
        !           396:            case 't':
        !           397:                if (!optarg) {
        !           398:                        fprintf(stderr, "Missing Table ID argument!\n");
        !           399:                        return usage(1);
        !           400:                }
        !           401: 
        !           402:                mrt_table_id = strtonum(optarg, 0, 999999999, &errstr);
        !           403:                if (errstr) {
        !           404:                    fprintf(stderr, "Table ID %s!\n", errstr);
        !           405:                    return usage(1);
        !           406:                }
        !           407:                break;
        !           408: 
        !           409: #if 0 /* XXX: TODO */
        !           410:            case 'i':
        !           411:                return killshow(SIGUSR2, _PATH_PIMD_CACHE);
        !           412: 
        !           413:            case 'p':
        !           414:                return killshow(SIGQUIT, NULL);
        !           415: #endif
        !           416:            default:
        !           417:                return usage(1);
        !           418:        }
        !           419:     }
        !           420: 
        !           421:     argc -= optind;
        !           422:     if (argc > 0)
        !           423:        return usage(1);
        !           424: 
        !           425:     if (geteuid() != 0)
        !           426:        errx(1, "Need root privileges to start.");
        !           427: 
        !           428:     setlinebuf(stderr);
        !           429: 
        !           430:     if (debug != 0) {
        !           431:        struct debugname *d;
        !           432:        char c;
        !           433:        int tmpd = debug;
        !           434: 
        !           435:        fprintf(stderr, "debug level 0x%lx ", debug);
        !           436:        c = '(';
        !           437:        for (d = debugnames; d < debugnames + ARRAY_LEN(debugnames); d++) {
        !           438:            if ((tmpd & d->level) == d->level) {
        !           439:                tmpd &= ~d->level;
        !           440:                fprintf(stderr, "%c%s", c, d->name);
        !           441:                c = ',';
        !           442:            }
        !           443:        }
        !           444:        fprintf(stderr, ")\n");
        !           445:     }
        !           446: 
        !           447:     /*
        !           448:      * Create directory for runtime files
        !           449:      */
        !           450:     if (-1 == mkdir(_PATH_PIMD_RUNDIR, 0755) && errno != EEXIST)
        !           451:        err(1, "Failed creating %s directory for runtime files", _PATH_PIMD_RUNDIR);
        !           452: 
        !           453:     /*
        !           454:      * Setup logging
        !           455:      */
        !           456: #ifdef LOG_DAEMON
        !           457:     openlog("pimd", LOG_PID, LOG_DAEMON);
        !           458:     setlogmask(LOG_UPTO(loglevel));
        !           459: #else
        !           460:     openlog("pimd", LOG_PID);
        !           461: #endif /* LOG_DAEMON */
        !           462: 
        !           463:     logit(LOG_NOTICE, 0, "%s starting ...", versionstring);
        !           464: 
        !           465:     do_randomize();
        !           466:     time(&boottime);
        !           467: 
        !           468:     callout_init();
        !           469:     init_igmp();
        !           470:     init_pim();
        !           471:     init_routesock(); /* Both for Linux netlink and BSD routing socket */
        !           472:     init_pim_mrt();
        !           473:     init_timers();
        !           474: 
        !           475:     /* Start up the log rate-limiter */
        !           476:     resetlogging(NULL);
        !           477: 
        !           478:     /* TODO: check the kernel DVMRP/MROUTED/PIM support version */
        !           479: 
        !           480:     init_vifs();
        !           481:     init_rp_and_bsr();   /* Must be after init_vifs() */
        !           482: 
        !           483: #ifdef RSRR
        !           484:     rsrr_init();
        !           485: #endif /* RSRR */
        !           486: 
        !           487:     sa.sa_handler = handler;
        !           488:     sa.sa_flags = 0;   /* Interrupt system calls */
        !           489:     sigemptyset(&sa.sa_mask);
        !           490:     sigaction(SIGALRM, &sa, NULL);
        !           491:     sigaction(SIGHUP, &sa, NULL);
        !           492:     sigaction(SIGTERM, &sa, NULL);
        !           493:     sigaction(SIGINT, &sa, NULL);
        !           494:     sigaction(SIGUSR1, &sa, NULL);
        !           495:     sigaction(SIGUSR2, &sa, NULL);
        !           496: 
        !           497:     FD_ZERO(&readers);
        !           498:     FD_SET(igmp_socket, &readers);
        !           499:     nfds = igmp_socket + 1;
        !           500:     for (i = 0; i < nhandlers; i++) {
        !           501:        FD_SET(ihandlers[i].fd, &readers);
        !           502:        if (ihandlers[i].fd >= nfds)
        !           503:            nfds = ihandlers[i].fd + 1;
        !           504:     }
        !           505: 
        !           506:     IF_DEBUG(DEBUG_IF)
        !           507:        dump_vifs(stderr);
        !           508:     IF_DEBUG(DEBUG_PIM_MRT)
        !           509:        dump_pim_mrt(stderr);
        !           510: 
        !           511:     /* schedule first timer interrupt */
        !           512:     timer_setTimer(TIMER_INTERVAL, timer, NULL);
        !           513: 
        !           514:     if (!debug && !foreground) {
        !           515:        /* Detach from the terminal */
        !           516:        haveterminal = 0;
        !           517:        if (fork())
        !           518:            exit(0);
        !           519: 
        !           520:        close(STDIN_FILENO);
        !           521:        close(STDOUT_FILENO);
        !           522:        close(STDERR_FILENO);
        !           523: 
        !           524:        n = open("/dev/null", O_RDWR, 0);
        !           525:        if (n >= 0) {
        !           526:            dup2(n, STDIN_FILENO);
        !           527:            dup2(n, STDOUT_FILENO);
        !           528:            dup2(n, STDERR_FILENO);
        !           529:        }
        !           530: #ifdef SYSV
        !           531:        setpgrp();
        !           532: #else
        !           533: #ifdef TIOCNOTTY
        !           534:        n = open("/dev/tty", 2);
        !           535:        if (n >= 0) {
        !           536:            (void)ioctl(n, TIOCNOTTY, (char *)0);
        !           537:            (void)close(n);
        !           538:        }
        !           539: #else
        !           540:        if (setsid() < 0)
        !           541:            perror("setsid");
        !           542: #endif /* TIOCNOTTY */
        !           543: #endif /* SYSV */
        !           544:     } /* End of child process code */
        !           545: 
        !           546:     if (pidfile(NULL))
        !           547:        warn("Cannot create pidfile");
        !           548: 
        !           549:     /*
        !           550:      * Main receive loop.
        !           551:      */
        !           552:     dummysigalrm = SIGALRM;
        !           553:     difftime.tv_usec = 0;
        !           554:     gettimeofday(&curtime, NULL);
        !           555:     lasttime = curtime;
        !           556:     while (1) {
        !           557:        memcpy(&rfds, &readers, sizeof(rfds));
        !           558:        secs = timer_nextTimer();
        !           559:        if (secs == -1)
        !           560:            timeout = NULL;
        !           561:        else {
        !           562:            timeout = &tv;
        !           563:            timeout->tv_sec = secs;
        !           564:            timeout->tv_usec = 0;
        !           565:        }
        !           566: 
        !           567:        if (boottime) {
        !           568:            time_t n;
        !           569: 
        !           570:            time(&n);
        !           571:            if (n > boottime + 15) {
        !           572:                struct rp_hold *rph = g_rp_hold;
        !           573: 
        !           574:                while(rph) {
        !           575:                    add_rp_grp_entry(&cand_rp_list, &grp_mask_list,
        !           576:                                     rph->address, 1, (uint16_t)0xffffff,
        !           577:                                     rph->group, rph->mask,
        !           578:                                     curr_bsr_hash_mask, curr_bsr_fragment_tag);
        !           579:                    rph = rph->next;
        !           580:                }
        !           581:                boottime = 0;
        !           582:            }
        !           583:        }
        !           584: 
        !           585:        if (sighandled) {
        !           586:            if (sighandled & GOT_SIGINT) {
        !           587:                sighandled &= ~GOT_SIGINT;
        !           588:                break;
        !           589:            }
        !           590:            if (sighandled & GOT_SIGHUP) {
        !           591:                sighandled &= ~GOT_SIGHUP;
        !           592:                restart(SIGHUP);
        !           593: 
        !           594:                /* reconstruct readers and nfds */
        !           595:                FD_ZERO(&readers);
        !           596:                FD_SET(igmp_socket, &readers);
        !           597:                nfds = igmp_socket + 1;
        !           598:                for (i = 0; i < nhandlers; i++) {
        !           599:                    FD_SET(ihandlers[i].fd, &readers);
        !           600:                    if (ihandlers[i].fd >= nfds)
        !           601:                        nfds = ihandlers[i].fd + 1;
        !           602:                }
        !           603:                memcpy(&rfds, &readers, sizeof(rfds));
        !           604:            }
        !           605:            if (sighandled & GOT_SIGUSR1) {
        !           606:                sighandled &= ~GOT_SIGUSR1;
        !           607:                fdump(SIGUSR1);
        !           608:            }
        !           609:            if (sighandled & GOT_SIGUSR2) {
        !           610:                sighandled &= ~GOT_SIGUSR2;
        !           611:                cdump(SIGUSR2);
        !           612:            }
        !           613:            if (sighandled & GOT_SIGALRM) {
        !           614:                sighandled &= ~GOT_SIGALRM;
        !           615:                timer(&dummysigalrm);
        !           616:            }
        !           617:        }
        !           618:        if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) {
        !           619:            if (errno != EINTR) /* SIGALRM is expected */
        !           620:                logit(LOG_WARNING, errno, "select failed");
        !           621:            continue;
        !           622:        }
        !           623:        if (n > 0) {
        !           624:            /* TODO: shall check first igmp_socket for better performance? */
        !           625:            for (i = 0; i < nhandlers; i++) {
        !           626:                if (FD_ISSET(ihandlers[i].fd, &rfds)) {
        !           627:                    (*ihandlers[i].func)(ihandlers[i].fd, &rfds);
        !           628:                }
        !           629:            }
        !           630:        }
        !           631: 
        !           632:        /*
        !           633:         * Handle timeout queue.
        !           634:         *
        !           635:         * If select + packet processing took more than 1 second,
        !           636:         * or if there is a timeout pending, age the timeout queue.
        !           637:         *
        !           638:         * If not, collect usec in difftime to make sure that the
        !           639:         * time doesn't drift too badly.
        !           640:         *
        !           641:         * If the timeout handlers took more than 1 second,
        !           642:         * age the timeout queue again.  XXX This introduces the
        !           643:         * potential for infinite loops!
        !           644:         */
        !           645:        do {
        !           646:            /*
        !           647:             * If the select timed out, then there's no other
        !           648:             * activity to account for and we don't need to
        !           649:             * call gettimeofday.
        !           650:             */
        !           651:            if (n == 0) {
        !           652:                curtime.tv_sec = lasttime.tv_sec + secs;
        !           653:                curtime.tv_usec = lasttime.tv_usec;
        !           654:                n = -1; /* don't do this next time through the loop */
        !           655:            } else
        !           656:                gettimeofday(&curtime, NULL);
        !           657:            difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
        !           658:            difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
        !           659:            while (difftime.tv_usec >= 1000000) {
        !           660:                difftime.tv_sec++;
        !           661:                difftime.tv_usec -= 1000000;
        !           662:            }
        !           663:            if (difftime.tv_usec < 0) {
        !           664:                difftime.tv_sec--;
        !           665:                difftime.tv_usec += 1000000;
        !           666:            }
        !           667:            lasttime = curtime;
        !           668:            if (secs == 0 || difftime.tv_sec > 0)
        !           669:                age_callout_queue(difftime.tv_sec);
        !           670:            secs = -1;
        !           671:        } while (difftime.tv_sec > 0);
        !           672:     } /* Main loop */
        !           673: 
        !           674:     logit(LOG_NOTICE, 0, "%s exiting.", versionstring);
        !           675:     cleanup();
        !           676:     exit(0);
        !           677: }
        !           678: 
        !           679: /*
        !           680:  * The 'virtual_time' variable is initialized to a value that will cause the
        !           681:  * first invocation of timer() to send a probe or route report to all vifs
        !           682:  * and send group membership queries to all subnets for which this router is
        !           683:  * querier.  This first invocation occurs approximately TIMER_INTERVAL seconds
        !           684:  * after the router starts up.   Note that probes for neighbors and queries
        !           685:  * for group memberships are also sent at start-up time, as part of initial-
        !           686:  * ization.  This repetition after a short interval is desirable for quickly
        !           687:  * building up topology and membership information in the presence of possible
        !           688:  * packet loss.
        !           689:  *
        !           690:  * 'virtual_time' advances at a rate that is only a crude approximation of
        !           691:  * real time, because it does not take into account any time spent processing,
        !           692:  * and because the timer intervals are sometimes shrunk by a random amount to
        !           693:  * avoid unwanted synchronization with other routers.
        !           694:  */
        !           695: 
        !           696: uint32_t virtual_time = 0;
        !           697: 
        !           698: /*
        !           699:  * Timer routine. Performs all perodic functions:
        !           700:  * aging interfaces, quering neighbors and members, etc... The granularity
        !           701:  * is equal to TIMER_INTERVAL.
        !           702:  */
        !           703: static void timer(void *i __attribute__((unused)))
        !           704: {
        !           705:     age_vifs();                /* Timeout neighbors and groups         */
        !           706:     age_routes();      /* Timeout routing entries              */
        !           707:     age_misc();                /* Timeout the rest (Cand-RP list, etc) */
        !           708: 
        !           709:     virtual_time += TIMER_INTERVAL;
        !           710:     timer_setTimer(TIMER_INTERVAL, timer, NULL);
        !           711: }
        !           712: 
        !           713: /*
        !           714:  * Performs all necessary functions to quit gracefully
        !           715:  */
        !           716: /* TODO: implement all necessary stuff */
        !           717: static void cleanup(void)
        !           718: {
        !           719:     vifi_t vifi;
        !           720:     struct uvif *v;
        !           721: 
        !           722:     /* inform all neighbors that I'm going to die */
        !           723:     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
        !           724:        if ((v->uv_flags &
        !           725:             (VIFF_DOWN | VIFF_DISABLED | VIFF_REGISTER | VIFF_TUNNEL)) == 0)
        !           726:            send_pim_hello(v, 0);
        !           727:     }
        !           728: 
        !           729: #ifdef RSRR
        !           730:     rsrr_clean();
        !           731: #endif /* RSRR */
        !           732: 
        !           733:     /* TODO: XXX (not in the spec): if I am the BSR, somehow inform the
        !           734:      * other routers I am going down and need to elect another BSR?
        !           735:      * (probably by sending a the Cand-RP-set with my_priority=LOWEST?)
        !           736:      */
        !           737: 
        !           738:     k_stop_pim(igmp_socket);
        !           739: }
        !           740: 
        !           741: 
        !           742: /*
        !           743:  * Signal handler.  Take note of the fact that the signal arrived
        !           744:  * so that the main loop can take care of it.
        !           745:  */
        !           746: static void handler(int sig)
        !           747: {
        !           748:     switch (sig) {
        !           749:     case SIGALRM:
        !           750:        sighandled |= GOT_SIGALRM;
        !           751:        break;
        !           752: 
        !           753:     case SIGINT:
        !           754:     case SIGTERM:
        !           755:        sighandled |= GOT_SIGINT;
        !           756:        break;
        !           757: 
        !           758:     case SIGHUP:
        !           759:        sighandled |= GOT_SIGHUP;
        !           760:        break;
        !           761: 
        !           762:     case SIGUSR1:
        !           763:        sighandled |= GOT_SIGUSR1;
        !           764:        break;
        !           765: 
        !           766:     case SIGUSR2:
        !           767:        sighandled |= GOT_SIGUSR2;
        !           768:        break;
        !           769:     }
        !           770: }
        !           771: 
        !           772: 
        !           773: /* TODO: not verified */
        !           774: /*
        !           775:  * Restart the daemon
        !           776:  */
        !           777: static void restart(int i __attribute__((unused)))
        !           778: {
        !           779:     logit(LOG_NOTICE, 0, "%s restarting ...", versionstring);
        !           780: 
        !           781:     /*
        !           782:      * reset all the entries
        !           783:      */
        !           784:     /* TODO: delete?
        !           785:        free_all_routes();
        !           786:     */
        !           787:     free_all_callouts();
        !           788:     stop_all_vifs();
        !           789:     k_stop_pim(igmp_socket);
        !           790:     nhandlers = 0;
        !           791:     close(igmp_socket);
        !           792:     close(pim_socket);
        !           793: 
        !           794:     /*
        !           795:      * When IOCTL_OK_ON_RAW_SOCKET is defined, 'udp_socket' is equal
        !           796:      * 'to igmp_socket'. Therefore, 'udp_socket' should be closed only
        !           797:      * if they are different.
        !           798:      */
        !           799: #ifndef IOCTL_OK_ON_RAW_SOCKET
        !           800:     close(udp_socket);
        !           801: #endif
        !           802: 
        !           803:     /* Both for Linux netlink and BSD routing socket */
        !           804:     close(routing_socket);
        !           805: 
        !           806:     /*
        !           807:      * start processing again
        !           808:      */
        !           809: 
        !           810:     init_igmp();
        !           811:     init_pim();
        !           812:     init_routesock(); /* Both for Linux netlink and BSD routing socket */
        !           813:     init_pim_mrt();
        !           814:     init_vifs();
        !           815: 
        !           816:     /* schedule timer interrupts */
        !           817:     timer_setTimer(TIMER_INTERVAL, timer, NULL);
        !           818: }
        !           819: 
        !           820: 
        !           821: static void resetlogging(void *arg)
        !           822: {
        !           823:     int nxttime = 60;
        !           824:     void *narg = NULL;
        !           825: 
        !           826:     if (arg == NULL && log_nmsgs >= LOG_MAX_MSGS) {
        !           827:        nxttime = LOG_SHUT_UP;
        !           828:        narg = (void *)&log_nmsgs;      /* just need some valid void * */
        !           829:        syslog(LOG_WARNING, "logging too fast, shutting up for %d minutes",
        !           830:               LOG_SHUT_UP / 60);
        !           831:     } else {
        !           832:        if (arg != NULL) {
        !           833:            syslog(LOG_NOTICE, "logging enabled again after rate limiting");
        !           834:        }
        !           835:        log_nmsgs = 0;
        !           836:     }
        !           837: 
        !           838:     timer_setTimer(nxttime, resetlogging, narg);
        !           839: }
        !           840: 
        !           841: /**
        !           842:  * Local Variables:
        !           843:  *  version-control: t
        !           844:  *  indent-tabs-mode: t
        !           845:  *  c-file-style: "ellemtel"
        !           846:  *  c-basic-offset: 4
        !           847:  * End:
        !           848:  */

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