diff --git a/src/callout.c b/src/callout.c index c49da6cf..dd23fb91 100644 --- a/src/callout.c +++ b/src/callout.c @@ -37,91 +37,48 @@ /* the code below implements a callout queue */ static int id = 0; -static struct timeOutQueue *queue = 0; /* pointer to the beginning of timeout queue */ +static struct timeOutQueue *queue = NULL; /* pointer to the beginning of timeout queue */ struct timeOutQueue { - struct timeOutQueue *next; // Next event in queue int id; timer_f func; // function to call void *data; // Data for function - int time; // Time offset for next event + long time; // Time for event + struct timeOutQueue *next; // Next event in queue }; // Method for dumping the Queue to the log. static void debugQueue(void); -/** -* Initializes the callout queue -*/ -void callout_init(void) { - queue = NULL; -} - /** * Clears all scheduled timeouts... */ void free_all_callouts(void) { struct timeOutQueue *p; - while (queue) { - p = queue; - queue = queue->next; - free(p); + for (p = queue ? queue->next : NULL; queue; queue = p, p = queue->next) { + free(queue); // Alloced by timer_setTimer() } } - /** - * elapsed_time seconds have passed; perform all the events that should - * happen. + * Execute all expired timers, using .5s grace. */ -void age_callout_queue(int elapsed_time) { - struct timeOutQueue *ptr; - struct timeOutQueue *_queue = NULL; - struct timeOutQueue *last = NULL; - int i = 0; - - for (ptr = queue; ptr; ptr = ptr->next) { - if (ptr->time > elapsed_time) { - ptr->time -= elapsed_time; - break; - } else { - elapsed_time -= ptr->time; - if (_queue == NULL) - _queue = ptr; - last = ptr; - } - } - - queue = ptr; - if (last) { - last->next = NULL; - } - - /* process existing events */ - for (ptr = _queue; ptr; ptr = _queue, i++) { - _queue = _queue->next; +void age_callout_queue(struct timespec curtime) { + struct timeOutQueue *ptr = queue; + int i = 1; + + if (curtime.tv_sec == 0) clock_gettime (CLOCK_MONOTONIC, &curtime); + while (ptr && ((ptr->time <= curtime.tv_sec) || (curtime.tv_nsec >= 500000000 && ptr->time <= curtime.tv_sec-1))) { my_log(LOG_DEBUG, 0, "About to call timeout %d (#%d)", ptr->id, i); - if (ptr->func) - ptr->func(ptr->data); - free(ptr); - } -} - -/** - * Return in how many seconds age_callout_queue() would like to be called. - * Return -1 if there are no events pending. - */ -int timer_nextTimer(void) { - if (queue) { - if (queue->time < 0) { - my_log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d", - queue->time); - return 0; + struct timeOutQueue *tmp = ptr; + if (ptr->func) { + ptr->func(ptr->data); } - return queue->time; + queue = ptr = ptr->next; + free(tmp); // Alloced by timer_setTimer() + i++; } - return -1; } /** @@ -131,61 +88,40 @@ int timer_nextTimer(void) { * @param data - Pointer to the function data to supply... */ int timer_setTimer(int delay, timer_f action, void *data) { - struct timeOutQueue *ptr, *node, *prev; - int i = 0; + struct timeOutQueue *ptr = queue, *node; + struct timespec curtime; + int i = 1; - /* create a node */ + // create a node. Freed by free_all_callouts() and age_callout_queue(). node = (struct timeOutQueue *)malloc(sizeof(struct timeOutQueue)); - if (node == 0) { + if (! node) { my_log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n"); return -1; } + clock_gettime(CLOCK_MONOTONIC, &curtime); node->func = action; node->data = data; - node->time = delay; - node->next = 0; + node->time = curtime.tv_sec + delay; node->id = ++id; + node->next = NULL; - prev = ptr = queue; - - /* insert node in the queue */ - - /* if the queue is empty, insert the node and return */ - if (!queue) { + if (! queue) { + // if the queue is empty, insert the node and return. queue = node; - } - else { - /* chase the pointer looking for the right place */ - while (ptr) { - if (delay < ptr->time) { - // We found the correct node - node->next = ptr; - if (ptr == queue) { - queue = node; - } - else { - prev->next = node; - } - ptr->time -= node->time; - my_log(LOG_DEBUG, 0, - "Created timeout %d (#%d) - delay %d secs", - node->id, i, node->time); - debugQueue(); - return node->id; - } else { - // Continur to check nodes. - delay -= ptr->time; node->time = delay; - prev = ptr; - ptr = ptr->next; - } - i++; + } else { + // chase the queue looking for the right place. + for (i++; ptr->next && node->time >= ptr->next->time; ptr = ptr->next, i++); + if (ptr == queue && node->time < ptr->time) { + // Start of queue, insert. + queue = node; + node->next = ptr; + } else { + node->next = ptr->next; + ptr->next = node; } - prev->next = node; } - my_log(LOG_DEBUG, 0, "Created timeout %d (#%d) - delay %d secs", - node->id, i, node->time); debugQueue(); - + my_log(LOG_DEBUG, 0, "Created timeout %d (#%d) - delay %d secs", node->id, i, delay); return node->id; } @@ -194,76 +130,26 @@ int timer_setTimer(int delay, timer_f action, void *data) { */ int timer_leftTimer(int timer_id) { struct timeOutQueue *ptr; - int left = 0; - - if (!timer_id) - return -1; + struct timespec curtime; + if (!timer_id || !queue) return -1; for (ptr = queue; ptr; ptr = ptr->next) { - left += ptr->time; if (ptr->id == timer_id) { - return left; + clock_gettime(CLOCK_MONOTONIC, &curtime); + return (ptr->time - curtime.tv_sec); } } return -1; } -/** -* clears the associated timer. Returns 1 if succeeded. -*/ -int timer_clearTimer(int timer_id) { - struct timeOutQueue *ptr, *prev; - int i = 0; - - if (!timer_id) - return 0; - - prev = ptr = queue; - - /* - * find the right node, delete it. the subsequent node's time - * gets bumped up - */ - - debugQueue(); - while (ptr) { - if (ptr->id == timer_id) { - /* got the right node */ - - /* unlink it from the queue */ - if (ptr == queue) - queue = queue->next; - else - prev->next = ptr->next; - - /* increment next node if any */ - if (ptr->next != 0) - (ptr->next)->time += ptr->time; - - if (ptr->data) - free(ptr->data); - my_log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i); - free(ptr); - debugQueue(); - return 1; - } - prev = ptr; - ptr = ptr->next; - i++; - } - // If we get here, the timer was not deleted. - my_log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i); - debugQueue(); - return 0; -} - /** * debugging utility */ static void debugQueue(void) { struct timeOutQueue *ptr; + int i; - for (ptr = queue; ptr; ptr = ptr->next) { - my_log(LOG_DEBUG, 0, "(Id:%d, Time:%d) ", ptr->id, ptr->time); + for (i = 1, ptr = queue; ptr; ptr = ptr->next, i++) { + my_log(LOG_DEBUG, 0, "(%d - Id:%d, Time:%d) ", i, ptr->id, ptr->time); } } diff --git a/src/config.c b/src/config.c index 030da1ac..c7bc86f3 100644 --- a/src/config.c +++ b/src/config.c @@ -47,9 +47,11 @@ struct vifconfig { // Keep allowed nets for VIF. struct SubnetList* allowednets; + struct SubnetList* deniednets; // Allowed Groups struct SubnetList* allowedgroups; + struct SubnetList* deniedgroups; // Next config in list... struct vifconfig* next; @@ -100,6 +102,27 @@ struct Config *getCommonConfig(void) { return &commonConfig; } +// Reloads the configuration file and removes interfaces which were removed from config. +void reloadConfig(void) { + struct vifconfig *OldConfPtr, *TmpConfPtr; + + // Load the new configuration keep reference to the old. + OldConfPtr = vifconf; + if (! loadConfig(configFilePath)) { + my_log(LOG_ERR, 0, "reloadConfig: Unable to load config file."); + } + + // Rebuild the interfaces config. + rebuildIfVc(); + + my_log(LOG_DEBUG, 0, "reloadConfig: Config Reloaded. OldConfPtr %x, NewConfPtr, %x", OldConfPtr, vifconf); + + // Free all the old mallocd vifconf list. + for (TmpConfPtr = OldConfPtr->next; OldConfPtr; OldConfPtr = TmpConfPtr, TmpConfPtr = OldConfPtr->next) { + free (OldConfPtr); // Alloced by parsePhyintToken() + } +} + /** * Loads the configuration from file, and stores the config in * respective holders... @@ -252,6 +275,9 @@ void configureVifs(void) { vifLast->next = confPtr->allowednets; Dp->allowedgroups = confPtr->allowedgroups; + Dp->deniednets = confPtr->deniednets; + Dp->allowedgroups = confPtr->allowedgroups; + Dp->deniedgroups = confPtr->deniedgroups; break; } @@ -260,6 +286,147 @@ void configureVifs(void) { } } +/* create VIFs for all IP, non-loop interfaces. + When argument is not NULL rebuild the interface table. +*/ +void createVifs(struct IfDescP *RebuildP) { + struct IfDesc *Dp, *oDp = NULL; + int vifcount = 0, upsvifcount = 0, Ix = 0; + struct gvDescL *gvDescL = NULL, *TmpgvDescL = NULL, *AddgvDescL = NULL; + + if (RebuildP) { + // When rebuild, check if interfaces have dissapeared and call delVIF if necessary. + for (oDp=RebuildP->S; oDpE; oDp++) { + if (! (Dp = getIfByName(oDp->Name))) { + my_log(LOG_DEBUG, 0, "Interface %s disappeared from system", oDp->Name); + if (oDp->index != (unsigned int)-1) { + AddgvDescL = clearRoutes(); + // For any dissappaerd downstream vif we may have a list of groups to be queried after we are done. + if (AddgvDescL) { + if (! gvDescL) { + gvDescL = AddgvDescL; + } else { + for (TmpgvDescL = gvDescL; TmpgvDescL && TmpgvDescL->next; TmpgvDescL = TmpgvDescL->next); + TmpgvDescL->next = AddgvDescL; + } + } + delVIF(oDp); + } + } + } + } + + // Loop through all new interfaces and check what has changed. + for(Ix = 0; (Dp = getIfByIx(Ix)); Ix++) { + AddgvDescL = NULL; + if (! RebuildP) { + // Only add vif for valid interfaces on start-up. + if ((Dp->Flags & IFF_LOOPBACK) || (Dp->state != IF_STATE_DOWNSTREAM && Dp->state != IF_STATE_UPSTREAM)) { + continue; + } + } else if ((oDp = getIfByName(Dp->Name))) { + /* Need rebuild, check if interface is new or already exists (check table below). + old: disabled new: disabled -> do nothing + old: disabled new: downstream -> addVIF(new) + old: disabled new: upstream -> addVIF(new) + old: downstream new: disabled -> clear routes oldvif, delVIF(old) + state table old: downstream new: downstream -> addvif(new,old) + old: downstream new: upstream -> clear routes oldvif, delvif(old), addvif(new) + old: upstream new: disabled -> clear routes oldvif, delVIF(old) + old: upstream new: downstream -> clear routes oldvif, delvif(old)),addvif(new) + old: upstream new: upstream -> addvif(new,old) + */ + if (oDp->state != IF_STATE_UPSTREAM && Dp->state == IF_STATE_UPSTREAM) { + // If vif transitions to upstream set relevant routes to not joined. + clearRoutes(); + } + + switch (oDp->state) { + case IF_STATE_DISABLED: + switch (Dp->state) { + case IF_STATE_DISABLED: { continue; } + case IF_STATE_DOWNSTREAM: { oDp=NULL; break; } + case IF_STATE_UPSTREAM: { oDp=NULL; break; } + } + break; + case IF_STATE_DOWNSTREAM: + switch (Dp->state) { + case IF_STATE_DISABLED: { AddgvDescL = clearRoutes(); delVIF(oDp); break; } + case IF_STATE_DOWNSTREAM: { break; } + case IF_STATE_UPSTREAM: { AddgvDescL = clearRoutes(); delVIF(oDp); oDp=NULL; break; } + } + break; + case IF_STATE_UPSTREAM: + switch (Dp->state) { + case IF_STATE_DISABLED: { clearRoutes(); delVIF(oDp); continue; } + case IF_STATE_DOWNSTREAM: { clearRoutes(); delVIF(oDp); oDp=NULL; break; } + case IF_STATE_UPSTREAM: { break; } + } + break; + } + + // For any removed downstream vif we may have a list of groups to be queried after we are done. + if (AddgvDescL) { + if (! gvDescL) { + gvDescL = AddgvDescL; + } else { + for (TmpgvDescL = gvDescL; TmpgvDescL && TmpgvDescL->next; TmpgvDescL = TmpgvDescL->next); + TmpgvDescL->next = AddgvDescL; + } + } + + // Do not call addvif for loopback or if switched from downstream to disabled. + if ((Dp->Flags & IFF_LOOPBACK) || (oDp && oDp->state == IF_STATE_DOWNSTREAM && Dp->state == IF_STATE_DISABLED)) { + continue; + } + } else { + // New Interface. Only add valid up/downstream vif. + if ((Dp->Flags & IFF_LOOPBACK) || (Dp->state != IF_STATE_DOWNSTREAM && Dp->state != IF_STATE_UPSTREAM)) { + continue; + } + if (Dp->state == IF_STATE_UPSTREAM) { + // Set relevant routes to not joined. + clearRoutes(); + } + oDp=NULL; + } + if(Dp->state == IF_STATE_UPSTREAM) { + if (upsvifcount >= MAX_UPS_VIFS) { + my_log(LOG_ERR, 0, "Cannot set VIF #%d as upstream as well. Max upstream Vif count is %d", + Ix, MAX_UPS_VIFS); + } else { + my_log(LOG_DEBUG, 0, "Found upstream IF #%d, will assign as upstream Vif %d", upsvifcount, Ix); + upsvifcount++; + } + } + addVIF(Dp); + vifcount++; + } + + // All vifs created, check if there is an upstream and at least one downstream. + if (upsvifcount == 0 || vifcount == upsvifcount) { + my_log(LOG_ERR, 0, "There must be at least 1 Vif as upstream and 1 as dowstream."); + } + + // If we have a lists of groups that have been set to check last member start the group specific querier. + while (gvDescL) { + struct gvDescL *FgvDescL = gvDescL; + + my_log(LOG_DEBUG, 0, "createVifs: Starting group specific query for %s", inetFmt(gvDescL->gvDesc->group,s1)); + sendGroupSpecificMemberQuery(gvDescL->gvDesc); + + // The list may have duplicates, remove them + for (TmpgvDescL = gvDescL; TmpgvDescL && TmpgvDescL->next; TmpgvDescL = TmpgvDescL->next) { + if (TmpgvDescL->next->gvDesc->group == gvDescL->gvDesc->group) { + TmpgvDescL->next = TmpgvDescL->next->next; + free(TmpgvDescL->next->gvDesc); // Alloced by clearRoutes() + free(TmpgvDescL->next); // Alloced by clearRoutes() + } + } + gvDescL = gvDescL->next; + free(FgvDescL); // Alloced by clearRoutes() + } +} /** * Internal function to parse phyint config @@ -290,7 +457,9 @@ struct vifconfig *parsePhyintToken(void) { tmpPtr->threshold = 1; tmpPtr->state = commonConfig.defaultInterfaceState; tmpPtr->allowednets = NULL; + tmpPtr->deniednets = NULL; tmpPtr->allowedgroups = NULL; + tmpPtr->deniedgroups = NULL; // Make a copy of the token to store the IF name tmpPtr->name = strdup( token ); diff --git a/src/ifvc.c b/src/ifvc.c index 509012f0..ca30de1b 100644 --- a/src/ifvc.c +++ b/src/ifvc.c @@ -42,6 +42,7 @@ static inline uint32_t s_addr_from_sockaddr(const struct sockaddr *addr) { } struct IfDesc IfDescVc[ MAX_IF ], *IfDescEp = IfDescVc; +struct IfDescP IfDescP = { NULL, NULL, 0 }; /* aimwang: add for detect interface and rebuild IfVc record */ /*************************************************** @@ -49,150 +50,34 @@ struct IfDesc IfDescVc[ MAX_IF ], *IfDescEp = IfDescVc; * For example: /etc/ppp/ip-up & ip-down can touch a file /tmp/ppp_changed * So I can check if the file exist then run me and delete the file. ***************************************************/ -void rebuildIfVc () { - struct ifreq IfVc[ sizeof( IfDescVc ) / sizeof( IfDescVc[ 0 ] ) ]; - struct ifreq *IfEp; - struct ifconf IoCtlReq; - struct IfDesc *Dp; - struct ifreq *IfPt, *IfNext; - uint32_t addr, subnet, mask; - int Sock; - - // Get the config. - struct Config *config = getCommonConfig(); - - if ( (Sock = socket( AF_INET, SOCK_DGRAM, 0 )) < 0 ) - my_log( LOG_ERR, errno, "RAW socket open" ); - - // aimwang: set all downstream IF as lost, for check IF exist or gone. - for (Dp = IfDescVc; Dp < IfDescEp; Dp++) { - if (Dp->state == IF_STATE_DOWNSTREAM) { - Dp->state = IF_STATE_LOST; - } - } - - IoCtlReq.ifc_buf = (void *)IfVc; - IoCtlReq.ifc_len = sizeof( IfVc ); - - if ( ioctl( Sock, SIOCGIFCONF, &IoCtlReq ) < 0 ) - my_log( LOG_ERR, errno, "ioctl SIOCGIFCONF" ); - - IfEp = (void *)((char *)IfVc + IoCtlReq.ifc_len); - - for ( IfPt = IfVc; IfPt < IfEp; IfPt = IfNext ) { - struct ifreq IfReq; - char FmtBu[ 32 ]; - - IfNext = (struct ifreq *)((char *)&IfPt->ifr_addr + -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - IfPt->ifr_addr.sa_len -#else - sizeof(struct sockaddr_in) -#endif - ); - if (IfNext < IfPt + 1) - IfNext = IfPt + 1; - - for (Dp = IfDescVc; Dp < IfDescEp; Dp++) { - if (0 == strcmp(Dp->Name, IfPt->ifr_name)) { - break; - } - } - - if (Dp == IfDescEp) { - strncpy( Dp->Name, IfPt->ifr_name, sizeof( IfDescEp->Name ) ); - } +void rebuildIfVc() { + // Build new IfDesc Table. Keep Copy of Old. + struct IfDescP OldIfDescP = IfDescP; + buildIfVc(); - if ( IfPt->ifr_addr.sa_family != AF_INET ) { - if (Dp == IfDescEp) { - IfDescEp++; - } - Dp->InAdr.s_addr = 0; /* mark as non-IP interface */ - continue; - } - - // Get the interface adress... - Dp->InAdr.s_addr = s_addr_from_sockaddr(&IfPt->ifr_addr); - addr = Dp->InAdr.s_addr; + // Call configureVifs to link the new IfDesc table. + configureVifs(); - memcpy( IfReq.ifr_name, Dp->Name, sizeof( IfReq.ifr_name ) ); + // Call createvifs with pointers IfDesc tables for relinking vifs and removing or adding interfaces if required. + my_log (LOG_DEBUG,0,"RebuildIfVc: creating vifs, Old IfDescP: %x, New: %x", OldIfDescP.S, IfDescP.S); + createVifs(&OldIfDescP); - // Get the subnet mask... - if (ioctl(Sock, SIOCGIFNETMASK, &IfReq ) < 0) - my_log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK for %s", IfReq.ifr_name); - mask = s_addr_from_sockaddr(&IfReq.ifr_addr); // Do not use ifr_netmask as it is not available on freebsd - subnet = addr & mask; - - if ( ioctl( Sock, SIOCGIFFLAGS, &IfReq ) < 0 ) - my_log( LOG_ERR, errno, "ioctl SIOCGIFFLAGS" ); - Dp->Flags = IfReq.ifr_flags; - - if (0x10d1 == Dp->Flags) - { - if ( ioctl( Sock, SIOCGIFDSTADDR, &IfReq ) < 0 ) - my_log(LOG_ERR, errno, "ioctl SIOCGIFDSTADDR for %s", IfReq.ifr_name); - addr = s_addr_from_sockaddr(&IfReq.ifr_dstaddr); - subnet = addr & mask; - } - - if (Dp == IfDescEp) { - // Insert the verified subnet as an allowed net... - Dp->allowednets = (struct SubnetList *)malloc(sizeof(struct SubnetList)); - if(IfDescEp->allowednets == NULL) { - my_log(LOG_ERR, 0, "Out of memory !"); + // Free the old IfDesc Table and linked subnet lists. + struct IfDesc *Dp; + for (Dp = OldIfDescP.S; Dp < OldIfDescP.E; Dp++) { + int i; + for (i = 1; i <= 4; i++) { + struct SubnetList *TmpNetPtr, *currsubnet; + currsubnet = i == 1 ? Dp->allowednets : + i == 2 ? Dp->deniednets : + i == 3 ? Dp->allowedgroups : + Dp->deniedgroups; + for (TmpNetPtr = currsubnet ? currsubnet->next : NULL; currsubnet; currsubnet = TmpNetPtr, TmpNetPtr = currsubnet->next) { + free(currsubnet); // Alloced by builfIfVc and allocSubnet(). } - Dp->allowednets->next = NULL; - Dp->state = IF_STATE_DOWNSTREAM; - Dp->robustness = DEFAULT_ROBUSTNESS; - Dp->threshold = DEFAULT_THRESHOLD; /* ttl limit */ - Dp->ratelimit = DEFAULT_RATELIMIT; - } - - // Set the network address for the IF.. - Dp->allowednets->subnet_mask = mask; - Dp->allowednets->subnet_addr = subnet; - - // Set the state for the IF... - if (Dp->state == IF_STATE_LOST) { - Dp->state = IF_STATE_DOWNSTREAM; - } - - // when IF become enabeld from downstream, addVIF to enable its VIF - if (Dp->state == IF_STATE_HIDDEN) { - my_log(LOG_NOTICE, 0, "%s [Hidden -> Downstream]", Dp->Name); - Dp->state = IF_STATE_DOWNSTREAM; - addVIF(Dp); - joinMcGroup(getMcGroupSock(), Dp, allrouters_group); - } - - // addVIF when found new IF - if (Dp == IfDescEp) { - my_log(LOG_NOTICE, 0, "%s [New]", Dp->Name); - Dp->state = config->defaultInterfaceState; - addVIF(Dp); - joinMcGroup(getMcGroupSock(), Dp, allrouters_group); - IfDescEp++; - } - - // Debug log the result... - my_log( LOG_DEBUG, 0, "rebuildIfVc: Interface %s Addr: %s, Flags: 0x%04x, Network: %s", - Dp->Name, - fmtInAdr( FmtBu, Dp->InAdr ), - Dp->Flags, - inetFmts(subnet, mask, s1)); - } - - // aimwang: search not longer exist IF, set as hidden and call delVIF - for (Dp = IfDescVc; Dp < IfDescEp; Dp++) { - if (IF_STATE_LOST == Dp->state) { - my_log(LOG_NOTICE, 0, "%s [Downstream -> Hidden]", Dp->Name); - Dp->state = IF_STATE_HIDDEN; - leaveMcGroup( getMcGroupSock(), Dp, allrouters_group ); - delVIF(Dp); } } - - close( Sock ); + free(OldIfDescP.S); // Alloced by buildIfVc() } /* diff --git a/src/igmpproxy.c b/src/igmpproxy.c index c72a567f..fc5ce22b 100644 --- a/src/igmpproxy.c +++ b/src/igmpproxy.c @@ -113,7 +113,7 @@ int main( int ArgCn, char *ArgVc[] ) { fputs("You must specify the configuration file.\n", stderr); exit(1); } - char *configFilePath = ArgVc[optind]; + configFilePath = ArgVc[optind]; // Chech that we are root if (geteuid() != 0) { @@ -236,9 +236,9 @@ int igmpProxyInit(void) { // Initialize IGMP initIgmp(); // Initialize Routing table - initRouteTable(); + clearRoutes(); // Initialize timer - callout_init(); + free_all_callouts(); return 1; } @@ -250,7 +250,7 @@ void igmpProxyCleanUp(void) { my_log( LOG_DEBUG, 0, "clean handler called" ); free_all_callouts(); // No more timeouts. - clearAllRoutes(); // Remove all routes. + clearRoutes(); // Remove all routes. disableMRouter(); // Disable the multirout API } @@ -262,23 +262,21 @@ void igmpProxyRun(void) { struct Config *config = getCommonConfig(); // Set some needed values. register int recvlen; - int MaxFD, Rt, secs; + int MaxFD, Rt; fd_set ReadFDS; socklen_t dummy = 0; - struct timespec curtime, lasttime, difftime, tv; - // The timeout is a pointer in order to set it to NULL if nessecary. - struct timespec *timeout = &tv; + struct timespec curtime, lasttime, difftime, *timeout = &difftime; + + // First thing we send a membership query in downstream VIF's... + sendGeneralMembershipQuery(); // Initialize timer vars difftime.tv_nsec = 0; clock_gettime(CLOCK_MONOTONIC, &curtime); lasttime = curtime; - // First thing we send a membership query in downstream VIF's... - sendGeneralMembershipQuery(); - // Loop until the end... - for (;;) { + while (true) { // Process signaling... if (sighandled) { @@ -289,17 +287,24 @@ void igmpProxyRun(void) { } } - /* aimwang: call rebuildIfVc */ - if (config->rescanVif) - rebuildIfVc(); - - // Prepare timeout... - secs = timer_nextTimer(); - if(secs == -1) { - timeout = NULL; + if (config->rescanVif) (void)0; + + // Timeout = 1s - difference between current and last time age_callout queue with .01s grace. + // This will make sure age_callout_queue is run once every s (timer resolution) +- 0.01s. + // If aging queues takes > .01s on very slow systems or when queue is very large, + // this will become less accurate by about the time it takes to age the queue + time to process a request. + clock_gettime(CLOCK_MONOTONIC, &curtime); + difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec; + if (curtime.tv_nsec >= lasttime.tv_nsec ) { + timeout->tv_nsec = 999999999 - (curtime.tv_nsec - lasttime.tv_nsec); } else { - timeout->tv_nsec = 0; - timeout->tv_sec = (secs > 3) ? 3 : secs; // aimwang: set max timeout + timeout->tv_nsec = 999999999 - (1000000000 - lasttime.tv_nsec + curtime.tv_nsec); + difftime.tv_sec--; + } + if (difftime.tv_sec > 0 || timeout->tv_nsec < 10000000) { + timeout->tv_nsec = 999999999; timeout->tv_sec = 0; + lasttime = curtime; + age_callout_queue(curtime); } // Prepare for select. @@ -331,39 +336,7 @@ void igmpProxyRun(void) { acceptIgmp(recvlen); } } - - // At this point, we can handle timeouts... - do { - /* - * If the select timed out, then there's no other - * activity to account for and we don't need to - * call gettimeofday. - */ - if (Rt == 0) { - curtime.tv_sec = lasttime.tv_sec + secs; - curtime.tv_nsec = lasttime.tv_nsec; - Rt = -1; /* don't do this next time through the loop */ - } else { - clock_gettime(CLOCK_MONOTONIC, &curtime); - } - difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec; - difftime.tv_nsec += curtime.tv_nsec - lasttime.tv_nsec; - while (difftime.tv_nsec > 1000000000) { - difftime.tv_sec++; - difftime.tv_nsec -= 1000000000; - } - if (difftime.tv_nsec < 0) { - difftime.tv_sec--; - difftime.tv_nsec += 1000000000; - } - lasttime = curtime; - if (secs == 0 || difftime.tv_sec > 0) - age_callout_queue(difftime.tv_sec); - secs = -1; - } while (difftime.tv_sec > 0); - } - } /* diff --git a/src/igmpproxy.h b/src/igmpproxy.h index 5e25b23a..632b2353 100644 --- a/src/igmpproxy.h +++ b/src/igmpproxy.h @@ -151,13 +151,21 @@ struct IfDesc { short Flags; short state; struct SubnetList* allowednets; + struct SubnetList* deniednets; struct SubnetList* allowedgroups; + struct SubnetList* deniedgroups; unsigned int robustness; unsigned char threshold; /* ttl limit */ unsigned int ratelimit; unsigned int index; }; +struct IfDescP { + struct IfDesc *S; + struct IfDesc *E; + unsigned int nrint; +}; + // Keeps common configuration settings struct Config { unsigned int robustnessValue; @@ -184,6 +192,18 @@ struct Config { // Holds the indeces of the upstream IF... extern int upStreamIfIdx[MAX_UPS_VIFS]; +// Group specific query structs. +typedef struct { + uint32_t group; + struct IfDesc *sourceVif; + short started; +} GroupVifDesc; + +struct gvDescL { + GroupVifDesc *gvDesc; + struct gvDescL *next; +}; + /* ifvc.c */ void rebuildIfVc( void ); @@ -216,8 +236,11 @@ int getVifIx( struct IfDesc *IfDp ); /* config.c */ +char *configFilePath; +void reloadConfig(void); int loadConfig(char *configFile); void configureVifs(void); +void createVifs(struct IfDescP *RebuildP); struct Config *getCommonConfig(void); /* igmp.c @@ -260,8 +283,7 @@ int leaveMcGroup( int UdpSock, struct IfDesc *IfDp, uint32_t mcastaddr ); /* rttable.c */ -void initRouteTable(void); -void clearAllRoutes(void); +struct gvDescL *clearRoutes(void); int insertRoute(uint32_t group, int ifx, uint32_t src); int activateRoute(uint32_t group, uint32_t originAddr, int upstrVif); void ageActiveRoutes(void); @@ -272,6 +294,7 @@ int getMcGroupSock(void); /* request.c */ +void sendGroupSpecificMemberQuery(void *argument); void acceptGroupReport(uint32_t src, uint32_t group); void acceptLeaveMessage(uint32_t src, uint32_t group); void sendGeneralMembershipQuery(void); @@ -280,12 +303,9 @@ void sendGeneralMembershipQuery(void); */ typedef void (*timer_f)(void *); -void callout_init(void); void free_all_callouts(void); -void age_callout_queue(int); -int timer_nextTimer(void); +void age_callout_queue(struct timespec curtime); int timer_setTimer(int, timer_f, void *); -int timer_clearTimer(int); int timer_leftTimer(int); /* confread.c diff --git a/src/request.c b/src/request.c index 06d14c44..f1f84ff1 100644 --- a/src/request.c +++ b/src/request.c @@ -43,13 +43,6 @@ // Prototypes... void sendGroupSpecificMemberQuery(void *argument); -typedef struct { - uint32_t group; - // uint32_t vifAddr; - short started; -} GroupVifDesc; - - /** * Handles incoming membership reports, and * appends them to the routing table. diff --git a/src/rttable.c b/src/rttable.c index 3d33c77e..b8a0a620 100644 --- a/src/rttable.c +++ b/src/rttable.c @@ -68,7 +68,7 @@ struct RouteTable { // Keeper for the routing table... -static struct RouteTable *routing_table; +static struct RouteTable *routing_table = NULL; // Prototypes void logRouteTable(const char *header); @@ -126,33 +126,6 @@ int getMcGroupSock(void) { return mcGroupSock; } -/** -* Initializes the routing table. -*/ -void initRouteTable(void) { - unsigned Ix; - struct IfDesc *Dp; - - // Clear routing table... - routing_table = NULL; - - // Join the all routers group on downstream vifs... - for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { - // If this is a downstream vif, we should join the All routers group... - if( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) && Dp->state == IF_STATE_DOWNSTREAM) { - my_log(LOG_DEBUG, 0, "Joining all-routers group %s on vif %s", - inetFmt(allrouters_group,s1),inetFmt(Dp->InAdr.s_addr,s2)); - - //k_join(allrouters_group, Dp->InAdr.s_addr); - joinMcGroup( getMcGroupSock(), Dp, allrouters_group ); - - my_log(LOG_DEBUG, 0, "Joining all igmpv3 multicast routers group %s on vif %s", - inetFmt(alligmp3_group,s1),inetFmt(Dp->InAdr.s_addr,s2)); - joinMcGroup( getMcGroupSock(), Dp, alligmp3_group ); - } - } -} - /** * Internal function to send join or leave requests for * a specified route upstream... @@ -228,7 +201,7 @@ static void sendJoinLeaveUpstream(struct RouteTable* route, int join) { /** * Clear all routes from routing table, and alerts Leaves upstream. */ -void clearAllRoutes(void) { +struct gvDescL *clearRoutes(void) { struct RouteTable *croute, *remainroute; // Loop through all routes... @@ -255,6 +228,8 @@ void clearAllRoutes(void) { // Send a notice that the routing table is empty... my_log(LOG_NOTICE, 0, "All routes removed. Routing table is empty."); + + return 0; } /**