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>