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>