From c615d4dd9c5d952cd81ec4ae2e7ad7cf54062e9b Mon Sep 17 00:00:00 2001 From: Sietse van Zanen Date: Tue, 26 May 2020 17:31:02 +0200 Subject: [PATCH] Changes to timing and igmpproxy This commit contains a number of changes to the timing structure and main event loops. Includes minor changes to config.c and request.c to include add name for timers. callout.c is modified to a simpler and more stable algorithm. igmpproxy.h and igmpproxy.c are sanitized and adopted to the new callout queue. FIXES: https://github.com/pali/igmpproxy/issues/58 Fixed a few typos and comments Updated Timing Algorithm Timers are now kept with a struct timespec, so they are much mnore acurately scheduled. Added a name to the timeoutqueue struct, improves debugging timers by a bunch. Renamed timer functions to be more in line with style time_ageQueue() now returns ns until next timer if scheduled in less then 1s. this makes timer execuation really accurate. Timers are not missed by more than a few 1/100s Updated syslog.c to add timestamp when logging to stderr. void debugQeueu(VOID) --- src/callout.c | 277 ++++++++++++++++-------------------------------- src/config.c | 23 ++-- src/igmpproxy.c | 182 ++++++++++++------------------- src/igmpproxy.h | 30 ++++-- src/request.c | 10 +- src/syslog.c | 20 ++-- 6 files changed, 208 insertions(+), 334 deletions(-) diff --git a/src/callout.c b/src/callout.c index c49da6cf..b81937dd 100644 --- a/src/callout.c +++ b/src/callout.c @@ -32,238 +32,149 @@ ** */ - #include "igmpproxy.h" /* the code below implements a callout queue */ -static int id = 0; -static struct timeOutQueue *queue = 0; /* pointer to the beginning of timeout queue */ +static unsigned long id = 1; +static struct timeOutQueue *queue = NULL; 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 + unsigned long id; + char name[32]; // name of the timer + timer_f func; // function to call + void *data; // Argument for function. + struct timespec 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) { +void timer_freeQueue(void) { struct timeOutQueue *p; - while (queue) { - p = queue; - queue = queue->next; - free(p); + for (p = queue; queue; queue = p) { + p = p->next; + free(queue); // Alloced by timer_setTimer() } + my_log(LOG_DEBUG, 0, "timer_freeQueue: All Timeouts removed, Queue is empty."); } - /** - * elapsed_time seconds have passed; perform all the events that should - * happen. - */ -void age_callout_queue(int elapsed_time) { +* Execute all expired timers, return ns until next timer if scheduled in less than 1s. +*/ +unsigned int timer_ageQueue() { 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; + unsigned long i = 1; + + for (ptr = queue; ptr && ((curtime.tv_sec > ptr->time.tv_sec) || (curtime.tv_sec == ptr->time.tv_sec && curtime.tv_nsec > ptr->time.tv_nsec)); ptr = queue) { + my_log(LOG_DEBUG, 0, "About to call timeout %d (#%d) - %s - Missed by %dus", ptr->id, i++, ptr->name, (ptr->time.tv_nsec > curtime.tv_nsec ? 1000000000 - ptr->time.tv_nsec + curtime.tv_nsec: curtime.tv_nsec - ptr->time.tv_nsec) / 1000); + ptr->func(ptr->data); + queue = ptr->next; + free(ptr); // Alloced by timer_setTimer() + debugQueue(); } - /* process existing events */ - for (ptr = _queue; ptr; ptr = _queue, i++) { - _queue = _queue->next; - my_log(LOG_DEBUG, 0, "About to call timeout %d (#%d)", ptr->id, i); - if (ptr->func) - ptr->func(ptr->data); - free(ptr); - } + diftime.tv_sec = curtime.tv_nsec > queue->time.tv_nsec ? queue->time.tv_sec - curtime.tv_sec - 1 : queue->time.tv_sec - curtime.tv_sec; + diftime.tv_nsec = curtime.tv_nsec > queue->time.tv_nsec ? 1000000000 - curtime.tv_nsec + queue->time.tv_nsec: queue->time.tv_nsec - curtime.tv_nsec; + return diftime.tv_sec == 0 ? diftime.tv_nsec : 0; } /** - * 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; - } - return queue->time; - } - return -1; -} - -/** - * Inserts a timer in queue. - * @param delay - Number of seconds the timeout should happen in. - * @param action - The function to call on timeout. - * @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; +* Inserts a timer in queue. +* @param delay - Number of seconds the timeout should happen in. +* @param name - Name for the timer. +* @param action - The function to call on timeout. +* @param data - Pointer to the function data to supply. +*/ +unsigned int timer_setTimer(int delay, const char *name, timer_f action, void *data) { + struct timeOutQueue *ptr = queue, *node; + unsigned long i = 1; - /* create a node */ - node = (struct timeOutQueue *)malloc(sizeof(struct timeOutQueue)); - if (node == 0) { - my_log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n"); - return -1; + node = (struct timeOutQueue *)malloc(sizeof(struct timeOutQueue)); // Freed by timer_freeQueue(), timer_ageQueue() or timer_clearTimer() + if (! node) { + my_log(LOG_ERR, 0, "timer_setTimer: Out of memory."); } + clock_gettime(CLOCK_MONOTONIC, &curtime); + strcpy(node->name, name); node->func = action; node->data = data; - node->time = delay; - node->next = 0; - node->id = ++id; - - prev = ptr = queue; + node->time.tv_sec = curtime.tv_sec + delay; + node->time.tv_nsec = curtime.tv_nsec; + node->id = id++; + node->next = NULL; - /* 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.tv_sec > ptr->next->time.tv_sec || + (node->time.tv_sec == ptr->next->time.tv_sec && node->time.tv_nsec >= ptr->next->time.tv_nsec)); ptr = ptr->next, i++); + if (ptr == queue && (node->time.tv_sec < ptr->time.tv_sec || (node->time.tv_sec == ptr->time.tv_sec && node->time.tv_nsec < ptr->time.tv_nsec))) { + // Start of queue, insert. + i--; + 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(); + debugQueue(); + my_log(LOG_DEBUG, 0, "Created timeout %d (#%d): %s - delay %d secs", node->id, i, node->name, delay); return node->id; } /** -* returns the time until the timer is scheduled +* Removes a timer from the queue. */ -int timer_leftTimer(int timer_id) { - struct timeOutQueue *ptr; - int left = 0; - - if (!timer_id) - return -1; +void *timer_clearTimer(unsigned long timer_id) { + struct timeOutQueue *ptr = NULL, *fptr = NULL; + void *data = NULL; + unsigned long i = 1; - for (ptr = queue; ptr; ptr = ptr->next) { - left += ptr->time; - if (ptr->id == timer_id) { - return left; - } + if (queue->id == timer_id) { + fptr = queue; + queue = queue->next; + } else { + for (i++, ptr = queue; ptr->next && ptr->next->id != timer_id; ptr = ptr->next, i++); + fptr = ptr->next; + ptr->next = ptr->next ? ptr->next->next : NULL; + } + if (fptr) { + clock_gettime(CLOCK_MONOTONIC, &curtime); + debugQueue(); + my_log(LOG_DEBUG, 0, "Removed timeout %d (#%d): %s", i, fptr->id, fptr->name); + data = fptr->data; + free(fptr); // Alloced by timer_setTimer() } - return -1; + + // Return pointer to the cleared timer's data, the caller may need it. + return data; } /** -* clears the associated timer. Returns 1 if succeeded. +* Returns the time until the timer is scheduled (-1 if timer not found). */ -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; +struct timespec timer_getTime(unsigned long timer_id) { + struct timeOutQueue *ptr; + for (ptr = queue; ptr && ptr->id != timer_id; ptr = ptr->next); + return ptr ? ptr->time : (struct timespec){ -1, -1 }; } /** - * debugging utility - */ -static void debugQueue(void) { +* Debugging utility +*/ +static void debugQueue() { struct timeOutQueue *ptr; + unsigned long 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 [%4ds] - Id:%6d - %s", i, ptr->time.tv_sec - curtime.tv_sec, ptr->id, ptr->name); } } diff --git a/src/config.c b/src/config.c index 030da1ac..223b27d5 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; @@ -226,31 +228,26 @@ void configureVifs(void) { } // Loop through all VIFs... - for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) { - if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) { - + for (Ix = 0; (Dp = getIfByIx(Ix)); Ix++) { + if (Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK)) { // Now try to find a matching config... - for( confPtr = vifconf; confPtr; confPtr = confPtr->next) { - + for (confPtr = vifconf; confPtr; confPtr = confPtr->next) { // I the VIF names match... - if(strcmp(Dp->Name, confPtr->name)==0) { + if (strcmp(Dp->Name, confPtr->name) == 0) { struct SubnetList *vifLast; my_log(LOG_DEBUG, 0, "Found config for %s", Dp->Name); - // Set the VIF state Dp->state = confPtr->state; - Dp->threshold = confPtr->threshold; Dp->ratelimit = confPtr->ratelimit; - // Go to last allowed net on VIF... - for(vifLast = Dp->allowednets; vifLast->next; vifLast = vifLast->next); - - // Insert the configured nets... + // Go to last allowed net on VIF and insert configured nets. + for (vifLast = Dp->allowednets; vifLast->next; vifLast = vifLast->next); vifLast->next = confPtr->allowednets; + // Link the black- and whitelists. Dp->allowedgroups = confPtr->allowedgroups; break; @@ -290,7 +287,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/igmpproxy.c b/src/igmpproxy.c index c72a567f..00db2fe4 100644 --- a/src/igmpproxy.c +++ b/src/igmpproxy.c @@ -61,23 +61,20 @@ int igmpProxyInit(void); void igmpProxyCleanUp(void); void igmpProxyRun(void); -// Global vars... -static int sighandled = 0; -#define GOT_SIGINT 0x01 -#define GOT_SIGHUP 0x02 -#define GOT_SIGUSR1 0x04 -#define GOT_SIGUSR2 0x08 - // Holds the indeces of the upstream IF... int upStreamIfIdx[MAX_UPS_VIFS]; +// Global Variables / Config / Signal Handling / Timekeeping / Socket. +unsigned int sighandled = 0; +char *configFilePath; +struct timespec curtime, lasttime, diftime, *timeout = &diftime, utcoff; + /** * Program main method. Is invoked when the program is started * on commandline. The number of commandline arguments, and a * pointer to the arguments are received on the line... */ -int main( int ArgCn, char *ArgVc[] ) { - +int main(int ArgCn, char *ArgVc[]) { int c; bool NotAsDaemon = false; @@ -92,6 +89,8 @@ int main( int ArgCn, char *ArgVc[] ) { case 'd': Log2Stderr = true; NotAsDaemon = true; + time_t rawtime = time(NULL); + utcoff.tv_sec = timegm(localtime(&rawtime)) - rawtime; break; case 'v': if (LogLevel == LOG_INFO) @@ -113,7 +112,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) { @@ -126,41 +125,37 @@ int main( int ArgCn, char *ArgVc[] ) { // Write debug notice with file path... my_log(LOG_DEBUG, 0, "Searching for config file at '%s'" , configFilePath); - do { + // Loads the config file... + if (! loadConfig(configFilePath)) { + my_log(LOG_ERR, 0, "Unable to load config file..."); + exit(1); + } - // Loads the config file... - if( ! loadConfig( configFilePath ) ) { - my_log(LOG_ERR, 0, "Unable to load config file..."); - break; - } + // Initializes the deamon. + if (!igmpProxyInit()) { + my_log(LOG_ERR, 0, "Unable to initialize IGMPproxy."); + exit(1); + } - // Initializes the deamon. - if ( !igmpProxyInit() ) { - my_log(LOG_ERR, 0, "Unable to initialize IGMPproxy."); - break; + if (! NotAsDaemon) { + // Only daemon goes past this line... + if (fork()) { + exit(0); } - if ( !NotAsDaemon ) { - - // Only daemon goes past this line... - if (fork()) exit(0); - - // Detach daemon from terminal - if ( close( 0 ) < 0 || close( 1 ) < 0 || close( 2 ) < 0 - || open( "/dev/null", 0 ) != 0 || dup2( 0, 1 ) < 0 || dup2( 0, 2 ) < 0 - || setpgid( 0, 0 ) < 0 - ) { - my_log( LOG_ERR, errno, "failed to detach daemon" ); - } + // Detach daemon from terminal + if (close(0) < 0 || close(1) < 0 || close(2) < 0 + || open("/dev/null", 0) != 0 || dup2(0, 1) < 0 || dup2(0, 2) < 0 + || setpgid(0, 0) < 0) { + my_log( LOG_ERR, errno, "failed to detach daemon" ); } + } - // Go to the main loop. - igmpProxyRun(); - - // Clean up - igmpProxyCleanUp(); + // Go to the main loop. + igmpProxyRun(); - } while ( false ); + // Clean up + igmpProxyCleanUp(); // Inform that we are exiting. my_log(LOG_INFO, 0, "Shutdown complete...."); @@ -187,10 +182,10 @@ int igmpProxyInit(void) { // Configures IF states and settings configureVifs(); - switch ( Err = enableMRouter() ) { + switch (Err = enableMRouter()) { case 0: break; - case EADDRINUSE: my_log( LOG_ERR, EADDRINUSE, "MC-Router API already in use" ); break; - default: my_log( LOG_ERR, Err, "MRT_INIT failed" ); + case EADDRINUSE: my_log(LOG_ERR, EADDRINUSE, "MC-Router API already in use"); break; + default: my_log(LOG_ERR, Err, "MRT_INIT failed"); } /* create VIFs for all IP, non-loop interfaces @@ -237,8 +232,6 @@ int igmpProxyInit(void) { initIgmp(); // Initialize Routing table initRouteTable(); - // Initialize timer - callout_init(); return 1; } @@ -249,7 +242,7 @@ int igmpProxyInit(void) { void igmpProxyCleanUp(void) { my_log( LOG_DEBUG, 0, "clean handler called" ); - free_all_callouts(); // No more timeouts. + timer_freeQueue(); // No more timeouts. clearAllRoutes(); // Remove all routes. disableMRouter(); // Disable the multirout API } @@ -258,28 +251,20 @@ void igmpProxyCleanUp(void) { * Main daemon loop. */ void igmpProxyRun(void) { - // Get the config. - struct Config *config = getCommonConfig(); - // Set some needed values. - register int recvlen; - int MaxFD, Rt, secs; + register int fastage = 0, recvlen, 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; + + // First thing we send a membership query in downstream VIF's... + sendGeneralMembershipQuery(); // Initialize timer vars - difftime.tv_nsec = 0; + diftime.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) { if (sighandled & GOT_SIGINT) { @@ -289,79 +274,42 @@ void igmpProxyRun(void) { } } - /* aimwang: call rebuildIfVc */ - if (config->rescanVif) - rebuildIfVc(); - - // Prepare timeout... - secs = timer_nextTimer(); - if(secs == -1) { - timeout = NULL; - } else { - timeout->tv_nsec = 0; - timeout->tv_sec = (secs > 3) ? 3 : secs; // aimwang: set max timeout + // Timeout = 1s - difference between current and last time timer_ageQueue() with .01s grace. + // This will make sure queue aging is run once every s (timer resolution) +- 0.01s. + // If timer_ageQueue returns the nr of ns until next timer use that as the base for timeout. + // Using this algorithm a timer will never overshoot more than t_age_queue + t_handle_sig. + clock_gettime(CLOCK_MONOTONIC, &curtime); + diftime.tv_sec = curtime.tv_nsec >= lasttime.tv_nsec ? curtime.tv_sec - lasttime.tv_sec : curtime.tv_sec - lasttime.tv_sec - 1; + diftime.tv_nsec = curtime.tv_nsec >= lasttime.tv_nsec ? curtime.tv_nsec - lasttime.tv_nsec : 1000000000 - lasttime.tv_nsec + curtime.tv_nsec; + if (diftime.tv_sec > 0 || (! fastage && diftime.tv_nsec > 990000000) || (fastage && diftime.tv_nsec > fastage)) { + lasttime = curtime; + fastage = timer_ageQueue(); + diftime.tv_sec = diftime.tv_nsec = 0; } - - // Prepare for select. - MaxFD = MRouterFD; - - FD_ZERO( &ReadFDS ); - FD_SET( MRouterFD, &ReadFDS ); + timeout->tv_nsec = (fastage ? fastage : 999999999) - diftime.tv_nsec; // wait for input - Rt = pselect( MaxFD +1, &ReadFDS, NULL, NULL, timeout, NULL ); + FD_ZERO(&ReadFDS); + FD_SET(MRouterFD, &ReadFDS); + Rt = pselect(MRouterFD + 1, &ReadFDS, NULL, NULL, timeout, NULL); // log and ignore failures - if( Rt < 0 ) { + if (Rt < 0) { my_log( LOG_WARNING, errno, "select() failure" ); continue; - } - else if( Rt > 0 ) { - + } 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 (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"); + 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_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 4122a857..cdd2c219 100644 --- a/src/igmpproxy.h +++ b/src/igmpproxy.h @@ -80,7 +80,6 @@ #define BIT_CLR(X,n) ((X) &= ~(1 << (n))) #define BIT_TST(X,n) ((X) & 1 << (n)) - //################################################################################# // Globals //################################################################################# @@ -97,7 +96,21 @@ extern char s2[]; extern char s3[]; extern char s4[]; +/** +* Signal Handling. +*/ +extern unsigned int sighandled; +extern unsigned int sigstatus; // 0 = no signal, 1 = SIGHUP, 2 = SIGUSR1, 3 = SIGUSR2, 4 = Timed Reload, 5 = Timed Rebuild +#define GOT_SIGINT 0x01 +#define GOT_SIGHUP 0x02 +#define GOT_SIGUSR1 0x04 +#define GOT_SIGUSR2 0x08 +#define GOT_SIGURG 0x10 +/** +* Timekeeping +*/ +extern struct timespec curtime, lasttime, diftime, utcoff; //################################################################################# // Lib function prototypes. @@ -275,17 +288,16 @@ void acceptGroupReport(uint32_t src, uint32_t group); void acceptLeaveMessage(uint32_t src, uint32_t group); void sendGeneralMembershipQuery(void); -/* callout.c +/** +* callout.c */ typedef void (*timer_f)(void *); -void callout_init(void); -void free_all_callouts(void); -void age_callout_queue(int); -int timer_nextTimer(void); -int timer_setTimer(int, timer_f, void *); -int timer_clearTimer(int); -int timer_leftTimer(int); +void timer_freeQueue(void); +unsigned int timer_ageQueue(); +unsigned int timer_setTimer(int delay, const char name[32], timer_f action, void *); +struct timespec timer_getTime(unsigned long timer_id); +void *timer_clearTimer(unsigned long timer_id); /* confread.c */ diff --git a/src/request.c b/src/request.c index 06d14c44..196fe74c 100644 --- a/src/request.c +++ b/src/request.c @@ -202,7 +202,9 @@ void sendGroupSpecificMemberQuery(void *argument) { } // Set timeout for next round... - timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc); + char msg[40] = "Query: "; + strcat(msg, inetFmt(gvDesc->group, s1)); + timer_setTimer(conf->lastMemberQueryInterval, msg, sendGroupSpecificMemberQuery, gvDesc); } @@ -233,17 +235,17 @@ void sendGeneralMembershipQuery(void) { } // Install timer for aging active routes. - timer_setTimer(conf->queryResponseInterval, (timer_f)ageActiveRoutes, NULL); + timer_setTimer(conf->queryResponseInterval, "Age Active Routes", (timer_f)ageActiveRoutes, NULL); // Install timer for next general query... if(conf->startupQueryCount>0) { // Use quick timer... - timer_setTimer(conf->startupQueryInterval, (timer_f)sendGeneralMembershipQuery, NULL); + timer_setTimer(conf->startupQueryInterval, "General Query", (timer_f)sendGeneralMembershipQuery, NULL); // Decrease startup counter... conf->startupQueryCount--; } else { // Use slow timer... - timer_setTimer(conf->queryInterval, (timer_f)sendGeneralMembershipQuery, NULL); + timer_setTimer(conf->queryInterval, "General Query", (timer_f)sendGeneralMembershipQuery, NULL); } } diff --git a/src/syslog.c b/src/syslog.c index 0c718f09..63fce46c 100644 --- a/src/syslog.c +++ b/src/syslog.c @@ -37,23 +37,25 @@ int LogLevel = LOG_WARNING; bool Log2Stderr = false; -void my_log( int Severity, int Errno, const char *FmtSt, ... ) -{ +void my_log( int Severity, int Errno, const char *FmtSt, ... ) { + struct timespec logtime; char LogMsg[ 128 ]; - va_list ArgPt; unsigned Ln; + va_start( ArgPt, FmtSt ); Ln = vsnprintf( LogMsg, sizeof( LogMsg ), FmtSt, ArgPt ); - if( Errno > 0 ) - snprintf( LogMsg + Ln, sizeof( LogMsg ) - Ln, - "; Errno(%d): %s", Errno, strerror(Errno) ); + if( Errno > 0 ) { + snprintf( LogMsg + Ln, sizeof( LogMsg ) - Ln, "; Errno(%d): %s", Errno, strerror(Errno) ); + } va_end( ArgPt ); if (Severity <= LogLevel) { - if (Log2Stderr) - fprintf(stderr, "%s\n", LogMsg); - else { + if (Log2Stderr) { + clock_gettime(CLOCK_REALTIME, &logtime); + long sec = logtime.tv_sec + utcoff.tv_sec, nsec = logtime.tv_nsec; + fprintf(stderr, "%02ld:%02ld:%02ld:%04ld %s\n", sec % 86400 / 3600, sec % 3600 / 60, sec % 3600 % 60, nsec / 100000, LogMsg); + } else { syslog(Severity, "%s", LogMsg); } }