Annotation of embedaddon/igmpproxy/src/igmpproxy.c, revision 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>