Skip to content

Commit

Permalink
Changes to callout and igmpproxy
Browse files Browse the repository at this point in the history
First PR for a complete rewrite of igmpproxy. This rewrite will
include several fixes, and new functionality.

This PR changes callout.c to a simpler and more stable callout queue
algorithm.
Also igmpproxy.c is sanitized and the main event loop based on the new
callout queue.
Several structs and variables are moved to igmpproxy.h, a few prototypes
added and sanitized into the unified style.
config.c is modified slightly to add NULL pointers for new blacklists that
will be added.

Fixes: pali#58
  • Loading branch information
Uglymotha committed May 26, 2020
1 parent f71ba40 commit 20dcf0c
Show file tree
Hide file tree
Showing 5 changed files with 195 additions and 348 deletions.
214 changes: 48 additions & 166 deletions src/callout.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,91 +37,47 @@

/* the code below implements a callout queue */
static int id = 0;
static struct timeOutQueue *queue = 0; /* pointer to the beginning of timeout queue */
static struct timeOutQueue *queue = NULL; /* pointer to the beginning of timeout queue */

struct timeOutQueue {
struct timeOutQueue *next; // Next event in queue
int id;
timer_f func; // function to call
void *data; // Data for function
int time; // Time offset for next event
long time; // Time for event
struct timeOutQueue *next; // Next event in queue
};

// Method for dumping the Queue to the log.
static void debugQueue(void);

/**
* Initializes the callout queue
*/
void callout_init(void) {
queue = NULL;
}

