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