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