File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mrouted / main.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jul 21 23:59:21 2013 UTC (10 years, 10 months ago) by misho
Branches: mrouted, MAIN
CVS tags: v3_9_6p0, v3_9_6, HEAD
3.9.6

    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: 	    usleep(200);
  189: 	    snprintf(buf, sizeof(buf), "cat %s", file);
  190: 	    if (system(buf)) {
  191: 		warnx("Failed listing file %s\n", file);
  192: 	    }
  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>