File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / main.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (7 years ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    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.1.1.1 2017/06/12 07:59:37 misho 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>