Annotation of embedaddon/igmpproxy/src/igmpproxy.c, revision 1.1.1.1
1.1 misho 1: /*
2: ** igmpproxy - IGMP proxy based multicast router
3: ** Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>
4: **
5: ** This program is free software; you can redistribute it and/or modify
6: ** it under the terms of the GNU General Public License as published by
7: ** the Free Software Foundation; either version 2 of the License, or
8: ** (at your option) any later version.
9: **
10: ** This program is distributed in the hope that it will be useful,
11: ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12: ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13: ** GNU General Public License for more details.
14: **
15: ** You should have received a copy of the GNU General Public License
16: ** along with this program; if not, write to the Free Software
17: ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18: **
19: **----------------------------------------------------------------------------
20: **
21: ** This software is derived work from the following software. The original
22: ** source code has been modified from it's original state by the author
23: ** of igmpproxy.
24: **
25: ** smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>
26: ** - Licensed under the GNU General Public License, version 2
27: **
28: ** mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of
29: ** Leland Stanford Junior University.
30: ** - Original license can be found in the Stanford.txt file.
31: **
32: */
33: /**
34: * igmpproxy.c - The main file for the IGMP proxy application.
35: *
36: * February 2005 - Johnny Egeland
37: */
38:
39: #include "igmpproxy.h"
40:
41: static const char Usage[] =
42: "Usage: igmpproxy [-h] [-d] [-v [-v]] <configfile>\n"
43: "\n"
44: " -h Display this help screen\n"
45: " -d Run in debug mode. Output all messages on stderr\n"
46: " -v Be verbose. Give twice to see even debug messages.\n"
47: "\n"
48: PACKAGE_STRING "\n"
49: ;
50:
51: // Local function Prototypes
52: static void signalHandler(int);
53: int igmpProxyInit();
54: void igmpProxyCleanUp();
55: void igmpProxyRun();
56:
57: // Global vars...
58: static int sighandled = 0;
59: #define GOT_SIGINT 0x01
60: #define GOT_SIGHUP 0x02
61: #define GOT_SIGUSR1 0x04
62: #define GOT_SIGUSR2 0x08
63:
64: // The upstream VIF index
65: int upStreamVif;
66:
67: /**
68: * Program main method. Is invoked when the program is started
69: * on commandline. The number of commandline arguments, and a
70: * pointer to the arguments are recieved on the line...
71: */
72: int main( int ArgCn, char *ArgVc[] ) {
73:
74: // Parse the commandline options and setup basic settings..
75: for (int c; (c = getopt(ArgCn, ArgVc, "vdh")) != -1;) {
76: switch (c) {
77: case 'd':
78: Log2Stderr = true;
79: break;
80: case 'v':
81: if (LogLevel == LOG_INFO)
82: LogLevel = LOG_DEBUG;
83: else
84: LogLevel = LOG_INFO;
85: break;
86: case 'h':
87: fputs(Usage, stderr);
88: exit(0);
89: break;
90: default:
91: exit(1);
92: break;
93: }
94: }
95:
96: if (optind != ArgCn - 1) {
97: fputs("You must specify the configuration file.\n", stderr);
98: exit(1);
99: }
100: char *configFilePath = ArgVc[optind];
101:
102: // Chech that we are root
103: if (geteuid() != 0) {
104: fprintf(stderr, "igmpproxy: must be root\n");
105: exit(1);
106: }
107:
108: openlog("igmpproxy", LOG_PID, LOG_USER);
109:
110: // Write debug notice with file path...
111: my_log(LOG_DEBUG, 0, "Searching for config file at '%s'" , configFilePath);
112:
113: do {
114:
115: // Loads the config file...
116: if( ! loadConfig( configFilePath ) ) {
117: my_log(LOG_ERR, 0, "Unable to load config file...");
118: break;
119: }
120:
121: // Initializes the deamon.
122: if ( !igmpProxyInit() ) {
123: my_log(LOG_ERR, 0, "Unable to initialize IGMPproxy.");
124: break;
125: }
126:
127: // Go to the main loop.
128: igmpProxyRun();
129:
130: // Clean up
131: igmpProxyCleanUp();
132:
133: } while ( false );
134:
135: // Inform that we are exiting.
136: my_log(LOG_INFO, 0, "Shutdown complete....");
137:
138: exit(0);
139: }
140:
141:
142:
143: /**
144: * Handles the initial startup of the daemon.
145: */
146: int igmpProxyInit() {
147: struct sigaction sa;
148: int Err;
149:
150:
151: sa.sa_handler = signalHandler;
152: sa.sa_flags = 0; /* Interrupt system calls */
153: sigemptyset(&sa.sa_mask);
154: sigaction(SIGTERM, &sa, NULL);
155: sigaction(SIGINT, &sa, NULL);
156:
157: // Loads configuration for Physical interfaces...
158: buildIfVc();
159:
160: // Configures IF states and settings
161: configureVifs();
162:
163: switch ( Err = enableMRouter() ) {
164: case 0: break;
165: case EADDRINUSE: my_log( LOG_ERR, EADDRINUSE, "MC-Router API already in use" ); break;
166: default: my_log( LOG_ERR, Err, "MRT_INIT failed" );
167: }
168:
169: /* create VIFs for all IP, non-loop interfaces
170: */
171: {
172: unsigned Ix;
173: struct IfDesc *Dp;
174: int vifcount = 0;
175: upStreamVif = -1;
176:
177: for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
178:
179: if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
180: if(Dp->state == IF_STATE_UPSTREAM) {
181: if(upStreamVif == -1) {
182: upStreamVif = Ix;
183: } else {
184: my_log(LOG_ERR, 0, "Vif #%d was already upstream. Cannot set VIF #%d as upstream as well.",
185: upStreamVif, Ix);
186: }
187: }
188:
189: addVIF( Dp );
190: vifcount++;
191: }
192: }
193:
194: // If there is only one VIF, or no defined upstream VIF, we send an error.
195: if(vifcount < 2 || upStreamVif < 0) {
196: my_log(LOG_ERR, 0, "There must be at least 2 Vif's where one is upstream.");
197: }
198: }
199:
200: // Initialize IGMP
201: initIgmp();
202: // Initialize Routing table
203: initRouteTable();
204: // Initialize timer
205: callout_init();
206:
207:
208: return 1;
209: }
210:
211: /**
212: * Clean up all on exit...
213: */
214: void igmpProxyCleanUp() {
215:
216: my_log( LOG_DEBUG, 0, "clean handler called" );
217:
218: free_all_callouts(); // No more timeouts.
219: clearAllRoutes(); // Remove all routes.
220: disableMRouter(); // Disable the multirout API
221:
222: }
223:
224: /**
225: * Main daemon loop.
226: */
227: void igmpProxyRun() {
228: // Get the config.
229: //struct Config *config = getCommonConfig();
230: // Set some needed values.
231: register int recvlen;
232: int MaxFD, Rt, secs;
233: fd_set ReadFDS;
234: socklen_t dummy = 0;
235: struct timeval curtime, lasttime, difftime, tv;
236: // The timeout is a pointer in order to set it to NULL if nessecary.
237: struct timeval *timeout = &tv;
238:
239: // Initialize timer vars
240: difftime.tv_usec = 0;
241: gettimeofday(&curtime, NULL);
242: lasttime = curtime;
243:
244: // First thing we send a membership query in downstream VIF's...
245: sendGeneralMembershipQuery();
246:
247: // Loop until the end...
248: for (;;) {
249:
250: // Process signaling...
251: if (sighandled) {
252: if (sighandled & GOT_SIGINT) {
253: sighandled &= ~GOT_SIGINT;
254: my_log(LOG_NOTICE, 0, "Got a interupt signal. Exiting.");
255: break;
256: }
257: }
258:
259: // Prepare timeout...
260: secs = timer_nextTimer();
261: if(secs == -1) {
262: timeout = NULL;
263: } else {
264: timeout->tv_usec = 0;
265: timeout->tv_sec = secs;
266: }
267:
268: // Prepare for select.
269: MaxFD = MRouterFD;
270:
271: FD_ZERO( &ReadFDS );
272: FD_SET( MRouterFD, &ReadFDS );
273:
274: // wait for input
275: Rt = select( MaxFD +1, &ReadFDS, NULL, NULL, timeout );
276:
277: // log and ignore failures
278: if( Rt < 0 ) {
279: my_log( LOG_WARNING, errno, "select() failure" );
280: continue;
281: }
282: else if( Rt > 0 ) {
283:
284: // Read IGMP request, and handle it...
285: if( FD_ISSET( MRouterFD, &ReadFDS ) ) {
286:
287: recvlen = recvfrom(MRouterFD, recv_buf, RECV_BUF_SIZE,
288: 0, NULL, &dummy);
289: if (recvlen < 0) {
290: if (errno != EINTR) my_log(LOG_ERR, errno, "recvfrom");
291: continue;
292: }
293:
294:
295: acceptIgmp(recvlen);
296: }
297: }
298:
299: // At this point, we can handle timeouts...
300: do {
301: /*
302: * If the select timed out, then there's no other
303: * activity to account for and we don't need to
304: * call gettimeofday.
305: */
306: if (Rt == 0) {
307: curtime.tv_sec = lasttime.tv_sec + secs;
308: curtime.tv_usec = lasttime.tv_usec;
309: Rt = -1; /* don't do this next time through the loop */
310: } else {
311: gettimeofday(&curtime, NULL);
312: }
313: difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
314: difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
315: while (difftime.tv_usec > 1000000) {
316: difftime.tv_sec++;
317: difftime.tv_usec -= 1000000;
318: }
319: if (difftime.tv_usec < 0) {
320: difftime.tv_sec--;
321: difftime.tv_usec += 1000000;
322: }
323: lasttime = curtime;
324: if (secs == 0 || difftime.tv_sec > 0)
325: age_callout_queue(difftime.tv_sec);
326: secs = -1;
327: } while (difftime.tv_sec > 0);
328:
329: }
330:
331: }
332:
333: /*
334: * Signal handler. Take note of the fact that the signal arrived
335: * so that the main loop can take care of it.
336: */
337: static void signalHandler(int sig) {
338: switch (sig) {
339: case SIGINT:
340: case SIGTERM:
341: sighandled |= GOT_SIGINT;
342: break;
343: /* XXX: Not in use.
344: case SIGHUP:
345: sighandled |= GOT_SIGHUP;
346: break;
347:
348: case SIGUSR1:
349: sighandled |= GOT_SIGUSR1;
350: break;
351:
352: case SIGUSR2:
353: sighandled |= GOT_SIGUSR2;
354: break;
355: */
356: }
357: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>