1/* $Id: timer.c,v 1.1.1.1 2006-12-04 00:45:30 Exp $ */ 2/* ported from KAME: timer.c,v 1.3 2002/09/24 14:20:50 itojun Exp */ 3 4/* 5 * Copyright (C) 2002 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32#include <sys/types.h> 33#include <sys/time.h> 34#include <sys/socket.h> 35 36#include <netinet/in.h> 37 38#include <unistd.h> 39#include <syslog.h> 40#include <stdlib.h> 41#include <string.h> 42#if defined(__NetBSD__) || defined(__OpenBSD__) 43#include <search.h> 44#endif 45 46#include "queue.h" 47#include "dhcp6.h" 48#include "config.h" 49#include "common.h" 50#include "timer.h" 51 52#define MILLION 1000000 53 54LIST_HEAD(, dhcp6_timer) timer_head; 55static struct timeval tm_sentinel; 56static struct timeval tm_max = {0x7fffffff, 0x7fffffff}; 57 58/* result = a + b */ 59static void 60timeval_add(struct timeval *a, struct timeval *b, struct timeval *result) 61{ 62 long l; 63 64 if ((l = a->tv_usec + b->tv_usec) < MILLION) { 65 result->tv_usec = l; 66 result->tv_sec = a->tv_sec + b->tv_sec; 67 } 68 else { 69 result->tv_usec = l - MILLION; 70 result->tv_sec = a->tv_sec + b->tv_sec + 1; 71 } 72} 73 74void 75timeval_sub(struct timeval *a, struct timeval *b, struct timeval *result) 76{ 77 long l; 78 79 if ((l = a->tv_usec - b->tv_usec) >= 0) { 80 result->tv_usec = l; 81 result->tv_sec = a->tv_sec - b->tv_sec; 82 } 83 else { 84 result->tv_usec = MILLION + l; 85 result->tv_sec = a->tv_sec - b->tv_sec - 1; 86 } 87} 88 89void 90dhcp6_timer_init(void) 91{ 92 LIST_INIT(&timer_head); 93 tm_sentinel = tm_max; 94} 95 96struct dhcp6_timer * 97dhcp6_add_timer(struct dhcp6_timer *(*timeout)(void *), 98 void *timeodata) 99{ 100 struct dhcp6_timer *newtimer; 101 if ((newtimer = malloc(sizeof(*newtimer))) == NULL) { 102 dprintf(LOG_ERR, "%s" "can't allocate memory", FNAME); 103 return (NULL); 104 } 105 106 memset(newtimer, 0, sizeof(*newtimer)); 107 108 if (timeout == NULL) { 109 dprintf(LOG_ERR, "%s" "timeout function unspecified", FNAME); 110 return (NULL); 111 } 112 newtimer->expire = timeout; 113 newtimer->expire_data = timeodata; 114 newtimer->tm = tm_max; 115 116 LIST_INSERT_HEAD(&timer_head, newtimer, link); 117 118 return (newtimer); 119} 120 121void 122dhcp6_remove_timer(struct dhcp6_timer *timer) 123{ 124 timer->flag |= MARK_REMOVE; 125} 126 127void 128dhcp6_set_timer(struct timeval *tm, 129 struct dhcp6_timer *timer) 130{ 131 struct timeval now; 132 timer->flag |= MARK_CLEAR; 133 /* reset the timer */ 134 gettimeofday(&now, NULL); 135 136 timeval_add(&now, tm, &timer->tm); 137 138 /* update the next expiration time */ 139 if (TIMEVAL_LT(timer->tm, tm_sentinel)) 140 tm_sentinel = timer->tm; 141 return; 142} 143 144/* 145 * Check expiration for each timer. If a timer is expired, 146 * call the expire function for the timer and update the timer. 147 * Return the next interval for select() call. 148 */ 149struct timeval * 150dhcp6_check_timer(void) 151{ 152 static struct timeval returnval; 153 struct timeval now; 154 struct dhcp6_timer *tm, *tm_next; 155 156 gettimeofday(&now, NULL); 157 158 tm_sentinel = tm_max; 159 160 for (tm = LIST_FIRST(&timer_head); tm; tm = tm_next) { 161 tm_next = LIST_NEXT(tm, link); 162 if (tm->flag & MARK_REMOVE) { 163 LIST_REMOVE(tm, link); 164 free(tm); 165 tm = NULL; 166 continue; 167 } 168 if (TIMEVAL_LEQ(tm->tm, now)) { 169 if ((*tm->expire)(tm->expire_data) == NULL) 170 continue; /* timer has been freed */ 171 } 172 173 if (TIMEVAL_LT(tm->tm, tm_sentinel)) 174 tm_sentinel = tm->tm; 175 } 176 177 if (TIMEVAL_EQUAL(tm_max, tm_sentinel)) { 178 /* no need to timeout */ 179 return (NULL); 180 } else if (TIMEVAL_LT(tm_sentinel, now)) { 181 /* this may occur when the interval is too small */ 182 returnval.tv_sec = returnval.tv_usec = 0; 183 } else 184 timeval_sub(&tm_sentinel, &now, &returnval); 185 return (&returnval); 186} 187 188struct timeval * 189dhcp6_timer_rest(struct dhcp6_timer *timer) 190{ 191 struct timeval now; 192 static struct timeval returnval; 193 194 gettimeofday(&now, NULL); 195 if (TIMEVAL_LEQ(timer->tm, now)) { 196 syslog(LOG_DEBUG, 197 "<%s> a timer must be expired, but not yet", 198 __FUNCTION__); 199 returnval.tv_sec = returnval.tv_usec = 0; 200 } else 201 timeval_sub(&timer->tm, &now, &returnval); 202 203 return (&returnval); 204} 205