File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / igmpproxy / src / igmpproxy.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:00:29 2012 UTC (12 years, 4 months ago) by misho
Branches: igmpproxy, MAIN
CVS tags: v0_1p0, v0_1, HEAD
igmpproxy

    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>