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