Yuck, forgot to add `fdcontrol' in the Makefile along with
[unix-history] / usr.sbin / mrouted / main.c
CommitLineData
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
25extern char *configfilename;
26
27static char pidfilename[] = "/etc/mrouted.pid";
28static char dumpfilename[] = "/usr/tmp/mrouted.dump";
29
30static int debug = 0;
31
32
33/*
34 * Forward declarations.
35 */
36static void timer();
37static void hup();
38static void dump();
39static void fdump();
40
41
42main(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) {
79usage: 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
173static 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 */
181static 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 */
246static 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 */
258static void dump()
259{
260 dump_vifs(stderr);
261 dump_routes(stderr);
262}
263
264
265/*
266 * Dump internal data structures to a file.
267 */
268static 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 */
286void 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}