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