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>