Annotation of embedaddon/pimd/main.c, revision 1.1.1.1
1.1 misho 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.19 2003/02/12 21:56:04 pavlin 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>