From 2560322c71d5e3fb7b653c44006de8ab5de083a3 Mon Sep 17 00:00:00 2001 From: uglymotha Date: Sun, 21 Jul 2024 15:23:49 +0000 Subject: [PATCH] Unifying code --- src/cli.c | 28 +++++-------- src/config.c | 46 +++++++++----------- src/ifvc.c | 8 +--- src/igmp.c | 5 +-- src/igmpv3proxy.c | 104 +++++++++++++++++++--------------------------- src/igmpv3proxy.h | 43 +++++++++---------- src/kern.c | 21 ++++------ src/lib.c | 17 +++----- src/mctable.c | 4 +- src/querier.c | 2 + src/timers.c | 27 ++++++------ 11 files changed, 128 insertions(+), 177 deletions(-) diff --git a/src/cli.c b/src/cli.c index 5569b2f..b15ad3d 100644 --- a/src/cli.c +++ b/src/cli.c @@ -56,13 +56,10 @@ int openCliFd(void) { cli_sa.sun_family = AF_UNIX; // Open the socket, set permissions and mode. - if ( ! strcpy(cli_sa.sun_path, CONF->runPath) -#ifdef __linux__ + if (cli_fd == -1) { + if ( ! strcpy(cli_sa.sun_path, CONF->runPath) || ! snprintf(cli_sa.sun_path + strlen(cli_sa.sun_path), PATH_MAX - strlen(cli_sa.sun_path), mrt_tbl ? "cli-%d.sock" : "cli.sock", mrt_tbl) -#else - || ! strcat(cli_sa.sun_path, "cli.sock") -#endif || (stat(cli_sa.sun_path, &st) == 0 && unlink(cli_sa.sun_path) < 0) || ! (cli_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0)) #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN @@ -74,11 +71,11 @@ int openCliFd(void) { || listen(cli_fd, CONF->reqQsz) < 0 || ( chown(cli_sa.sun_path, CONF->user ? CONF->user->pw_uid : -1, CONF->group->gr_gid)) || chmod(cli_sa.sun_path, 0660)) { - LOG(LOG_WARNING, errno, "Cannot open CLI Socket %s. CLI connections will not be available.", cli_sa.sun_path); - cli_fd = -1; - } else - LOG(LOG_INFO, 0, "openCliFd: Opened CLI socket %s.", cli_sa.sun_path); - + LOG(LOG_WARNING, errno, "Cannot open CLI Socket %s. CLI connections will not be available.", cli_sa.sun_path); + cli_fd = -1; + } else + LOG(LOG_INFO, 0, "openCliFd: Opened CLI socket %s.", cli_sa.sun_path); + } return cli_fd; } @@ -106,7 +103,7 @@ int closeCliFd(void) { */ void acceptCli(void) { - int pid = 0, fd = -1, len = 0, s = sizeof(struct sockaddr); + int pid = -1, fd = -1, len = 0, s = sizeof(struct sockaddr); uint32_t addr = (uint32_t)-1, mask = (uint32_t)-1; char buf[CLI_CMD_BUF] = {0}, msg[CLI_CMD_BUF]; struct sockaddr cli_sa; @@ -125,10 +122,8 @@ void acceptCli(void) sighandled |= buf[0] == 'c' ? GOT_SIGUSR1 : GOT_SIGUSR2; buf[0] == 'c' ? send(fd, "Reloading Configuration.\n", 26, MSG_DONTWAIT) : send(fd, "Rebuilding Interfaces.\n", 24, MSG_DONTWAIT); -#ifdef __linux__ - IF_FOR_IF(mrt_tbl < 0, int i = 0; i < chld.nr; i++, chld.c[i].pid > 0) + IF_FOR_IF(mrt_tbl < 0 && chld.nr, int i = 0; i < chld.nr; i++, chld.c[i].pid > 0) kill(chld.c[i].pid, buf[0] == 'c' ? SIGUSR1 : SIGUSR2); -#endif } else if ((pid = fork()) != 0) pid < 0 ? LOG(LOG_WARNING, eNOFORK, "Cannot fork().") : LOG(LOG_DEBUG, 0, "acceptCli: Forked PID: %d", pid); if (pid != 0 || buf[0] == 'c' || buf[0] == 'b') { @@ -150,9 +145,9 @@ void acceptCli(void) debugQueue("", len > 1 && buf[1] == 'h' ? 0 : 1, fd); } else if (buf[0] == 'm') { getMemStats(buf[1] == 'h' ? 0 : 1, fd); -#ifdef __linux__ } else if (buf[0] == 'p' && mrt_tbl < 0) { - send(fd, "Currently Running Processes:\n", 29, MSG_DONTWAIT); + sprintf(msg, "Monitor PID: %d\n", getppid()); + send(fd, msg, strlen(msg), MSG_DONTWAIT); for (int i = 0; i < chld.nr; i++) { if (chld.c[i].pid > 0) sprintf(msg, "Table: %d - PID: %d\n", chld.c[i].tbl, chld.c[i].pid); @@ -163,7 +158,6 @@ void acceptCli(void) } else if (buf[0] == 'p' && mrt_tbl >= 0) { sprintf(msg, "Table: %d - PID: %d\n", mrt_tbl, getppid()); send(fd, msg, strlen(msg), MSG_DONTWAIT); -#endif } else send(fd, "GO AWAY\n", 9, MSG_DONTWAIT); diff --git a/src/config.c b/src/config.c index f72355b..5ab008a 100644 --- a/src/config.c +++ b/src/config.c @@ -399,8 +399,6 @@ static inline bool parsePhyintToken(char *token) { else { tmpPtr->tbl = intToken; LOG(LOG_INFO, 0, "Config (%s): Assigning to table %d.", tmpPtr->name, intToken); - if (intToken > 0 && mrt_tbl < 0) - igmpProxyFork(0); if (mrt_tbl < 0) // Check again becasue of fork(). igmpProxyFork(intToken); } @@ -661,11 +659,8 @@ bool loadConfig(char *cfgFile) { LOG(LOG_NOTICE, 0, "Config: Default table id should be between 0 and 999999999."); else { conf.defaultTable = intToken; - if (mrt_tbl < 0 && conf.defaultTable > 0) { - igmpProxyFork(0); - if (mrt_tbl < 0) // Check again because of fork(). - igmpProxyFork(conf.defaultTable); - } + if (mrt_tbl < 0 && conf.defaultTable > 0) + igmpProxyFork(conf.defaultTable); LOG(LOG_NOTICE, 0, "Config: Default to table %d for interfaces.", conf.defaultTable); } #else @@ -952,10 +947,6 @@ bool loadConfig(char *cfgFile) { timers.bwControl = timer_setTimer(conf.bwControlInterval * 10, "Bandwidth Control", bwControl, &timers.bwControl); } -#ifdef __linux__ - if (mrt_tbl < 0 && !chld.nr) - mrt_tbl = 0; -#endif return !logwarning; } @@ -1007,7 +998,7 @@ void configureVifs(void) { struct IfDesc *IfDp = NULL; struct vifConfig *vconf = NULL, *oconf = NULL; struct filters *fil, *ofil; - bool quickLeave = false; + bool quickLeave = false, tbl0 = false; uint32_t vifcount = 0, upvifcount = 0, downvifcount = 0; uVifs = 0; @@ -1037,6 +1028,8 @@ void configureVifs(void) { oconf = IfDp->conf; IfDp->conf = vconf; } + if (!SHUTDOWN && !IFREBUILD && mrt_tbl < 0 && chld.nr && IfDp->conf->tbl == 0 && !tbl0++) + igmpProxyFork(0); // Evaluate to old and new state of interface. if (!CONFRELOAD && !(IfDp->state & 0x40)) { @@ -1050,15 +1043,15 @@ void configureVifs(void) { } else // Existing interface, oldstate is current state, newstate is configured state. IfDp->state = ((IfDp->state & 0x3) << 2) | (IfDp->mtu && (IfDp->Flags & IFF_MULTICAST) ? IfDp->conf->state : 0); -#ifdef __linux__ - if (mrt_tbl >= 0 && IfDp->conf->tbl != mrt_tbl) { + + if (IfDp->conf->tbl != mrt_tbl) { // Check if Interface is in table for current process. LOG(LOG_NOTICE, 0, "Not enabling table %d interface %s", IfDp->conf->tbl, IfDp->Name); IfDp->state &= ~0x3; // Keep old state, new state disabled. - } else if (mrt_tbl < 0) - // Monitor process only needs config and state. + } + if (mrt_tbl < 0) + // Monitor process only needs config. continue; -#endif register uint8_t oldstate = IF_OLDSTATE(IfDp), newstate = IF_NEWSTATE(IfDp); quickLeave |= !IS_DISABLED(IfDp->state) && IfDp->conf->quickLeave; @@ -1095,19 +1088,21 @@ void configureVifs(void) { if (IS_UPSTREAM(newstate)) { upvifcount++; BIT_SET(uVifs, IfDp->index); - } + } else + BIT_CLR(uVifs, IfDp->index); } // Do maintenance on vifs according to their old and new state. - if ( IS_DISABLED(oldstate) && IS_UPSTREAM(newstate)) { ctrlQuerier(1, IfDp); clearGroups(IfDp); } - else if ((STARTUP || IS_DISABLED(oldstate)) && IS_DOWNSTREAM(newstate)) { ctrlQuerier(1, IfDp); } - else if (!STARTUP && !IS_DISABLED(oldstate) && IS_DISABLED(newstate)) { ctrlQuerier(0, IfDp); clearGroups(IfDp); } - else if (!STARTUP && oldstate != newstate) { ctrlQuerier(2, IfDp); clearGroups(IfDp); } - else if ( oldstate == newstate && !IS_DISABLED(newstate)) { if (!IFREBUILD) clearGroups(IfDp); } + if ( IS_DISABLED(oldstate) && IS_UPSTREAM(newstate)) { ctrlQuerier(1, IfDp); clearGroups(IfDp); } + else if ((STARTUP || IS_DISABLED(oldstate)) && IS_DOWNSTREAM(newstate)) { ctrlQuerier(1, IfDp); } + else if (!STARTUP && !IS_DISABLED(oldstate) && IS_DISABLED(newstate)) { ctrlQuerier(0, IfDp); clearGroups(IfDp); } + else if (!STARTUP && oldstate != newstate) { ctrlQuerier(2, IfDp); clearGroups(IfDp); } + else if ( IFREBUILD && oldstate == newstate && !IS_DISABLED(newstate)) { clearGroups(IfDp); } IfDp->filCh = false; // Check if vif needs to be removed. if (IS_DISABLED(newstate) && IfDp->index != (uint8_t)-1) { + BIT_CLR(uVifs, IfDp->index); k_delVIF(IfDp); if (vifcount) vifcount--; @@ -1117,11 +1112,10 @@ void configureVifs(void) { upvifcount--; } } -#ifdef __linux__ if (mrt_tbl < 0) // Monitor process only needs config and state. return; -#endif + // Set hashtable size to 0 when quickleave is not enabled on any interface. if (!quickLeave) { LOG(LOG_NOTICE, 0, "Disabling quickleave, no interfaces have it enabled."); @@ -1138,5 +1132,5 @@ void configureVifs(void) { // All vifs created / updated, check if there is an upstream and at least one downstream. if (!SHUTDOWN && !RESTART && (vifcount < 2 || upvifcount == 0 || downvifcount == 0)) - LOG(LOG_ERR, eNOCONF, "There must be at least 2 interfaces, 1 upstream and 1 dowstream."); + LOG(LOG_ERR, 0 - eNOINIT, "There must be at least 2 interfaces, 1 upstream and 1 dowstream."); } diff --git a/src/ifvc.c b/src/ifvc.c index 21536d2..39cdb69 100644 --- a/src/ifvc.c +++ b/src/ifvc.c @@ -72,7 +72,7 @@ void rebuildIfVc(uint64_t *tid) { // Build new IfDEsc table on SIGHUP, SIGUSR2 or timed rebuild. if (tid) sigstatus |= GOT_SIGUSR2; - if (!IfDescL || !(CONFRELOAD || SHUTDOWN || RESTART)) + if (! IfDescL || IFREBUILD || SHUP || STARTUP) buildIfVc(); // Call configureVifs to link the new IfDesc table. @@ -211,11 +211,7 @@ void getIfStats(struct IfDesc *IfDp, int h, int fd) { sprintf(buf, "%lu,%lu\n", IfDp->rqCnt, IfDp->sqCnt); send(fd, buf, strlen(buf), MSG_DONTWAIT); return; -#ifdef __linux__ - } else for (IFL(IfDp), i++) if (!mrt_tbl || !IS_DISABLED(IfDp->state)) { -#else - } else for (IFL(IfDp), i++) { -#endif + } else for (IFL(IfDp), i++) if (mrt_tbl == -1 || !chld.nr || !IS_DISABLED(IfDp->state)) { if (h) { total = (struct totals){ total.bytes + IfDp->bytes, total.rate + IfDp->rate, total.ratelimit + IfDp->conf->ratelimit }; strcpy(msg, "%4d |%15s| %2d| v%1d|%15s|%12s|%8s|%10s|%15s|%14lld B | %10lld B/s | %10lld B/s\n"); diff --git a/src/igmp.c b/src/igmp.c index 6b2b13e..9615d68 100644 --- a/src/igmp.c +++ b/src/igmp.c @@ -70,10 +70,9 @@ int initIgmp(bool activate) { } if (fd == -1) fd = k_enableMRouter(); -#ifdef __linux__ if (mrt_tbl < 0) return fd; -#endif + if (! _calloc(rcv_buf, 1, rcv, CONF->pBufsz) || ! _calloc(snd_buf, 1, snd, CONF->pBufsz)) LOG(LOG_ERR, eNOMEM, "initIgmp: Out of Memory."); // Freed by Self struct ip *ip = (struct ip *)snd_buf; @@ -125,7 +124,7 @@ static bool checkIgmp(struct IfDesc *IfDp, register uint32_t src, register uint3 inetFmt(group,1), IfDp->Name, inetFmt(src, 2)); else if (src == IfDp->InAdr.s_addr || (IfDp->querier.ip == IfDp->conf->qry.ip && src == IfDp->querier.ip)) LOG(LOG_DEBUG, 0, "checkIgmp: The request from %s on %s is from myself. Ignoring.", inetFmt(src, 1), IfDp->Name); - else if ((IfDp->state & ifstate) == 0) { + else if ((IfDp->state & ifstate) == 0 || IfDp->conf->tbl != mrt_tbl) { strcat(strcpy(msg, ""), IS_UPSTREAM(IfDp->state) ? "upstream interface " : IS_DOWNSTREAM(IfDp->state) ? "downstream interface " : "disabled interface "); LOG(LOG_INFO, 0, "checkIgmp: Message for %s from %s was received on %s interface %s. Ignoring.", diff --git a/src/igmpv3proxy.c b/src/igmpv3proxy.c index 51958e2..617a40f 100644 --- a/src/igmpv3proxy.c +++ b/src/igmpv3proxy.c @@ -54,10 +54,8 @@ char *rcv_buf = NULL, *fileName, tS[32], tE[32], RUNPATH[] = RUN struct memstats memuse = { 0 }, memalloc = { 0 }, memfree = { 0 }; static struct pollfd pollFD[2] = { {-1, POLLIN, 0}, {-1, POLLIN, 0} }; const struct timespec nto = { 0, 0 }; -#ifdef __linux__ int mrt_tbl = -1; struct chld chld = { 0 }; -#endif /** * Program main method. Is invoked when the program is started @@ -297,7 +295,6 @@ static void igmpProxyRun(void) { LOG(LOG_WARNING, 0, "%s", SHUTDOWN ? "SIGTERM: Exiting." : "SIGURG: Restarting"); } -#ifdef __linux__ /** * Start a new igmpv3proxy process for route table. */ @@ -317,7 +314,7 @@ void igmpProxyFork(int tbl) { // Do not increase the nr. childs here if an emtpy spot was found and check validity. LOG(LOG_ERR, eNOFORK, "igmpProxyFork: Cannot fork() child %d.", chld.nr); } else if (pid == 0) { - // Child initializes its own start time. + // Child initializes its own start time, Closes sockets in use by monitor and opens new ones. clock_gettime(CLOCK_REALTIME, &starttime); strcpy(tS, asctime(localtime(&starttime.tv_sec))); tS[strlen(tS) - 1] = '\0'; @@ -325,6 +322,8 @@ void igmpProxyFork(int tbl) { chld.nr = i + 1; // Just so that we know who we are. _free(chld.c, var, (((chld.nr - 1) / 32) + 1) * 32 * sizeof(struct pt)); // Alloced by Self. sigstatus = 1; + pollFD[0].fd = initIgmp(false), pollFD[1].fd = closeCliFd(); + pollFD[0].fd = initIgmp(true), pollFD[1].fd = openCliFd(); } else { // Parent sets the new child info in table. chld.c[i].tbl = tbl; @@ -390,8 +389,6 @@ static void igmpProxyMonitor(void) { timeout = timer_ageQueue(); if (mrt_tbl >= 0) { // SIGCHLD, ageQueue() or loadConfig() may have forked new proxy. - pollFD[0].fd = initIgmp(false), pollFD[1].fd = closeCliFd(); - pollFD[0].fd = initIgmp(true), pollFD[1].fd = openCliFd(); rebuildIfVc(NULL); return; // To igmpProxyInit() } @@ -402,13 +399,11 @@ static void igmpProxyMonitor(void) { LOG(LOG_ERR, eABNRML, "igmpProxyMonitor: Proceses exited."); } -#endif /** * Handles the initial startup of the daemon. Contains OS Specics. */ static void igmpProxyInit(void) { - pid_t pid = -1; struct stat st; sigstatus = 1; // STARTUP @@ -425,19 +420,18 @@ static void igmpProxyInit(void) { LOG(LOG_WARNING, errno, "Config: Failed to get group for %d.", CONF->user ? CONF->user->pw_gid : 0); unsigned int uid = CONF->user ? CONF->user->pw_uid : 0, gid = CONF->group->gr_gid; -#ifdef __linux__ if (mrt_tbl < 0) { // Write PID in main daemon process only. -#endif - char pidFile[strlen(CONF->runPath) + strlen(fileName) + 5]; - sprintf(pidFile, "%s/%s.pid", CONF->runPath, fileName); - remove(pidFile); - FILE *pidFilePtr = fopen(pidFile, "w"); - fprintf(pidFilePtr, "%d\n", getpid()); - fclose(pidFilePtr); -#ifdef __linux__ + if (!chld.nr) + mrt_tbl = 0; + char pidFile[strlen(CONF->runPath) + strlen(fileName) + 5]; + sprintf(pidFile, "%s/%s.pid", CONF->runPath, fileName); + remove(pidFile); + FILE *pidFilePtr = fopen(pidFile, "w"); + fprintf(pidFilePtr, "%d\n", getpid()); + fclose(pidFilePtr); } -#endif + // Change ownership of run directory. if (chown(CONF->runPath, uid, gid) < 0) LOG(LOG_ERR, eNOINIT, "Failed to change ownership of %s to %s:%s.", @@ -466,15 +460,13 @@ static void igmpProxyInit(void) { LOG(LOG_WARNING, errno, "Failed to chown log file %s to %s.", CONF->logFilePath, CONF->user->pw_name); SETSIGS; - // Enable mroute and open cli socket and add ip mrules while still running as root. - pollFD[0].fd = initIgmp(true); - pollFD[1].fd = openCliFd(); + // Enable mroute and open cli socket and go to monitor in case of multiple tables.. + if (mrt_tbl < 0 || !chld.nr) + pollFD[0].fd = initIgmp(true), pollFD[1].fd = openCliFd();; rebuildIfVc(NULL); -#ifdef __linux__ - // When multiple tables are in use, process for default table 0 is forked off here. if (mrt_tbl < 0) igmpProxyMonitor(); -#endif + // Make sure logfile and chroot directory are owned by configured user and switch ids. if (CONF->user && geteuid() == 0) { unsigned int uid = CONF->user ? CONF->user->pw_uid : 0, gid = CONF->group->gr_gid; @@ -487,61 +479,58 @@ static void igmpProxyInit(void) { } /** -* Clean up all on exit... +* Shutdown all interfaces, queriers, remove all routes, close sockets. */ void igmpProxyCleanUp(int code) { struct timespec endtime; - // Shutdown all interfaces, queriers, remove all routes, close sockets. -#ifdef __linux__ int size = (((chld.nr - 1) / 32) + 1) * 32 * sizeof(struct pt); + if (!code && mrt_tbl < 0) code = 0; else if (!code) code = 15; - if (mrt_tbl < 0 && chld.c && !RESTART) { + if (mrt_tbl < 0 && !RESTART) { pid_t pid; // Wait for all childs. Cli processes are not tracked, their fds are closed. LOG(LOG_INFO, 0, "Waiting for %d processes to finish.", chld.nr); while ((pid = wait(NULL)) > 0 && chld.nr) { - FOR_IF(int i = 0; i < chld.nr; i++, chld.c[i].pid == pid && chld.c[i].tbl > 0 && --chld.nr) { - ipRules(chld.c[i].tbl, false); + FOR_IF(int i = 0; i < chld.nr; i++, chld.c[i].pid == pid) { + chld.nr--; + if (chld.c[i].tbl > 0) + ipRules(chld.c[i].tbl, false); LOG(LOG_NOTICE, 0, "Still waiting for %d process%s to finish.", chld.nr, chld.nr > 1 ? "es" : ""); } } _free(chld.c, var, size); // Alloced by igmpProxyFork() LOG(LOG_NOTICE, 0, "All processes finished."); } -#endif - // Remove all interfaces. - rebuildIfVc(NULL); - // Remove MRT, CLI socket and PID file and Config in main daemon only. + // Remove all interfaces, CLI socket, PID file and Config. + rebuildIfVc(NULL); pollFD[1].fd = closeCliFd(), pollFD[0].fd = initIgmp(false); -#ifdef __linux__ - if (mrt_tbl < 0) -#endif - if (!RESTART && CONF->runPath) { - char rFile[strlen(CONF->runPath) + strlen(fileName) + 5]; - sprintf(rFile, "%s%s.pid", CONF->runPath, fileName); - remove(rFile); - sprintf(rFile, "%scli.sock", CONF->runPath); - remove(rFile); - if (rmdir(CONF->runPath) < 0) - LOG(LOG_WARNING, errno, "Cannot remove run dir %s.", CONF->runPath); - } + if ((mrt_tbl < 0 || !chld.nr) && !RESTART && CONF->runPath) { + char rFile[strlen(CONF->runPath) + strlen(fileName) + 5]; + sprintf(rFile, "%s%s.pid", CONF->runPath, fileName); + remove(rFile); + sprintf(rFile, "%scli.sock", CONF->runPath); + remove(rFile); + if (rmdir(CONF->runPath) < 0) + LOG(LOG_WARNING, errno, "Cannot remove run dir %s.", CONF->runPath); + } if (!RESTART) // On SIGURG reloadConfig will clear old config. freeConfig(false); getMemStats(0, -1); // Log shutdown. + if (SHUTDOWN) + timer_clearTimer((uint64_t)-1); clock_gettime(CLOCK_REALTIME, &endtime); strcpy(tE, asctime(localtime(&endtime.tv_sec))); tE[strlen(tE) - 1] = '\0'; LOG(LOG_WARNING, 0, "%s on %s. Running since %s (%ds).", RESTART ? "Restarting" : "Shutting down", tE, tS, timeDiff(starttime, endtime).tv_sec); if (SHUTDOWN) { - timer_clearTimer((uint64_t)-1); free(CONF->runPath); // Alloced by main() free(CONF->chroot); // Alloced by loadConfig() free(CONF->logFilePath); // Alloced by loadConfig() @@ -558,24 +547,19 @@ static void signalHandler(int sig, siginfo_t* siginfo, void* context) { switch (sig) { case SIGINT: -#ifdef __linux__ - if (mrt_tbl < 0 || !chld.nr) -#endif - if (!CONF->notAsDaemon) - return; // Daemon / monitor ignores SIGINT + if ((mrt_tbl < 0 || !chld.nr) && !CONF->notAsDaemon) + return; // Daemon / Monitor ignores SIGINT sighandled |= GOT_SIGINT; // Fallthrough case SIGTERM: + sighandled |= GOT_SIGTERM; if (SHUTDOWN) { -#ifdef __linux__ // If SIGTERM received more than once, KILL childs and exit. - IF_FOR_IF(mrt_tbl < 0 && chld.c, i = 0; i < chld.nr; i++, chld.c[i].pid > 0) { + IF_FOR_IF(mrt_tbl < 0 && chld.nr, i = 0; i < chld.nr; i++, chld.c[i].pid > 0) { kill(chld.c[i].pid, SIGKILL); } -#endif exit(sig); } BLOCKSIGS; - sighandled |= GOT_SIGTERM; if (sig == SIGINT) return; break; @@ -596,8 +580,7 @@ static void signalHandler(int sig, siginfo_t* siginfo, void* context) { break; case SIGCHLD: sighandled |= GOT_SIGCHLD; -#ifdef __linux__ - IF_FOR_IF(mrt_tbl < 0 && chld.c, i = 0; i < chld.nr; i++, chld.c[i].pid == siginfo->si_pid) { + IF_FOR_IF(mrt_tbl < 0 && chld.nr, i = 0; i < chld.nr; i++, chld.c[i].pid == siginfo->si_pid) { chld.c[i].sig = 1; chld.c[i].st = (int8_t)siginfo->si_status; break; @@ -606,9 +589,6 @@ static void signalHandler(int sig, siginfo_t* siginfo, void* context) { } // Send SIG to children, except for SIGINT SIGPIPE and SIGCHLD. // If monitor is terminating we will end childs with SIGINT. - IF_FOR_IF(mrt_tbl < 0 && chld.c, i = 0; i < chld.nr; i++, chld.c[i].pid > 0) + IF_FOR_IF(mrt_tbl < 0 && chld.nr, i = 0; i < chld.nr; i++, chld.c[i].pid > 0) kill(chld.c[i].pid, sig == SIGTERM ? SIGINT : sig); -#else - } -#endif } diff --git a/src/igmpv3proxy.h b/src/igmpv3proxy.h index 8f611d0..0ee95c0 100644 --- a/src/igmpv3proxy.h +++ b/src/igmpv3proxy.h @@ -76,14 +76,6 @@ // Global definitions and declarations. //################################################################################# -// Memory statistics. -struct memstats { - int64_t mct, src, mfc, ifm; // Multicast Forwarding Table - int64_t ifd, fil, vif; // Interfaces - int64_t rcv, snd; // Buffers - int64_t qry, tmr, var; // Queries, Timers, various. -}; - // Keeps common configuration settings. #define RUN_PATHS "/run /var/run /tmp /var/tmp" #define CFG_PATHS "/etc/ /usr/local/etc/ /var/etc/ /usr/local/var/etc/" @@ -142,6 +134,25 @@ struct Config { bool cksumVerify; }; +// Memory statistics. +struct memstats { + int64_t mct, src, mfc, ifm; // Multicast Forwarding Table + int64_t ifd, fil, vif; // Interfaces + int64_t rcv, snd; // Buffers + int64_t qry, tmr, var; // Queries, Timers, various. +}; + +struct pt { + pid_t pid; + int tbl; + volatile uint8_t sig; + volatile int8_t st; +}; +struct chld { + int nr; + struct pt *c; +}; + // Timers for proxy control. struct timers { uint64_t rescanConf; @@ -428,21 +439,11 @@ extern char *fileName, Usage[], tS[32]; extern struct timespec starttime, curtime, utcoff; // Process Signaling. -extern uint8_t sigstatus, logwarning; +extern uint8_t sigstatus, logwarning; -#ifdef __linux__ // MRT route table id. Linux only, not supported on FreeBSD. -extern struct chld { - struct pt { - pid_t pid; - int tbl; - volatile uint8_t sig; - volatile int8_t st; - } *c; - int nr; -} chld; +extern struct chld chld; extern int mrt_tbl; -#endif // Upstream vif mask. extern uint32_t uVifs; @@ -542,7 +543,7 @@ void k_set_rcvbuf(int bufsize); void k_set_ttl(uint8_t ttl); void k_set_loop(bool l); void k_set_if(struct IfDesc *IfDp); -bool k_updateGroup(struct IfDesc *IfDp, bool join, uint32_t group, int mode, uint32_t src); +bool k_updateGroup(struct IfDesc *IfDp, bool join, uint32_t group, int mode, uint32_t source); int k_setSourceFilter(struct IfDesc *IfDp, uint32_t group, uint32_t fmode, uint32_t nsrcs, uint32_t *slist); int k_getMrouterFD(void); int k_enableMRouter(void); diff --git a/src/kern.c b/src/kern.c index 1838b09..c1629d9 100644 --- a/src/kern.c +++ b/src/kern.c @@ -71,19 +71,19 @@ void k_set_rcvbuf(int bufsize) { LOG(LOG_DEBUG, 0, "Got %d byte buffer size in %d iterations", bufsize, i); } -inline void k_set_ttl(uint8_t ttl) { +void k_set_ttl(uint8_t ttl) { #ifndef RAW_OUTPUT_IS_RAW if (setsockopt(mrouterFD, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0) LOG(LOG_WARNING, errno, "setsockopt IP_MULTICAST_TTL %u", ttl); #endif } -inline void k_set_loop(bool loop) { +void k_set_loop(bool loop) { if (setsockopt(mrouterFD, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop, sizeof(loop)) < 0) LOG(LOG_WARNING, errno, "setsockopt IP_MULTICAST_LOOP %u", loop); } -inline void k_set_if(struct IfDesc *IfDp) { +void k_set_if(struct IfDesc *IfDp) { struct in_addr adr = { IfDp ? IfDp->InAdr.s_addr : INADDR_ANY }; if (setsockopt(mrouterFD, IPPROTO_IP, IP_MULTICAST_IF, (char *)&adr, sizeof(adr)) < 0) LOG(LOG_WARNING, errno, "setsockopt IP_MULTICAST_IF %s", inetFmt(adr.s_addr, 1)); @@ -94,7 +94,7 @@ inline void k_set_if(struct IfDesc *IfDp) { * The join is bound to the UDP socket 'udpSock', so if this socket is * closed the membership is dropped. */ -inline bool k_updateGroup(struct IfDesc *IfDp, bool join, uint32_t group, int mode, uint32_t source) { +bool k_updateGroup(struct IfDesc *IfDp, bool join, uint32_t group, int mode, uint32_t source) { struct group_req grpReq = { 0 }; struct group_source_req grpSReq = { 0 }; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN @@ -138,7 +138,7 @@ inline bool k_updateGroup(struct IfDesc *IfDp, bool join, uint32_t group, int mo inline int k_setSourceFilter(struct IfDesc *IfDp, uint32_t group, uint32_t fmode, uint32_t nsrcs, uint32_t *slist) { uint32_t i, err = 0, size = (nsrcs + 1) * sizeof(struct sockaddr_storage); struct sockaddr_storage *ss; - if (! (ss = malloc(size))) // Freed by self. + if (! _malloc(ss, var, size)) // Freed by self. LOG(LOG_ERR, eNOMEM, "k_setSourceFilter: Out of Memory."); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN int er = EADDRNOTAVAIL; // Freebsd errno when group is not joined. @@ -157,7 +157,7 @@ inline int k_setSourceFilter(struct IfDesc *IfDp, uint32_t group, uint32_t fmode fmode, nsrcs, ss) < 0 && ((err = errno) != er || nsrcs == 0)) LOG(LOG_WARNING, err, "Failed to update source filter list for %s on %s.", inetFmt(group, 1), IfDp->Name); - free(ss); // Alloced by self. + _free(ss, var, size); // Alloced by self. return err ? EADDRNOTAVAIL : 0; } @@ -174,14 +174,12 @@ inline int k_getMrouterFD(void) { int k_enableMRouter(void) { int Va = 1; -#ifdef __linux__ if (mrt_tbl < 0 && (mrouterFD = socket(AF_INET, SOCK_DGRAM, 0)) < 0) LOG(LOG_ERR, eNOINIT, "Failed to open UDP socket."); else if (mrt_tbl < 0) { LOG(LOG_INFO, 0, "k_enableMRouter: Opened UDP socket."); return mrouterFD; } -#endif if ((mrouterFD = socket(AF_INET, SOCK_RAW, IPPROTO_IGMP)) < 0) LOG(LOG_ERR, eNOINIT, "IGMP socket open Failed"); else if (setsockopt(mrouterFD, IPPROTO_IP, IP_HDRINCL, (void *)&Va, sizeof(Va)) < 0) @@ -212,11 +210,8 @@ int k_enableMRouter(void) { * Disable the mrouted API and relases by this the lock. */ int k_disableMRouter(void) { -#ifdef __linux__ - if (mrt_tbl >= 0 && !STARTUP) -#endif - if (setsockopt(mrouterFD, IPPROTO_IP, MRT_DONE, NULL, 0) != 0) - LOG(LOG_WARNING, errno, "k_disableMRouter: MRT_DONE"); + if (!STARTUP && mrt_tbl >= 0 && setsockopt(mrouterFD, IPPROTO_IP, MRT_DONE, NULL, 0) != 0) + LOG(LOG_WARNING, errno, "k_disableMRouter: MRT_DONE"); if (close(mrouterFD) < 0) LOG(LOG_WARNING, errno, "k_disableMRouter: CLOSE"); else { diff --git a/src/lib.c b/src/lib.c index e92584b..7e554db 100644 --- a/src/lib.c +++ b/src/lib.c @@ -287,12 +287,10 @@ void myLog(int Severity, int Errno, const char *FmtSt, ...) { va_end(ArgPt); if ((CONF->logFilePath || CONF->log2Stderr) && lfp) -#ifdef __linux__ if (mrt_tbl >= 0 && chld.nr) fprintf(lfp, "%02ld:%02ld:%02ld:%04ld [%d] %s\n", sec % 86400 / 3600, sec % 3600 / 60, sec % 3600 % 60, nsec / 100000, mrt_tbl, LogMsg); else -#endif fprintf(lfp, "%02ld:%02ld:%02ld:%04ld %s\n", sec % 86400 / 3600, sec % 3600 / 60, sec % 3600 % 60, nsec / 100000, LogMsg); else @@ -301,31 +299,27 @@ void myLog(int Severity, int Errno, const char *FmtSt, ...) { if (lfp && lfp != stderr) fclose(lfp); if (Severity <= LOG_ERR && !SHUTDOWN) { + BLOCKSIGS; sigstatus = GOT_SIGTERM; -#ifdef __linux__ - IF_FOR_IF(mrt_tbl < 0 && chld.c, Ln = 0; Ln < chld.nr; Ln++, chld.c[Ln].pid > 0) { + IF_FOR_IF(mrt_tbl < 0 && chld.nr, Ln = 0; Ln < chld.nr; Ln++, chld.c[Ln].pid > 0) { LOG(LOG_INFO, 0, "SIGINT: To PID: %d for table: %d.", chld.c[Ln].pid, chld.c[Ln].tbl); kill(chld.c[Ln].pid, SIGINT); - chld.c[Ln].pid = chld.c[Ln].tbl = -1; } -#endif if (Errno < 0) Errno = 0 - Errno; igmpProxyCleanUp(Errno); } } -#ifdef __linux__ /** * Sets or removes ip mrules for table. */ -void ipRules(int tbl, bool activate) -{ +void ipRules(int tbl, bool activate) { struct IfDesc *IfDp; char msg[12]; sprintf(msg, "%d", tbl); LOG(LOG_INFO, 0, "ipRules: %s mrules for table %s.", activate ? "Adding" : "Removing", msg); - GETIFLIF(IfDp, IfDp->conf->tbl == tbl && !IS_DISABLED(IfDp->state) && !IfDp->conf->disableIpMrules) { + GETIFLIF(IfDp, IfDp->conf->tbl == tbl && !IfDp->conf->disableIpMrules) { pid_t pid; LOG(LOG_NOTICE, 0, "%s ip mrules for interface %s.", activate ? "Adding" : "Removing", IfDp->Name); for (int i = 0; i < 2; i++) { @@ -333,13 +327,12 @@ void ipRules(int tbl, bool activate) LOG(LOG_ERR, eNOFORK, "ipRules: Cannot fork."); } else if (pid == 0) { execlp("ip", "ip", "mrule", activate ? "add" : "del", i ? "iif" : "oif", IfDp->Name, "table", msg, NULL); - LOG(LOG_ERR, eNOFORK, "ipRules: Cannot exec."); + LOG(LOG_WARNING, eNOFORK, "ipRules: Cannot exec."); exit(-1); } } } } -#endif /** * Show memory statistics for debugging purposes. diff --git a/src/mctable.c b/src/mctable.c index 544f941..f9e0a28 100644 --- a/src/mctable.c +++ b/src/mctable.c @@ -592,7 +592,7 @@ static void updateSourceFilter(struct mcTable *mct, int mode) { uint32_t nsrcs = 0, *slist = NULL, i; struct src *src; // Build source list for upstream interface. - if (! (slist = malloc((mct->nsrcs & ~0x80000000) * sizeof(uint32_t)))) // Freed by self + if (! _malloc(slist, var, ((mct->nsrcs & ~0x80000000) + 1) * sizeof(uint32_t))) // Freed by self LOG(LOG_ERR, eNOMEM, "updateSourceFilter: Out of Memory."); for (nsrcs = 0, src = mct->sources; src; src = src->next) { BIT_CLR(src->vifB.us, IfDp->index); @@ -641,7 +641,7 @@ static void updateSourceFilter(struct mcTable *mct, int mode) { if (mct->mode && k_updateGroup(IfDp, true, mct->group, 1, (uint32_t)-1) && nsrcs > 0) k_setSourceFilter(IfDp, mct->group, mct->mode ? MCAST_EXCLUDE : MCAST_INCLUDE, nsrcs, slist); - free(slist); // Alloced by self + _free(slist, var, ((mct->nsrcs & ~0x80000000) + 1) * sizeof(uint32_t)); // Alloced by self } } diff --git a/src/querier.c b/src/querier.c index f3c7723..7fcfa05 100644 --- a/src/querier.c +++ b/src/querier.c @@ -47,6 +47,8 @@ static uint32_t qC = 0; // Querier count. * Function to control the IGMP querier process on interfaces. */ void ctrlQuerier(int start, struct IfDesc *IfDp) { + if (IfDp->conf->tbl != mrt_tbl) + return; if (start == 0 || start == 2) { // Remove all queries, timers and reset all IGMP status for interface. LOG(LOG_INFO, 0, "ctrlQuerier: Stopping querier process on %s", IfDp->Name); diff --git a/src/timers.c b/src/timers.c index bfcf721..c8bf06e 100644 --- a/src/timers.c +++ b/src/timers.c @@ -50,7 +50,7 @@ static struct timeOutQueue { struct timeOutQueue *next; // Next event in queue char *name; // name of the timer } *queue = NULL; -#define TMSZ (sizeof(struct timeOutQueue) + n + 1) +#define TMSZ(n) (sizeof(struct timeOutQueue) + strlen(n) + 1) static uint64_t id = 1; /** @@ -59,19 +59,17 @@ static uint64_t id = 1; */ struct timespec timer_ageQueue(void) { struct timeOutQueue *node = queue; - uint64_t i = 1; + uint64_t i = 1, tid; clock_gettime(CLOCK_REALTIME, &curtime); - for (size_t n = 0; !sighandled && !STARTUP && i <= CONF->tmQsz && node && timeDiff(curtime, node->time).tv_nsec == -1; i++) { + for (; !sighandled && !STARTUP && i <= CONF->tmQsz && node && timeDiff(curtime, node->time).tv_nsec == -1; node = queue, i++) { LOG(LOG_INFO, 0, "About to call timeout %d (#%d) - %s - Missed by %dus", node->id, i, node->name, - timeDiff(node->time, curtime).tv_nsec / 1000); - n = strlen(node->name); - node->func(node->data, node->id); - queue = node->next; - _free(node, tmr, TMSZ); // Alloced by timer_setTimer() - node = queue; + timeDiff(node->time, curtime).tv_nsec / 1000); + tid = node->id; + node->func(node->data, tid); + timer_clearTimer(tid); + clock_gettime(CLOCK_REALTIME, &curtime); } - if (i > 1) DEBUGQUEUE("Age Queue", 1, -1); @@ -84,12 +82,12 @@ struct timespec timer_ageQueue(void) { */ uint64_t timer_setTimer(int delay, const char *name, void (*func)(), void *data) { struct timeOutQueue *ptr = NULL, *node = NULL; - uint64_t i = 1, n = strlen(name); + uint64_t i = 1; // Create and set a new timer. - if (! _malloc(node, tmr, TMSZ)) // Freed by timer_ageQueue() or timer_clearTimer() + if (! _malloc(node, tmr, TMSZ(name))) // Freed by timer_ageQueue() or timer_clearTimer() LOG(LOG_ERR, eNOMEM, "timer_setTimer: Out of memory."); - *node = (struct timeOutQueue){ id++, func, data, timeDelay(delay), NULL, memcpy(&node->name + 1, name, n + 1) }; + *node = (struct timeOutQueue){ id++, func, data, timeDelay(delay), NULL, memcpy(&node->name + 1, name, strlen(name) + 1) }; if (!queue || timeDiff(queue->time, node->time).tv_nsec == -1) { // Start of queue, insert. node->next = queue; @@ -118,7 +116,6 @@ void *timer_clearTimer(uint64_t tid) { // Find the timer and remove it if found. for (pnode = NULL, i = 1, node = queue; node && node->id != tid; pnode = node, node = node->next, i++); if (node) { - size_t n = strlen(node->name); if (pnode) pnode->next = node->next; else @@ -126,7 +123,7 @@ void *timer_clearTimer(uint64_t tid) { DEBUGQUEUE("Clear Timer", 1, -1); pnode = (void *)node->data; LOG(LOG_DEBUG, 0, "Removed timeout %d (#%d): %s", node->id, i, node->name); - _free(node, tmr, TMSZ); // Alloced by timer_setTimer() + _free(node, tmr, TMSZ(node->name)); // Alloced by timer_setTimer() } // If timer was removed, return its data, the caller may need it.