1/* 2** igmpproxy - IGMP proxy based multicast router 3** Copyright (C) 2005 Johnny Egeland <johnny@rlo.org> 4** 5** This program is free software; you can redistribute it and/or modify 6** it under the terms of the GNU General Public License as published by 7** the Free Software Foundation; either version 2 of the License, or 8** (at your option) any later version. 9** 10** This program is distributed in the hope that it will be useful, 11** but WITHOUT ANY WARRANTY; without even the implied warranty of 12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13** GNU General Public License for more details. 14** 15** You should have received a copy of the GNU General Public License 16** along with this program; if not, write to the Free Software 17** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18** 19**---------------------------------------------------------------------------- 20** 21** This software is derived work from the following software. The original 22** source code has been modified from it's original state by the author 23** of igmpproxy. 24** 25** smcroute 0.92 - Copyright (C) 2001 Carsten Schill <carsten@cschill.de> 26** - Licensed under the GNU General Public License, version 2 27** 28** mrouted 3.9-beta3 - COPYRIGHT 1989 by The Board of Trustees of 29** Leland Stanford Junior University. 30** - Original license can be found in the "doc/mrouted-LINCESE" file. 31** 32*/ 33 34 35#include "defs.h" 36 37/* the code below implements a callout queue */ 38static int id = 0; 39static struct timeOutQueue *queue = 0; /* pointer to the beginning of timeout queue */ 40 41struct timeOutQueue { 42 struct timeOutQueue *next; // Next event in queue 43 int id; 44 cfunc_t func; // function to call 45 void *data; // Data for function 46 int time; // Time offset for next event 47}; 48 49// Method for dumping the Queue to the igmp_syslog. 50static void debugQueue(void); 51 52/** 53* Initializes the callout queue 54*/ 55void callout_init() { 56 queue = NULL; 57} 58 59/** 60* Clears all scheduled timeouts... 61*/ 62void free_all_callouts() { 63 struct timeOutQueue *p; 64 65 while (queue) { 66 p = queue; 67 queue = queue->next; 68 free(p); 69 } 70} 71 72 73/** 74 * elapsed_time seconds have passed; perform all the events that should 75 * happen. 76 */ 77void age_callout_queue(int elapsed_time) { 78 struct timeOutQueue *ptr; 79 int i = 0; 80 81 for (ptr = queue; ptr; ptr = queue, i++) { 82 if (ptr->time > elapsed_time) { 83 ptr->time -= elapsed_time; 84 return; 85 } else { 86 elapsed_time -= ptr->time; 87 queue = queue->next; 88 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "About to call timeout %d (#%d)", ptr->id, i); 89 90 if (ptr->func) 91 ptr->func(ptr->data); 92 free(ptr); 93 } 94 } 95} 96 97/** 98 * Return in how many seconds age_callout_queue() would like to be called. 99 * Return -1 if there are no events pending. 100 */ 101int timer_nextTimer() { 102 if (queue) { 103 if (queue->time < 0) { 104 igmp_syslog(LOG_WARNING, 0, "timer_nextTimer top of queue says %d", 105 queue->time); 106 return 0; 107 } 108 return queue->time; 109 } 110 return -1; 111} 112 113/** 114 * Inserts a timer in queue. 115 * @param delay - Number of seconds the timeout should happen in. 116 * @param action - The function to call on timeout. 117 * @param data - Pointer to the function data to supply... 118 */ 119int timer_setTimer(int delay, cfunc_t action, void *data) { 120 struct timeOutQueue *ptr, *node, *prev; 121 int i = 0; 122 123 /* create a node */ 124 node = (struct timeOutQueue *)malloc(sizeof(struct timeOutQueue)); 125 if (node == 0) { 126 igmp_syslog(LOG_WARNING, 0, "Malloc Failed in timer_settimer\n"); 127 return -1; 128 } 129 node->func = action; 130 node->data = data; 131 node->time = delay; 132 node->next = 0; 133 node->id = ++id; 134 135 prev = ptr = queue; 136 137 /* insert node in the queue */ 138 139 /* if the queue is empty, insert the node and return */ 140 if (!queue) { 141 queue = node; 142 } 143 else { 144 /* chase the pointer looking for the right place */ 145 while (ptr) { 146 if (delay < ptr->time) { 147 // We found the correct node 148 node->next = ptr; 149 if (ptr == queue) { 150 queue = node; 151 } 152 else { 153 prev->next = node; 154 } 155 ptr->time -= node->time; 156 IF_DEBUG { 157 igmp_syslog(LOG_DEBUG, 0, "Created timeout %d (#%d) - delay %d secs", 158 node->id, i, node->time); 159 160// debugQueue(); 161 } 162 return node->id; 163 } else { 164 // Continur to check nodes. 165 delay -= ptr->time; node->time = delay; 166 prev = ptr; 167 ptr = ptr->next; 168 } 169 i++; 170 } 171 prev->next = node; 172 } 173 IF_DEBUG { 174 igmp_syslog(LOG_DEBUG, 0, "Created timeout %d (#%d) - delay %d secs", 175 node->id, i, node->time); 176 177// debugQueue(); 178 } 179 180 return node->id; 181} 182 183/** 184* returns the time until the timer is scheduled 185*/ 186int timer_leftTimer(int timer_id) { 187 struct timeOutQueue *ptr; 188 int left = 0; 189 190 if (!timer_id) 191 return -1; 192 193 for (ptr = queue; ptr; ptr = ptr->next) { 194 left += ptr->time; 195 if (ptr->id == timer_id) { 196 return left; 197 } 198 } 199 return -1; 200} 201 202/** 203* clears the associated timer. Returns 1 if succeeded. 204*/ 205int timer_clearTimer(int timer_id) { 206 struct timeOutQueue *ptr, *prev; 207 int i = 0; 208 209 if (!timer_id) 210 return 0; 211 212 prev = ptr = queue; 213 214 /* 215 * find the right node, delete it. the subsequent node's time 216 * gets bumped up 217 */ 218 219 IF_DEBUG debugQueue(); 220 while (ptr) { 221 if (ptr->id == timer_id) { 222 /* got the right node */ 223 224 /* unlink it from the queue */ 225 if (ptr == queue) 226 queue = queue->next; 227 else 228 prev->next = ptr->next; 229 230 /* increment next node if any */ 231 if (ptr->next != 0) 232 (ptr->next)->time += ptr->time; 233 234 if (ptr->data) 235 free(ptr->data); 236 IF_DEBUG igmp_syslog(LOG_DEBUG, 0, "deleted timer %d (#%d)", ptr->id, i); 237 free(ptr); 238 IF_DEBUG debugQueue(); 239 return 1; 240 } 241 prev = ptr; 242 ptr = ptr->next; 243 i++; 244 } 245 // If we get here, the timer was not deleted. 246 IF_DEBUG { 247 igmp_syslog(LOG_DEBUG, 0, "failed to delete timer %d (#%d)", timer_id, i); 248 debugQueue(); 249 } 250 return 0; 251} 252 253/** 254 * debugging utility 255 */ 256static void debugQueue() { 257 struct timeOutQueue *ptr; 258 259 IF_DEBUG { 260 for (ptr = queue; ptr; ptr = ptr->next) { 261 igmp_syslog(LOG_DEBUG, 0, "(Id:%d, Time:%d) ", ptr->id, ptr->time); 262 } 263 } 264} 265 266