freebsd-skq/usr.sbin/pim6sd/callout.c
Yoshinobu Inoue 0fea3d5165 IPv6 multicast routing.
kernel IPv6 multicast routing support.
  pim6 dense mode daemon
  pim6 sparse mode daemon
  netstat support of IPv6 multicast routing statistics

  Merging to the current and testing with other existing multicast routers
  is done by Tatsuya Jinmei <jinmei@kame.net>, who writes and maintainances
  the base code in KAME distribution.

  Make world check and kernel build check was also successful.
2000-01-28 05:10:56 +00:00

317 lines
5.4 KiB
C

/*
* The mrouted program is covered by the license in the accompanying file
* named "LICENSE.mrouted". Use of the mrouted program represents acceptance
* of the terms and conditions listed in that file.
*
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
* Leland Stanford Junior University.
*
*
* callout.c,v 3.8.4.5 1997/05/16 20:18:25 fenner Exp
*/
/*
* Questions concerning this software should be directed to
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
*
*/
/*
* This program has been derived from pim6dd.
* The pim6dd program is covered by the license in the accompanying file
* named "LICENSE.pim6dd".
*/
/*
* This program has been derived from pimd.
* The pimd program is covered by the license in the accompanying file
* named "LICENSE.pimd".
*
* $FreeBSD$
*/
#include <stdio.h>
#include <syslog.h>
#include <stdlib.h>
#include "debug.h"
#include "defs.h"
/* the code below implements a callout queue */
static int id = 0;
static struct timeout_q *Q = 0; /* pointer to the beginning of timeout queue */
struct timeout_q
{
struct timeout_q *next; /* next event */
int id;
cfunc_t func; /* function to call */
void *data; /* func's data */
int time; /* time offset to next event */
};
#if 0
#define CALLOUT_DEBUG 1
#define CALLOUT_DEBUG2 1
#endif /* 0 */
#ifdef CALLOUT_DEBUG2
static void print_Q __P((void));
#else
#define print_Q()
#endif
void
callout_init()
{
Q = (struct timeout_q *) 0;
}
void
free_all_callouts()
{
struct timeout_q *p;
while (Q)
{
p = Q;
Q = Q->next;
free(p);
}
}
/*
* elapsed_time seconds have passed; perform all the events that should
* happen.
*/
void
age_callout_queue(elapsed_time)
int elapsed_time;
{
struct timeout_q *ptr,
*expQ;
#ifdef CALLOUT_DEBUG
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "aging queue (elapsed time %d):", elapsed_time);
print_Q();
#endif
expQ = Q;
ptr = NULL;
while (Q)
{
if (Q->time > elapsed_time)
{
Q->time -= elapsed_time;
if (ptr)
{
ptr->next = NULL;
break;
}
return;
}
else
{
elapsed_time -= Q->time;
ptr = Q;
Q = Q->next;
}
}
/* handle queue of expired timers */
while (expQ)
{
ptr = expQ;
if (ptr->func)
ptr->func(ptr->data);
expQ = expQ->next;
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 (Q)
{
if (Q->time < 0)
{
log(LOG_WARNING, 0, "timer_nextTimer top of queue says %d",
Q->time);
return 0;
}
return Q->time;
}
return -1;
}
/*
* sets the timer
*/
int
timer_setTimer(delay, action, data)
int delay; /* number of units for timeout */
cfunc_t action; /* function to be called on timeout */
void *data; /* what to call the timeout function with */
{
struct timeout_q *ptr,
*node,
*prev;
#ifdef CALLOUT_DEBUG
IF_DEBUG(DEBUG_TIMEOUT)
log(LOG_DEBUG, 0, "setting timer:");
print_Q();
#endif
/* create a node */
node = (struct timeout_q *) malloc(sizeof(struct timeout_q));
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 = Q;
/* insert node in the queue */
/* if the queue is empty, insert the node and return */
if (!Q)
Q = node;
else
{
/* chase the pointer looking for the right place */
while (ptr)
{
if (delay < ptr->time)
{
/* right place */
node->next = ptr;
if (ptr == Q)
Q = node;
else
prev->next = node;
ptr->time -= node->time;
print_Q();
return node->id;
}
else
{
/* keep moving */
delay -= ptr->time;
node->time = delay;
prev = ptr;
ptr = ptr->next;
}
}
prev->next = node;
}
print_Q();
return node->id;
}
/* returns the time until the timer is scheduled */
int
timer_leftTimer(timer_id)
int timer_id;
{
struct timeout_q *ptr;
int left = 0;
if (!timer_id)
return -1;
for (ptr = Q; ptr; ptr = ptr->next)
{
left += ptr->time;
if (ptr->id == timer_id)
return left;
}
return -1;
}
/* clears the associated timer */
void
timer_clearTimer(timer_id)
int timer_id;
{
struct timeout_q *ptr,
*prev;
if (!timer_id)
return;
prev = ptr = Q;
/*
* find the right node, delete it. the subsequent node's time gets bumped
* up
*/
print_Q();
while (ptr)
{
if (ptr->id == timer_id)
{
/* got the right node */
/* unlink it from the queue */
if (ptr == Q)
Q = Q->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);
free(ptr);
print_Q();
return;
}
prev = ptr;
ptr = ptr->next;
}
print_Q();
}
#ifdef CALLOUT_DEBUG2
/*
* debugging utility
*/
static void
print_Q()
{
struct timeout_q *ptr;
IF_DEBUG(DEBUG_TIMEOUT)
for (ptr = Q; ptr; ptr = ptr->next)
log(LOG_DEBUG, 0, "(%d,%d) ", ptr->id, ptr->time);
}
#endif /* CALLOUT_DEBUG2 */