Commit | Line | Data |
---|---|---|
0a4d79af JH |
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 | * $Id: main.c,v 1.5 1993/06/24 05:11:16 deering Exp $ | |
11 | */ | |
12 | ||
13 | /* | |
14 | * Written by Steve Deering, Stanford University, February 1989. | |
15 | * | |
16 | * (An earlier version of DVMRP was implemented by David Waitzman of | |
17 | * BBN STC by extending Berkeley's routed program. Some of Waitzman's | |
18 | * extensions have been incorporated into mrouted, but none of the | |
19 | * original routed code has been adopted.) | |
20 | */ | |
21 | ||
22 | ||
23 | #include "defs.h" | |
24 | ||
25 | extern char *configfilename; | |
26 | ||
27 | static char pidfilename[] = "/etc/mrouted.pid"; | |
28 | static char dumpfilename[] = "/usr/tmp/mrouted.dump"; | |
29 | ||
30 | static int debug = 0; | |
31 | ||
32 | ||
33 | /* | |
34 | * Forward declarations. | |
35 | */ | |
36 | static void timer(); | |
37 | static void hup(); | |
38 | static void dump(); | |
39 | static void fdump(); | |
40 | ||
41 | ||
42 | main(argc, argv) | |
43 | int argc; | |
44 | char *argv[]; | |
45 | { | |
46 | register int recvlen; | |
47 | register int omask; | |
48 | int dummy; | |
49 | FILE *fp; | |
50 | extern uid_t geteuid(); | |
51 | ||
52 | setlinebuf(stderr); | |
53 | ||
54 | if (geteuid() != 0) { | |
55 | fprintf(stderr, "mrouted: must be root\n"); | |
56 | exit(1); | |
57 | } | |
58 | ||
59 | argv++, argc--; | |
60 | while (argc > 0 && *argv[0] == '-') { | |
61 | if (strcmp(*argv, "-d") == 0) { | |
62 | if (argc > 1 && isdigit(*(argv + 1)[0])) { | |
63 | argv++, argc--; | |
64 | debug = atoi(*argv); | |
65 | } else | |
66 | debug = DEFAULT_DEBUG; | |
67 | } else if (strcmp(*argv, "-c") == 0) { | |
68 | if (argc > 1) { | |
69 | argv++, argc--; | |
70 | configfilename = *argv; | |
71 | } else | |
72 | goto usage; | |
73 | } else | |
74 | goto usage; | |
75 | argv++, argc--; | |
76 | } | |
77 | ||
78 | if (argc > 0) { | |
79 | usage: fprintf(stderr, "usage: mrouted [-c configfile] [-d [debug_level]]\n"); | |
80 | exit(1); | |
81 | } | |
82 | ||
83 | if (debug == 0) { | |
84 | /* | |
85 | * Detach from the terminal | |
86 | */ | |
87 | int t; | |
88 | ||
89 | if (fork()) exit(0); | |
90 | (void)close(0); | |
91 | (void)close(1); | |
92 | (void)close(2); | |
93 | (void)open("/", 0); | |
94 | (void)dup2(0, 1); | |
95 | (void)dup2(0, 2); | |
96 | t = open("/dev/tty", 2); | |
97 | if (t >= 0) { | |
98 | (void)ioctl(t, TIOCNOTTY, (char *)0); | |
99 | (void)close(t); | |
100 | } | |
101 | } | |
102 | else fprintf(stderr, "debug level %u\n", debug); | |
103 | ||
104 | #ifdef LOG_DAEMON | |
105 | (void)openlog("mrouted", LOG_PID, LOG_DAEMON); | |
106 | (void)setlogmask(LOG_UPTO(LOG_NOTICE)); | |
107 | #else | |
108 | (void)openlog("mrouted", LOG_PID); | |
109 | #endif | |
110 | log(LOG_NOTICE, 0, "mrouted version %d.%d", | |
111 | PROTOCOL_VERSION, MROUTED_VERSION); | |
112 | ||
113 | fp = fopen(pidfilename, "w"); | |
114 | if (fp != NULL) { | |
115 | fprintf(fp, "%d\n", getpid()); | |
116 | (void) fclose(fp); | |
117 | } | |
118 | ||
119 | srandom(gethostid()); | |
120 | ||
121 | init_igmp(); | |
122 | k_init_dvmrp(); /* enable DVMRP routing in kernel */ | |
123 | init_routes(); | |
124 | init_vifs(); | |
125 | ||
126 | if (debug >= 2) dump(); | |
127 | ||
128 | (void)signal(SIGALRM, timer); | |
129 | (void)signal(SIGHUP, hup); | |
130 | (void)signal(SIGTERM, hup); | |
131 | (void)signal(SIGINT, hup); | |
132 | (void)signal(SIGUSR1, fdump); | |
133 | if (debug != 0) | |
134 | (void)signal(SIGQUIT, dump); | |
135 | ||
136 | (void)alarm(TIMER_INTERVAL); /* schedule first timer interrupt */ | |
137 | ||
138 | /* | |
139 | * Main receive loop. | |
140 | */ | |
141 | dummy = 0; | |
142 | for(;;) { | |
143 | recvlen = recvfrom(igmp_socket, recv_buf, sizeof(recv_buf), | |
144 | 0, NULL, &dummy); | |
145 | if (recvlen < 0) { | |
146 | if (errno != EINTR) log(LOG_ERR, errno, "recvfrom"); | |
147 | continue; | |
148 | } | |
149 | omask = sigblock(sigmask(SIGALRM)); | |
150 | accept_igmp(recvlen); | |
151 | (void)sigsetmask(omask); | |
152 | } | |
153 | } | |
154 | ||
155 | ||
156 | /* | |
157 | * The 'virtual_time' variable is initialized to a value that will cause the | |
158 | * first invocation of timer() to send a probe or route report to all vifs | |
159 | * and send group membership queries to all subnets for which this router is | |
160 | * querier. This first invocation occurs approximately TIMER_INTERVAL seconds | |
161 | * after the router starts up. Note that probes for neighbors and queries | |
162 | * for group memberships are also sent at start-up time, as part of initial- | |
163 | * ization. This repetition after a short interval is desirable for quickly | |
164 | * building up topology and membership information in the presence of possible | |
165 | * packet loss. | |
166 | * | |
167 | * 'virtual_time' advances at a rate that is only a crude approximation of | |
168 | * real time, because it does not take into account any time spent processing, | |
169 | * and because the timer intervals are sometimes shrunk by a random amount to | |
170 | * avoid unwanted synchronization with other routers. | |
171 | */ | |
172 | ||
173 | static u_long virtual_time = 0; | |
174 | ||
175 | ||
176 | /* | |
177 | * Timer routine. Performs periodic neighbor probing, route reporting, and | |
178 | * group querying duties, and drives various timers in routing entries and | |
179 | * virtual interface data structures. | |
180 | */ | |
181 | static void timer() | |
182 | { | |
183 | int next_interval; | |
184 | ||
185 | age_routes(); /* Advance the timers in the route entries */ | |
186 | age_vifs(); /* Advance the timers for neighbors and groups */ | |
187 | ||
188 | if (virtual_time % GROUP_QUERY_INTERVAL == 0) { | |
189 | /* | |
190 | * Time to query the local group memberships on all subnets | |
191 | * for which this router is the elected querier. | |
192 | */ | |
193 | query_groups(); | |
194 | } | |
195 | ||
196 | if (virtual_time % NEIGHBOR_PROBE_INTERVAL == 0) { | |
197 | /* | |
198 | * Time to send a probe on all vifs from which no neighbors have | |
199 | * been heard. Also, check if any inoperative interfaces have now | |
200 | * come up. (If they have, they will also be probed as part of | |
201 | * their initialization.) | |
202 | */ | |
203 | probe_for_neighbors(); | |
204 | ||
205 | if (vifs_down) | |
206 | check_vif_state(); | |
207 | } | |
208 | ||
209 | delay_change_reports = FALSE; | |
210 | next_interval = TIMER_INTERVAL; | |
211 | ||
212 | if (virtual_time % ROUTE_REPORT_INTERVAL == 0) { | |
213 | /* | |
214 | * Time for the periodic report of all routes to all neighbors. | |
215 | */ | |
216 | report_to_all_neighbors(ALL_ROUTES); | |
217 | ||
218 | /* | |
219 | * Schedule the next timer interrupt for a random time between | |
220 | * 1 and TIMER_INTERVAL seconds from now. This randomization is | |
221 | * intended to counteract the undesirable synchronizing tendency | |
222 | * of periodic transmissions from multiple sources. | |
223 | */ | |
224 | next_interval = (random() % TIMER_INTERVAL) + 1; | |
225 | } | |
226 | else if (routes_changed) { | |
227 | /* | |
228 | * Some routes have changed since the last timer interrupt, but | |
229 | * have not been reported yet. Report the changed routes to all | |
230 | * neighbors. | |
231 | */ | |
232 | report_to_all_neighbors(CHANGED_ROUTES); | |
233 | } | |
234 | ||
235 | /* | |
236 | * Advance virtual time and schedule the next timer interrupt. | |
237 | */ | |
238 | virtual_time += TIMER_INTERVAL; | |
239 | (void)alarm(next_interval); | |
240 | } | |
241 | ||
242 | ||
243 | /* | |
244 | * On hangup signal, let everyone know we're going away. | |
245 | */ | |
246 | static void hup() | |
247 | { | |
248 | log(LOG_INFO, 0, "hup"); | |
249 | expire_all_routes(); | |
250 | report_to_all_neighbors(ALL_ROUTES); | |
251 | exit(1); | |
252 | } | |
253 | ||
254 | ||
255 | /* | |
256 | * Dump internal data structures to stderr. | |
257 | */ | |
258 | static void dump() | |
259 | { | |
260 | dump_vifs(stderr); | |
261 | dump_routes(stderr); | |
262 | } | |
263 | ||
264 | ||
265 | /* | |
266 | * Dump internal data structures to a file. | |
267 | */ | |
268 | static void fdump() | |
269 | { | |
270 | FILE *fp; | |
271 | ||
272 | fp = fopen(dumpfilename, "w"); | |
273 | if (fp != NULL) { | |
274 | dump_vifs(fp); | |
275 | dump_routes(fp); | |
276 | (void) fclose(fp); | |
277 | } | |
278 | } | |
279 | ||
280 | ||
281 | /* | |
282 | * Log errors and other messages to the system log daemon and to stderr, | |
283 | * according to the severity of the message and the current debug level. | |
284 | * For errors of severity LOG_ERR or worse, terminate the program. | |
285 | */ | |
286 | void log(severity, syserr, format, a, b, c, d, e) | |
287 | int severity, syserr; | |
288 | char *format; | |
289 | int a, b, c, d, e; | |
290 | { | |
291 | char fmt[100]; | |
292 | ||
293 | switch (debug) { | |
294 | case 0: break; | |
295 | case 1: if (severity > LOG_NOTICE) break; | |
296 | case 2: if (severity > LOG_INFO ) break; | |
297 | default: | |
298 | fmt[0] = '\0'; | |
299 | if (severity == LOG_WARNING) strcat(fmt, "warning - "); | |
300 | strncat(fmt, format, 80); | |
301 | fprintf(stderr, fmt, a, b, c, d, e); | |
302 | if (syserr == 0) | |
303 | fprintf(stderr, "\n"); | |
304 | else if(syserr < sys_nerr) | |
305 | fprintf(stderr, ": %s\n", sys_errlist[syserr]); | |
306 | else | |
307 | fprintf(stderr, ": errno %d\n", syserr); | |
308 | } | |
309 | ||
310 | if (severity <= LOG_NOTICE) { | |
311 | fmt[0] = '\0'; | |
312 | if (severity == LOG_WARNING) strcat(fmt, "warning - "); | |
313 | strncat(fmt, format, 80); | |
314 | if (syserr != 0) { | |
315 | strcat(fmt, ": %m"); | |
316 | errno = syserr; | |
317 | } | |
318 | syslog(severity, fmt, a, b, c, d, e); | |
319 | ||
320 | if (severity <= LOG_ERR) exit(-1); | |
321 | } | |
322 | } |