"Fossies" - the Fresh Open Source Software Archive

Member "mrouted-3.9.8/main.c" (1 Jan 2017, 25030 Bytes) of package /linux/misc/mrouted-3.9.8.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "main.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.9.7_vs_3.9.8.

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