/** * Sends a group specific member report query until the * group times out... */ static void sendGroupSpecificMemberQuery(void *argument) { struct Config *conf = getCommonConfig(); // Cast argument to correct type... GroupVifDesc *gvDesc = (GroupVifDesc*) argument; if(gvDesc->started) { // If aging returns false, we don't do any further action... if(!lastMemberGroupAge(gvDesc->group)) { return; } } else { gvDesc->started = 1; } // Send a group specific membership query... sendIgmp(gvDesc->vifAddr, gvDesc->group, IGMP_MEMBERSHIP_QUERY, conf->lastMemberQueryInterval * IGMP_TIMER_SCALE, gvDesc->group, 0); my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d", inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2), conf->lastMemberQueryInterval); // Set timeout for next round... timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc); }
void schedule_join(struct mrt *mymrt,u_int32 dst) {//设置join计时器 struct pim_join_data *joindata; joindata=(struct pim_join_data *)malloc(sizeof(struct pim_join_data)); joindata->source=mymrt->source; joindata->group=mymrt->group; joindata->destination=dst; mymrt->join_delay_timer_id=timer_setTimer(1,send_join,joindata); }
/** * Sends a general membership query on downstream VIFs */ void sendGeneralMembershipQuery() { struct Config *conf = getCommonConfig(); struct IfDesc *Dp; unsigned Ix; #ifdef RALINK_ESW_SUPPORT clear_all_entries_report(); #endif // Loop through all downstream vifs... for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { if(Dp->state == IF_STATE_DOWNSTREAM) { // Send the membership query... sendIgmp(Dp->InAdr.s_addr, allhosts_group, IGMP_MEMBERSHIP_QUERY, conf->queryResponseInterval * IGMP_TIMER_SCALE, 0, 0); my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d", inetFmt(Dp->InAdr.s_addr,s1), inetFmt(allhosts_group,s2), conf->queryResponseInterval); } } } // Install timer for aging active routes. timer_setTimer(conf->queryResponseInterval, ageActiveRoutes, NULL); // Install timer for next general query... if(conf->startupQueryCount>0) { // Use quick timer... timer_setTimer(conf->startupQueryInterval, sendGeneralMembershipQuery, NULL); // Decrease startup counter... conf->startupQueryCount--; } else { // Use slow timer... timer_setTimer(conf->queryInterval, sendGeneralMembershipQuery, NULL); } }
void plan_graft(void *arg) {// struct mrt *mymrt,*thismrt,*mrtdata; mymrt=(struct mrt *)arg; thismrt=find_sg(mymrt->source,mymrt->group); if(mymrt->upstream==mymrt->source) { return; } if(thismrt!=NULL) { pim_graft_output(mymrt); mymrt->graft_timer_id=timer_setTimer(PIM_GRAFT_TIMER,plan_graft,mymrt); } }
void schedule_prune(struct mrt *mrtdata,vifi_t vif,int holdtime) {//设置prune计时器 struct pim_prune_data *prunedata; struct mrt *mymrt; mymrt=mrtdata; prunedata=(struct pim_prune_data *)malloc(sizeof(struct pim_prune_data)); prunedata->source=mymrt->source; prunedata->group=mymrt->group; prunedata->destination=mymrt->upstream; prunedata->vif=vif; prunedata->holdtime=holdtime; mymrt->prune_delay_timer_id[vif]=timer_setTimer(PIM_PRUNE_DELAY,set_prune,prunedata); log(LOG_INFO,"schedule_prune!!!"); }
void add_pim_neighbor(u_int32 src,int holdtime,vifi_t thevif) {//添加一个邻居 vifi_t vif; vif=thevif; struct pim_neighbor *newentry; newentry=(struct pim_neighbor *)malloc(sizeof(struct pim_neighbor)); newentry->next=myvifs[vif].neighbor; newentry->address=src; newentry->holdtime=holdtime; newentry->timeoutid=timer_setTimer(holdtime,delete_pim_neighbor,newentry); myvifs[vif].neighbor=newentry; log(LOG_INFO,"It's a new neighbor,add this neighbor on vif %s",myvifs[vif].name); refresh_mrt(vif,ADD_NEIGHBOR);/*1 add 0 delete*/ }
void receive_hello(u_int32 src,u_int32 dst,char *data,int length) {//收到Hello报文 vifi_t vif; struct pim_neighbor *pimneighbor; int holdtime; vif=find_vif_direct(src); if(valid_packet(src,data,length)==0) { return; } holdtime=get_hold_time(data,length); if(holdtime==-1) { log(LOG_INFO,"Get hold time error!"); } log(LOG_INFO,"Receive PIM Hello message,get Hold time=%d from %s",holdtime,inet_fmt(src,s1)); for(pimneighbor=myvifs[vif].neighbor;pimneighbor!=NULL;pimneighbor=pimneighbor->next) { if(pimneighbor->address==src) { if(holdtime==0) { delete_pim_neighbor(pimneighbor); return; } pimneighbor->holdtime=holdtime; if(pimneighbor->timeoutid!=-1) { timer_clearTimer(pimneighbor->timeoutid); } pimneighbor->timeoutid=timer_setTimer(holdtime,delete_pim_neighbor,pimneighbor); log(LOG_INFO,"Refresh hold time of neighbor %s to %d",inet_fmt(pimneighbor->address,s1),holdtime); return; } } add_pim_neighbor(src,holdtime,vif); return; //根据所得到的时间,采取相应的操作*/ }
void pim_hello_output(void *arg) {//给定Holdtime,发送一条PIM的Hello报文 struct pim_hello_output_data *hello_data;//参考实验指导书 struct pim_hello_header *option; char *mydata; short *hold_time; int length; hello_data=(struct pim_hello_output_data *)arg; mydata=(char *)(pim_send_buf+sizeof(struct ip)+sizeof(struct pim)); option=(struct pim_hello_header *)mydata; option->option_type=htons(1); option->option_length=htons(2); mydata=mydata+sizeof(struct pim_hello_header); hold_time=(short *)mydata; *hold_time=htons(hello_data->holdtime); length=sizeof(struct pim_hello_header)+sizeof(short); if(hello_data->regular==1) { timer_setTimer(PIM_HELLO_PERIOD,pim_hello_output,hello_data); } if(pimdm_output(pim_send_buf,myvifs[hello_data->vif].address,allpimrouters,PIM_HELLO,length)!=1) { log(LOG_INFO,"Send Pim Hello Packet On %s(%s) Error!",myvifs[hello_data->vif].name,inet_fmt(myvifs[hello_data->vif].address,s1)); } else { log(LOG_INFO,"Send Pim Hello Packet On %s(%s) Success!",myvifs[hello_data->vif].name,inet_fmt(myvifs[hello_data->vif].address,s1)); } return; }
void set_prune(void *data) {//在prune计时器超时后,执行操作 struct pim_prune_data *prunedata; struct mrt *mymrt; log(LOG_INFO,"Begin Prune"); prunedata=(struct pim_prune_data *)data; mymrt=find_sg(prunedata->source,prunedata->group); log(LOG_INFO,"Prune source:%s Group:%s",inet_fmt(prunedata->source,s1),inet_fmt(prunedata->group,s2)); if(mymrt==NULL) { return; } else { mymrt->prune_delay_timer_id[prunedata->vif]=0; mymrt->outvif[prunedata->vif]=0; change_mfc(igmpsocket,mymrt->source,mymrt->group,mymrt->incoming); check_pim_state(DEL_LEAF); log(LOG_INFO,"miss,handle set the prune"); mymrt->prune_timer_id[prunedata->vif]=timer_setTimer(5,prune_time_out,prunedata); } }
int main(int argc, char *argv[]) { int foreground = 0, do_syslog = 1; fd_set fds; int nfds, fd, n = -1, i, ch; struct sigaction sa; struct option long_options[] = { { "config", 1, 0, 'f' }, { "no-fallback", 0, 0, 500 }, { "disable-vifs", 0, 0, 'N' }, { "foreground", 0, 0, 'n' }, { "help", 0, 0, 'h' }, { "ident", 1, 0, 'I' }, { "loglevel", 1, 0, 'l' }, { "pidfile", 1, 0, 'P' }, { "syslog", 0, 0, 's' }, { "table-id", 1, 0, 't' }, { "version", 0, 0, 'v' }, { NULL, 0, 0, 0 } }; snprintf(versionstring, sizeof (versionstring), "pimd version %s", PACKAGE_VERSION); prognm = ident = progname(argv[0]); while ((ch = getopt_long(argc, argv, "d:f:hI:l:nNP:rst:v", long_options, NULL)) != EOF) { const char *errstr; switch (ch) { case 'd': { char *p,*q; size_t i, len; struct debugname *d; debug = 0; p = optarg; q = NULL; while (p) { q = strchr(p, ','); if (q) *q++ = '\0'; len = strlen(p); for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) { if (len >= d->nchars && strncmp(d->name, p, len) == 0) break; } if (i == ARRAY_LEN(debugnames)) return usage(1); debug |= d->level; p = q; } } break; case 'f': config_file = optarg; break; case 500: no_fallback = 1; break; case 'h': return usage(0); case 'I': /* --ident=NAME */ ident = optarg; break; case 'l': loglevel = loglvl(optarg); if (-1 == loglevel) return usage(1); break; case 'n': do_syslog--; foreground = 1; break; case 'N': do_vifs = 0; break; case 'P': /* --pidfile=NAME */ pid_file = strdup(optarg); break; case 'r': retry_forever++; break; case 's': do_syslog++; break; case 't': mrt_table_id = strtonum(optarg, 0, 999999999, &errstr); if (errstr) { fprintf(stderr, "Table ID %s!\n", errstr); return usage(1); } break; case 'v': printf("%s\n", versionstring); return 0; default: return usage(1); } } argc -= optind; if (argc > 0) return usage(1); if (geteuid() != 0) errx(1, "Need root privileges to start."); compose_paths(); setlinebuf(stderr); if (debug != 0) { struct debugname *d; char c; int tmpd = debug; fprintf(stderr, "debug level 0x%lx ", debug); c = '('; for (d = debugnames; d < debugnames + ARRAY_LEN(debugnames); d++) { if ((tmpd & d->level) == d->level) { tmpd &= ~d->level; fprintf(stderr, "%c%s", c, d->name); c = ','; } } fprintf(stderr, ")\n"); } if (!debug && !foreground) { /* Detach from the terminal */ haveterminal = 0; if (fork()) exit(0); close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); fd = open("/dev/null", O_RDWR, 0); if (fd >= 0) { dup2(fd, STDIN_FILENO); dup2(fd, STDOUT_FILENO); dup2(fd, STDERR_FILENO); close(fd); } #ifdef SYSV setpgrp(); #else #ifdef TIOCNOTTY fd = open("/dev/tty", 2); if (fd >= 0) { (void)ioctl(fd, TIOCNOTTY, (char *)0); close(fd); } #else if (setsid() < 0) perror("setsid"); #endif /* TIOCNOTTY */ #endif /* SYSV */ } /* End of child process code */ /* * Create directory for runtime files */ if (-1 == mkdir(_PATH_PIMD_RUNDIR, 0755) && errno != EEXIST) err(1, "Failed creating %s directory for runtime files", _PATH_PIMD_RUNDIR); /* * Setup logging */ log_init(haveterminal && do_syslog > 0); logit(LOG_NOTICE, 0, "%s starting ...", versionstring); do_randomize(); callout_init(); init_igmp(); init_pim(); init_routesock(); /* Both for Linux netlink and BSD routing socket */ init_pim_mrt(); init_timers(); ipc_init(); /* Start up the log rate-limiter */ resetlogging(NULL); /* TODO: check the kernel DVMRP/MROUTED/PIM support version */ init_vifs(); init_rp_and_bsr(); /* Must be after init_vifs() */ add_static_rp(); /* Must be after init_vifs() */ #ifdef RSRR rsrr_init(); #endif /* RSRR */ sa.sa_handler = handle_signals; sa.sa_flags = 0; /* Interrupt system calls */ sigemptyset(&sa.sa_mask); sigaction(SIGALRM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR2, &sa, NULL); IF_DEBUG(DEBUG_IF) dump_vifs(stderr); IF_DEBUG(DEBUG_PIM_MRT) dump_pim_mrt(stderr); /* schedule first timer interrupt */ timer_setTimer(TIMER_INTERVAL, timer, NULL); if (pidfile(pid_file)) warn("Cannot create pidfile"); /* * Main receive loop. */ while (1) { if (check_signals()) break; FD_ZERO(&fds); for (i = 0, nfds = 0; i < nhandlers; i++) { FD_SET(ihandlers[i].fd, &fds); if (ihandlers[i].fd >= nfds) nfds = ihandlers[i].fd + 1; } n = select(nfds, &fds, NULL, NULL, timeout(n)); if (n < 0) { if (errno != EINTR) /* SIGALRM is expected */ logit(LOG_WARNING, errno, "select failed"); continue; } for (i = 0; n > 0 && i < nhandlers; i++) { if (FD_ISSET(ihandlers[i].fd, &fds)) ihandlers[i].func(ihandlers[i].fd); } } logit(LOG_NOTICE, 0, "%s exiting.", versionstring); cleanup(); exit(0); }
void receive_assert(u_int32 src,u_int32 dst,char *data,int length) {// vifi_t vif; vifi_t *vifdata; u_int32 *unicast_address; struct encode_group_address *group_address; u_int32 source,group; struct mrt *mymrt; char *mydata; u_int32 *preference; u_int32 *metric; vif=find_vif_direct(src); if(vif==0) { return; } if(valid_packet(src,data,length)==0) { return; } mydata=data+sizeof(struct pim); group_address=(struct encode_group_address *)mydata; group=group_address->group_address; mydata=mydata+sizeof(struct encode_group_address)+sizeof(struct encode_unicast_option); unicast_address=(u_int32 *)mydata; source=*unicast_address; mydata=mydata+sizeof(u_int32); preference=(u_int32 *)mydata; mydata=mydata+sizeof(u_int32); metric=(u_int32 *)mydata; log(LOG_INFO,"Receive PIM Assert from %s to %s",inet_fmt(src,s1),inet_fmt(dst,s2)); mymrt=find_sg(source,group); if(mymrt==NULL) { return; } if(vif==mymrt->incoming) { if(source==mymrt->upstream) { return; } else { if(assert_compare(mymrt->preference,mymrt->metric,mymrt->upstream,*preference,*metric,source)==1) { return; } else { log(LOG_INFO,"PIM Assert!:Change upstream!"); mymrt->preference=*preference; mymrt->metric=*metric; mymrt->upstream=source; return; } } } else { if(mymrt->outvif[vif]==0) { return; } if(assert_compare(mymrt->preference,mymrt->metric,mymrt->upstream,*preference,*metric,source)==1) { pim_assert_output(source,group,vif,mymrt->preference,mymrt->metric); return; } else { vifdata=(vifi_t *)malloc(sizeof(vifi_t)); *vifdata=vif; mymrt->prune_delay_timer_id[vif]=timer_setTimer(PIM_ASSERT_TIMER,active_forward,vifdata); //changeinterface();将该接口置为不转发状态 } } }
int main(int argc, char *argv[]) { int dummy, dummysigalrm, foreground = 0; struct timeval tv, difftime, curtime, lasttime, *timeout; fd_set rfds, readers; int nfds, n, i, secs, ch; struct sigaction sa; time_t boottime; struct option long_options[] = { {"config", 1, 0, 'c'}, {"debug", 2, 0, 'd'}, {"foreground", 0, 0, 'f'}, {"disable-vifs", 0, 0, 'N'}, {"help", 0, 0, 'h'}, {"version", 0, 0, 'v'}, {"quit-daemon", 0, 0, 'q'}, {"reload-config", 0, 0, 'l'}, {"show-routes", 0, 0, 'r'}, /* {"show-cache", 0, 0, 'i'}, */ /* {"show-debug", 0, 0, 'p'}, */ {0, 0, 0, 0} }; snprintf(versionstring, sizeof (versionstring), "pimd version %s", todaysversion); while ((ch = getopt_long (argc, argv, "c:d::fhlNP::vqr", long_options, NULL)) != EOF) { switch (ch) { case 'c': configfilename = optarg; break; case 'd': if (!optarg) { debug = DEBUG_DEFAULT; } else { char *p,*q; size_t i, len; struct debugname *d; debug = 0; p = optarg; q = NULL; while (p) { q = strchr(p, ','); if (q) *q++ = '\0'; len = strlen(p); for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++) if (len >= d->nchars && strncmp(d->name, p, len) == 0) break; if (i == ARRAY_LEN(debugnames)) return usage(); debug |= d->level; p = q; } } break; case 'f': foreground = 1; break; case 'h': return usage(); case 'l': killshow(SIGHUP, NULL); return 0; case 'N': disable_all_by_default = 1; break; case 'P': #ifdef SNMP if (!optarg) dest_port = DEFAULT_PORT; else { dest_port = strtonum(optarg, 1, 65535, &errstr); if (errstr) { warnx("destination port %s", errstr); dest_port = DEFAULT_PORT; } } #else warnx("SNMP support missing, please feel free to submit a patch."); #endif break; case 'v': printf("%s\n", versionstring); return 0; case 'q': killshow(SIGTERM, NULL); return 0; case 'r': killshow(SIGUSR1, _PATH_PIMD_DUMP); return 0; #if 0 /* XXX: TODO */ case 'i': killshow(SIGUSR2, _PATH_PIMD_CACHE); return 0; case 'p': killshow(SIGQUIT, NULL); return 0; #endif default: return usage(); } } argc -= optind; argv += optind; if (argc > 0) { return usage(); } if (geteuid() != 0) { fprintf(stderr, "%s: must be root\n", __progname); exit(1); } setlinebuf(stderr); if (debug != 0) { struct debugname *d; char c; int tmpd = debug; fprintf(stderr, "debug level 0x%lx ", debug); c = '('; for (d = debugnames; d < debugnames + ARRAY_LEN(debugnames); d++) { if ((tmpd & d->level) == d->level) { tmpd &= ~d->level; fprintf(stderr, "%c%s", c, d->name); c = ','; } } fprintf(stderr, ")\n"); } /* * Create directory for runtime files */ mkdir(_PATH_PIMD_RUNDIR, 0755); /* * Setup logging */ #ifdef LOG_DAEMON (void)openlog("pimd", LOG_PID, LOG_DAEMON); (void)setlogmask(LOG_UPTO(LOG_NOTICE)); #else (void)openlog("pimd", LOG_PID); #endif /* LOG_DAEMON */ logit(LOG_DEBUG, 0, "%s starting", versionstring); do_randomize(); time(&boottime); /* Start up the log rate-limiter */ resetlogging(NULL); callout_init(); init_igmp(); init_pim(); #ifdef HAVE_ROUTING_SOCKETS init_routesock(); #endif /* HAVE_ROUTING_SOCKETS */ init_pim_mrt(); init_timers(); /* TODO: check the kernel DVMRP/MROUTED/PIM support version */ #ifdef SNMP if (i = snmp_init()) return i; #endif /* SNMP */ init_vifs(); init_rp_and_bsr(); /* Must be after init_vifs() */ #ifdef RSRR rsrr_init(); #endif /* RSRR */ sa.sa_handler = handler; sa.sa_flags = 0; /* Interrupt system calls */ sigemptyset(&sa.sa_mask); sigaction(SIGALRM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR2, &sa, NULL); FD_ZERO(&readers); FD_SET(igmp_socket, &readers); nfds = igmp_socket + 1; for (i = 0; i < nhandlers; i++) { FD_SET(ihandlers[i].fd, &readers); if (ihandlers[i].fd >= nfds) nfds = ihandlers[i].fd + 1; } IF_DEBUG(DEBUG_IF) dump_vifs(stderr); IF_DEBUG(DEBUG_PIM_MRT) dump_pim_mrt(stderr); /* schedule first timer interrupt */ timer_setTimer(TIMER_INTERVAL, timer, NULL); if (!debug && !foreground) { /* Detach from the terminal */ haveterminal = 0; if (fork()) exit(0); (void)close(0); (void)close(1); (void)close(2); (void)open("/", 0); (void)dup2(0, 1); (void)dup2(0, 2); #ifdef SYSV (void)setpgrp(); #else #ifdef TIOCNOTTY n = open("/dev/tty", 2); if (n >= 0) { (void)ioctl(n, TIOCNOTTY, (char *)0); (void)close(n); } #else if (setsid() < 0) perror("setsid"); #endif /* TIOCNOTTY */ #endif /* SYSV */ } /* End of child process code */ if (pidfile(NULL)) { warn("Cannot create pidfile"); } /* * Main receive loop. */ dummy = 0; dummysigalrm = SIGALRM; difftime.tv_usec = 0; gettimeofday(&curtime, NULL); lasttime = curtime; while (1) { memcpy(&rfds, &readers, sizeof(rfds)); secs = timer_nextTimer(); if (secs == -1) timeout = NULL; else { timeout = &tv; timeout->tv_sec = secs; timeout->tv_usec = 0; } if (boottime) { time_t n; time(&n); if (n > boottime + 15) { struct rp_hold *rph = g_rp_hold; while(rph) { add_rp_grp_entry(&cand_rp_list, &grp_mask_list, rph->address, 1, (u_int16)0xffffff, rph->group, rph->mask, curr_bsr_hash_mask, curr_bsr_fragment_tag); rph = rph->next; } boottime = 0; } } if (sighandled) { if (sighandled & GOT_SIGINT) { sighandled &= ~GOT_SIGINT; break; } if (sighandled & GOT_SIGHUP) { sighandled &= ~GOT_SIGHUP; restart(SIGHUP); /* reconstruct readers and nfds */ FD_ZERO(&readers); FD_SET(igmp_socket, &readers); nfds = igmp_socket + 1; for (i = 0; i < nhandlers; i++) { FD_SET(ihandlers[i].fd, &readers); if (ihandlers[i].fd >= nfds) nfds = ihandlers[i].fd + 1; } memcpy(&rfds, &readers, sizeof(rfds)); } if (sighandled & GOT_SIGUSR1) { sighandled &= ~GOT_SIGUSR1; fdump(SIGUSR1); } if (sighandled & GOT_SIGUSR2) { sighandled &= ~GOT_SIGUSR2; cdump(SIGUSR2); } if (sighandled & GOT_SIGALRM) { sighandled &= ~GOT_SIGALRM; timer(&dummysigalrm); } } if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) { if (errno != EINTR) /* SIGALRM is expected */ logit(LOG_WARNING, errno, "select failed"); continue; } if (n > 0) { /* TODO: shall check first igmp_socket for better performance? */ for (i = 0; i < nhandlers; i++) { if (FD_ISSET(ihandlers[i].fd, &rfds)) { (*ihandlers[i].func)(ihandlers[i].fd, &rfds); } } } /* * Handle timeout queue. * * If select + packet processing took more than 1 second, * or if there is a timeout pending, age the timeout queue. * * If not, collect usec in difftime to make sure that the * time doesn't drift too badly. * * If the timeout handlers took more than 1 second, * age the timeout queue again. XXX This introduces the * potential for infinite loops! */ do { /* * If the select timed out, then there's no other * activity to account for and we don't need to * call gettimeofday. */ if (n == 0) { curtime.tv_sec = lasttime.tv_sec + secs; curtime.tv_usec = lasttime.tv_usec; n = -1; /* don't do this next time through the loop */ } else gettimeofday(&curtime, NULL); difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec; difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec; while (difftime.tv_usec >= 1000000) { difftime.tv_sec++; difftime.tv_usec -= 1000000; } if (difftime.tv_usec < 0) { difftime.tv_sec--; difftime.tv_usec += 1000000; } lasttime = curtime; if (secs == 0 || difftime.tv_sec > 0) age_callout_queue(difftime.tv_sec); secs = -1; } while (difftime.tv_sec > 0); } /* Main loop */ logit(LOG_NOTICE, 0, "%s exiting", versionstring); cleanup(); exit(0); }
int main(int argc, char *argv[]) { register int recvlen; socklen_t dummy; struct timeval tv, difftime, curtime, lasttime, *timeout; int foreground = 0; fd_set rfds, readers; int nfds, n, i, secs, ch; struct sigaction sa; while ((ch = getopt(argc, argv, "fh")) != EOF) { switch (ch) { case 'f': foreground = 1; break; case 'h': usage(); break; default: usage(); } } argc -= optind; argv += optind; if (argc > 0) usage(); if (geteuid() != 0) { fprintf(stderr, "%s: must be root\n", __progname); exit(1); } setlinebuf(stderr); callout_init(); init_igmp(); init_vifs(); sa.sa_handler = handler; sa.sa_flags = 0; /* Interrupt system calls */ sigemptyset(&sa.sa_mask); sigaction(SIGHUP, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); sigaction(SIGUSR2, &sa, NULL); FD_ZERO(&readers); if (igmp_socket >= (int)FD_SETSIZE) logit("Descriptor too big"); FD_SET(igmp_socket, &readers); nfds = igmp_socket + 1; for (i = 0; i < nhandlers; i++) { if (ihandlers[i].fd >= (int)FD_SETSIZE) logit("Descriptor too big"); FD_SET(ihandlers[i].fd, &readers); if (ihandlers[i].fd >= nfds) nfds = ihandlers[i].fd + 1; } timer_setTimer(TIMER_INTERVAL, timer, NULL); if (!foreground) { /* Detach from the terminal */ haveterminal = 0; if (fork()) exit(0); (void)close(0); (void)close(1); (void)close(2); (void)open("/", 0); (void)dup2(0, 1); (void)dup2(0, 2); } /* * Main receive loop. */ dummy = 0; difftime.tv_usec = 0; gettimeofday(&curtime, NULL); lasttime = curtime; for(;;) { memmove ((char *)&rfds, (char *)&readers, sizeof(rfds)); secs = timer_nextTimer(); if (secs == -1) timeout = NULL; else { timeout = &tv; timeout->tv_sec = secs; timeout->tv_usec = 0; } if (sighandled) { if (sighandled & GOT_SIGINT) { sighandled &= ~GOT_SIGINT; break; } } if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) { if (errno != EINTR) logit("select failed"); continue; } if (n > 0) { if (FD_ISSET(igmp_socket, &rfds)) { recvlen = recvfrom(igmp_socket, recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy); if (recvlen < 0) { if (errno != EINTR) logit("recvfrom"); continue; } accept_igmp(recvlen); } for (i = 0; i < nhandlers; i++) { if (FD_ISSET(ihandlers[i].fd, &rfds)) { (*ihandlers[i].func)(ihandlers[i].fd, &rfds); } } } /* * Handle timeout queue. * * If select + packet processing took more than 1 second, * or if there is a timeout pending, age the timeout queue. * * If not, collect usec in difftime to make sure that the * time doesn't drift too badly. * * If the timeout handlers took more than 1 second, * age the timeout queue again. XXX This introduces the * potential for infinite loops! */ do { /* * If the select timed out, then there's no other * activity to account for and we don't need to * call gettimeofday. */ if (n == 0) { curtime.tv_sec = lasttime.tv_sec + secs; curtime.tv_usec = lasttime.tv_usec; n = -1; /* don't do this next time through the loop */ } else gettimeofday(&curtime, NULL); difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec; difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec; while (difftime.tv_usec > 1000000) { difftime.tv_sec++; difftime.tv_usec -= 1000000; } if (difftime.tv_usec < 0) { difftime.tv_sec--; difftime.tv_usec += 1000000; } lasttime = curtime; if (secs == 0 || difftime.tv_sec > 0) age_callout_queue(difftime.tv_sec); secs = -1; } while (difftime.tv_sec > 0); } cleanup(); exit(0); }
static void timer(void UNUSED *arg) { query_groups(); timer_setTimer(TIMER_INTERVAL, timer, NULL); }