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