/**
* Clears all scheduled timeouts...
*/
void free_all_callouts(void) {
struct timeOutQueue *p;

while (queue) {
p = queue;
queue = queue->next;
free(p);
for (p = queue ? queue->next : NULL; queue; queue = p, p = p ? p->next : NULL) {
free(queue); // Alloced by timer_setTimer()
}
my_log(LOG_DEBUG, 0, "free_all_callouts: All Timeouts removed, Queue is empty.");
}


/**
* elapsed_time seconds have passed; perform all the events that should
* happen.
* Execute all expired timers, using .5s grace.
*/
void age_callout_queue(int elapsed_time) {
struct timeOutQueue *ptr;
struct timeOutQueue *_queue = NULL;
struct timeOutQueue *last = NULL;
int i = 0;

for (ptr = queue; ptr; ptr = ptr->next) {
if (ptr->time > elapsed_time) {
ptr->time -= elapsed_time;
break;
} else {
elapsed_time -= ptr->time;
if (_queue == NULL)
_queue = ptr;
last = ptr;
}
}

queue = ptr;
if (last) {
last->next = NULL;
}

/* process existing events */
for (ptr = _queue; ptr; ptr = _queue, i++) {
_queue = _queue->next;
void age_callout_queue(struct timespec curtime) {
struct timeOutQueue *ptr = queue;
int i = 1;
if (curtime.tv_sec == 0) clock_gettime (CLOCK_MONOTONIC, &curtime);
while (ptr && ((ptr->time <= curtime.tv_sec) || (curtime.tv_nsec >= 500000000 && ptr->time <= curtime.tv_sec-1))) {
my_log(LOG_DEBUG, 0, "About to call timeout %d (#%d)", ptr->id, i);
if (ptr->func)
ptr->func(ptr->data);
free(ptr);
}
}

/**
* Return in how many seconds age_callout_queue() would like to be called.
* Return -1 if there are no events pending.
*/
int timer_nextTimer(void) {
if (queue) {
if (queue->time < 0) {
my_log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d",
queue->time);
return 0;
struct timeOutQueue *tmp = ptr;
if (ptr->func) {
ptr->func(ptr->data);
}
return queue->time;
queue = ptr = ptr->next;
free(tmp); // Alloced by timer_setTimer()
i++;
}
return -1;
}

/**
Expand All @@ -131,61 +87,41 @@ int timer_nextTimer(void) {
* @param data - Pointer to the function data to supply...
*/
int timer_setTimer(int delay, timer_f action, void *data) {
struct timeOutQueue *ptr, *node, *prev;
int i = 0;
struct timeOutQueue *ptr = queue, *node;
struct timespec curtime;
int i = 1;

/* create a node */
// create a node. Freed by free_all_callouts() and age_callout_queue().
node = (struct timeOutQueue *)malloc(sizeof(struct timeOutQueue));
if (node == 0) {
if (! node) {
my_log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
return -1;
}
clock_gettime(CLOCK_MONOTONIC, &curtime);
node->func = action;
node->data = data;
node->time = delay;
node->next = 0;
node->time = curtime.tv_sec + delay;
node->id = ++id;
node->next = NULL;

prev = ptr = queue;

/* insert node in the queue */

/* if the queue is empty, insert the node and return */
if (!queue) {
if (! queue) {
// if the queue is empty, insert the node and return.
queue = node;
}
else {
/* chase the pointer looking for the right place */
while (ptr) {
if (delay < ptr->time) {
// We found the correct node
node->next = ptr;
if (ptr == queue) {
queue = node;
}
else {
prev->next = node;
}
ptr->time -= node->time;
my_log(LOG_DEBUG, 0,
"Created timeout %d (#%d) - delay %d secs",
node->id, i, node->time);
debugQueue();
return node->id;
} else {
// Continur to check nodes.
delay -= ptr->time; node->time = delay;
prev = ptr;
ptr = ptr->next;
}
i++;
} else {
// chase the queue looking for the right place.
for (i++; ptr->next && node->time >= ptr->next->time; ptr = ptr->next, i++);
if (ptr == queue && node->time < ptr->time) {
// Start of queue, insert.
queue = node;
node->next = ptr;
} else {
node->next = ptr->next;
ptr->next = node;
}
prev->next = node;
}
my_log(LOG_DEBUG, 0, "Created timeout %d (#%d) - delay %d secs",
node->id, i, node->time);
debugQueue();

debugQueue();
my_log(LOG_DEBUG, 0, "Created timeout %d (#%d) - delay %d secs", node->id, i, delay);
return node->id;
}

Expand All @@ -194,76 +130,22 @@ int timer_setTimer(int delay, timer_f action, void *data) {
*/
int timer_leftTimer(int timer_id) {
struct timeOutQueue *ptr;
int left = 0;

if (!timer_id)
return -1;

for (ptr = queue; ptr; ptr = ptr->next) {
left += ptr->time;
if (ptr->id == timer_id) {
return left;
}
struct timespec curtime;
for (ptr = queue; ptr && ptr->id != timer_id; ptr = ptr->next);
if (ptr) {
clock_gettime(CLOCK_MONOTONIC, &curtime);
return (ptr->time - curtime.tv_sec);
}
return -1;
}

/**
* clears the associated timer. Returns 1 if succeeded.
*/
int timer_clearTimer(int timer_id) {
struct timeOutQueue *ptr, *prev;
int i = 0;

if (!timer_id)
return 0;

prev = ptr = queue;

/*
* find the right node, delete it. the subsequent node's time
* gets bumped up
*/

debugQueue();
while (ptr) {
if (ptr->id == timer_id) {
/* got the right node */

/* unlink it from the queue */
if (ptr == queue)
queue = queue->next;
else
prev->next = ptr->next;

/* increment next node if any */
if (ptr->next != 0)
(ptr->next)->time += ptr->time;

if (ptr->data)
free(ptr->data);
my_log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
free(ptr);
debugQueue();
return 1;
}
prev = ptr;
ptr = ptr->next;
i++;
}
// If we get here, the timer was not deleted.
my_log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
debugQueue();
return 0;
}

/**
* debugging utility
*/
static void debugQueue(void) {
struct timeOutQueue *ptr;

for (ptr = queue; ptr; ptr = ptr->next) {
my_log(LOG_DEBUG, 0, "(Id:%d, Time:%d) ", ptr->id, ptr->time);
int i;
for (i = 1, ptr = queue; ptr; ptr = ptr->next, i++) {
my_log(LOG_DEBUG, 0, "(%d - Id:%d, Time:%d) ", i, ptr->id, ptr->time);
}
}
17 changes: 9 additions & 8 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -228,30 +230,27 @@ void configureVifs(void) {
// Loop through all VIFs...
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) {

// I the VIF names match...
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->deniednets = confPtr->deniednets;
Dp->allowedgroups = confPtr->allowedgroups;
Dp->deniedgroups = confPtr->deniedgroups;

break;
}
Expand Down Expand Up @@ -290,7 +289,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 );
Expand Down
Loading

0 comments on commit 20dcf0c

Please sign in to comment.