/** * Main daemon loop. */ void igmpProxyRun() { // Get the config. //struct Config *config = getCommonConfig(); // Set some needed values. register int recvlen; int MaxFD, Rt, secs; fd_set ReadFDS; socklen_t dummy = 0; struct timeval curtime, lasttime, difftime, tv; // The timeout is a pointer in order to set it to NULL if nessecary. struct timeval *timeout = &tv; // Initialize timer vars difftime.tv_usec = 0; gettimeofday(&curtime, NULL); lasttime = curtime; // First thing we send a membership query in downstream VIF's... sendGeneralMembershipQuery(); // Loop until the end... for (;;) { // Process signaling... if (sighandled) { if (sighandled & GOT_SIGINT) { sighandled &= ~GOT_SIGINT; my_log(LOG_NOTICE, 0, "Got a interupt signal. Exiting."); break; } } // Prepare timeout... secs = timer_nextTimer(); if(secs == -1) { timeout = NULL; } else { timeout->tv_usec = 0; timeout->tv_sec = secs; } // Prepare for select. MaxFD = MRouterFD; FD_ZERO( &ReadFDS ); FD_SET( MRouterFD, &ReadFDS ); // wait for input Rt = select( MaxFD +1, &ReadFDS, NULL, NULL, timeout ); // log and ignore failures if( Rt < 0 ) { my_log( LOG_WARNING, errno, "select() failure" ); continue; } else if( Rt > 0 ) { // Read IGMP request, and handle it... if( FD_ISSET( MRouterFD, &ReadFDS ) ) { recvlen = recvfrom(MRouterFD, recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy); if (recvlen < 0) { if (errno != EINTR) my_log(LOG_ERR, errno, "recvfrom"); continue; } 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_usec = lasttime.tv_usec; Rt = -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); } }
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); }
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); }
/** * Main daemon loop. */ void igmpProxyRun() { // Get the config. //struct Config *config = getCommonConfig(); // Set some needed values. register int recvlen; int MaxFD, Rt, secs; fd_set ReadFDS; int dummy = 0; #ifdef TRENDCHIP struct timespec curtime, lasttime, difftime, tv; #else struct timeval curtime, lasttime, difftime, tv; #endif // The timeout is a pointer in order to set it to NULL if nessecary. struct timeval *timeout = &tv; // Initialize timer vars #ifdef TRENDCHIP difftime.tv_nsec = 0; clock_gettime(CLOCK_MONOTONIC, &curtime); #else difftime.tv_usec = 0; gettimeofday(&curtime, NULL); #endif lasttime = curtime; // First thing we send a membership query in downstream VIF's... sendGeneralMembershipQuery(); // Loop until the end... for (;;) { // Process signaling... if (sighandled) { if (sighandled & GOT_SIGINT) { sighandled &= ~GOT_SIGINT; log(LOG_NOTICE, 0, "Got a interupt signal. Exiting."); break; } } // Prepare timeout... secs = timer_nextTimer(); if(secs == -1) { timeout = NULL; } else { timeout->tv_usec = 0; timeout->tv_sec = secs; } // Prepare for select. MaxFD = MRouterFD; FD_ZERO( &ReadFDS ); FD_SET( MRouterFD, &ReadFDS ); // wait for input Rt = select( MaxFD +1, &ReadFDS, NULL, NULL, timeout ); // log and ignore failures if( Rt < 0 ) { log( LOG_WARNING, errno, "select() failure" ); continue; } else if( Rt > 0 ) { // Read IGMP request, and handle it... if( FD_ISSET( MRouterFD, &ReadFDS ) ) { recvlen = recvfrom(MRouterFD, recv_buf, RECV_BUF_SIZE, 0, NULL, &dummy); if (recvlen < 0) { if (errno != EINTR) log(LOG_ERR, errno, "recvfrom"); continue; } #ifdef TCSUPPORT_IGMP_QOS int len = sizeof(uint32); if (getsockopt(MRouterFD, SOL_IP, IP_SKB_MARK, &skb_mark, &len)) { /* dbg_info */ ;//tcdbg_printf("%s,getsockopt error\n", __FUNCTION__); } //tcdbg_printf("xyz_dbg:%s, skb_mark is %x\n", __FUNCTION__, skb_mark); #endif 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; #ifdef TRENDCHIP curtime.tv_nsec = lasttime.tv_nsec; #else curtime.tv_usec = lasttime.tv_usec; #endif Rt = -1; /* don't do this next time through the loop */ } else { #ifdef TRENDCHIP clock_gettime(CLOCK_MONOTONIC, &curtime); #else gettimeofday(&curtime, NULL); #endif } #ifdef TRENDCHIP 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; } #else 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; } #endif lasttime = curtime; if (secs == 0 || difftime.tv_sec > 0) age_callout_queue(difftime.tv_sec); secs = -1; } while (difftime.tv_sec > 0); } }