266 lines
6.8 KiB
C
Executable File
266 lines
6.8 KiB
C
Executable File
/*
|
|
** igmpproxy - IGMP proxy based multicast router
|
|
** Copyright (C) 2005 Johnny Egeland <johnny@rlo.org>
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
**
|
|
**----------------------------------------------------------------------------
|
|
**
|
|
** This software is derived work from the following software. The original
|
|
** source code has been modified from it's original state by the author
|
|
** of igmpproxy.
|
|
**
|
|
** smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de>
|
|
** - Licensed under the GNU General Public License, version 2
|
|
**
|
|
** mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of
|
|
** Leland Stanford Junior University.
|
|
** - Original license can be found in the "doc/mrouted-LINCESE" file.
|
|
**
|
|
*/
|
|
|
|
|
|
#include "defs.h"
|
|
|
|
/* the code below implements a callout queue */
|
|
static int id = 0;
|
|
static struct timeOutQueue *queue = 0; /* pointer to the beginning of timeout queue */
|
|
|
|
struct timeOutQueue {
|
|
struct timeOutQueue *next; // Next event in queue
|
|
int id;
|
|
cfunc_t func; // function to call
|
|
void *data; // Data for function
|
|
int time; // Time offset for next event
|
|
};
|
|
|
|
// Method for dumping the Queue to the log.
|
|
static void debugQueue(void);
|
|
|
|
/**
|
|
* Initializes the callout queue
|
|
*/
|
|
void callout_init() {
|
|
queue = NULL;
|
|
}
|
|
|
|
/**
|
|
* Clears all scheduled timeouts...
|
|
*/
|
|
void free_all_callouts() {
|
|
struct timeOutQueue *p;
|
|
|
|
while (queue) {
|
|
p = queue;
|
|
queue = queue->next;
|
|
free(p);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* elapsed_time seconds have passed; perform all the events that should
|
|
* happen.
|
|
*/
|
|
void age_callout_queue(int elapsed_time) {
|
|
struct timeOutQueue *ptr;
|
|
int i = 0;
|
|
|
|
for (ptr = queue; ptr; ptr = queue, i++) {
|
|
if (ptr->time > elapsed_time) {
|
|
ptr->time -= elapsed_time;
|
|
return;
|
|
} else {
|
|
elapsed_time -= ptr->time;
|
|
queue = queue->next;
|
|
IF_DEBUG 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() {
|
|
if (queue) {
|
|
if (queue->time < 0) {
|
|
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, cfunc_t action, void *data) {
|
|
struct timeOutQueue *ptr, *node, *prev;
|
|
int i = 0;
|
|
|
|
/* create a node */
|
|
node = (struct timeOutQueue *)malloc(sizeof(struct timeOutQueue));
|
|
if (node == 0) {
|
|
log(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n");
|
|
return -1;
|
|
}
|
|
node->func = action;
|
|
node->data = data;
|
|
node->time = delay;
|
|
node->next = 0;
|
|
node->id = ++id;
|
|
|
|
prev = ptr = queue;
|
|
|
|
/* insert node in the queue */
|
|
|
|
/* if the queue is empty, insert the node and return */
|
|
if (!queue) {
|
|
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;
|
|
IF_DEBUG {
|
|
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++;
|
|
}
|
|
prev->next = node;
|
|
}
|
|
IF_DEBUG {
|
|
log(LOG_DEBUG, 0, "Created timeout %d (#%d) - delay %d secs",
|
|
node->id, i, node->time);
|
|
|
|
debugQueue();
|
|
}
|
|
|
|
return node->id;
|
|
}
|
|
|
|
/**
|
|
* returns the time until the timer is scheduled
|
|
*/
|
|
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;
|
|
}
|
|
}
|
|
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
|
|
*/
|
|
|
|
IF_DEBUG 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);
|
|
IF_DEBUG log(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i);
|
|
free(ptr);
|
|
IF_DEBUG debugQueue();
|
|
return 1;
|
|
}
|
|
prev = ptr;
|
|
ptr = ptr->next;
|
|
i++;
|
|
}
|
|
// If we get here, the timer was not deleted.
|
|
IF_DEBUG {
|
|
log(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i);
|
|
debugQueue();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* debugging utility
|
|
*/
|
|
static void debugQueue() {
|
|
struct timeOutQueue *ptr;
|
|
|
|
IF_DEBUG {
|
|
for (ptr = queue; ptr; ptr = ptr->next) {
|
|
log(LOG_DEBUG, 0, "(Id:%d, Time:%d) ", ptr->id, ptr->time);
|
|
}
|
|
}
|
|
}
|
|
|