xref: /freebsd/usr.sbin/rtadvd/timer.c (revision fa19f9be0400bf0b77b89ad6940eb0675235db1c)
1ae326725SJun-ichiro itojun Hagino /*	$FreeBSD$	*/
2fa19f9beSHajimu UMEMOTO /*	$KAME: timer.c,v 1.9 2002/06/10 19:59:47 itojun Exp $	*/
3b26e03e9SKris Kennaway 
49a4365d0SYoshinobu Inoue /*
59a4365d0SYoshinobu Inoue  * Copyright (C) 1998 WIDE Project.
69a4365d0SYoshinobu Inoue  * All rights reserved.
79a4365d0SYoshinobu Inoue  *
89a4365d0SYoshinobu Inoue  * Redistribution and use in source and binary forms, with or without
99a4365d0SYoshinobu Inoue  * modification, are permitted provided that the following conditions
109a4365d0SYoshinobu Inoue  * are met:
119a4365d0SYoshinobu Inoue  * 1. Redistributions of source code must retain the above copyright
129a4365d0SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer.
139a4365d0SYoshinobu Inoue  * 2. Redistributions in binary form must reproduce the above copyright
149a4365d0SYoshinobu Inoue  *    notice, this list of conditions and the following disclaimer in the
159a4365d0SYoshinobu Inoue  *    documentation and/or other materials provided with the distribution.
169a4365d0SYoshinobu Inoue  * 3. Neither the name of the project nor the names of its contributors
179a4365d0SYoshinobu Inoue  *    may be used to endorse or promote products derived from this software
189a4365d0SYoshinobu Inoue  *    without specific prior written permission.
199a4365d0SYoshinobu Inoue  *
209a4365d0SYoshinobu Inoue  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
219a4365d0SYoshinobu Inoue  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
229a4365d0SYoshinobu Inoue  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
239a4365d0SYoshinobu Inoue  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
249a4365d0SYoshinobu Inoue  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
259a4365d0SYoshinobu Inoue  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
269a4365d0SYoshinobu Inoue  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
279a4365d0SYoshinobu Inoue  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
289a4365d0SYoshinobu Inoue  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
299a4365d0SYoshinobu Inoue  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
309a4365d0SYoshinobu Inoue  * SUCH DAMAGE.
319a4365d0SYoshinobu Inoue  */
329a4365d0SYoshinobu Inoue 
339a4365d0SYoshinobu Inoue #include <sys/time.h>
349a4365d0SYoshinobu Inoue 
359a4365d0SYoshinobu Inoue #include <unistd.h>
369a4365d0SYoshinobu Inoue #include <syslog.h>
379a4365d0SYoshinobu Inoue #include <stdlib.h>
389a4365d0SYoshinobu Inoue #include <string.h>
39b26e03e9SKris Kennaway #if defined(__NetBSD__) || defined(__OpenBSD__)
409a4365d0SYoshinobu Inoue #include <search.h>
419a4365d0SYoshinobu Inoue #endif
429a4365d0SYoshinobu Inoue #include "timer.h"
439a4365d0SYoshinobu Inoue 
449a4365d0SYoshinobu Inoue static struct rtadvd_timer timer_head;
459a4365d0SYoshinobu Inoue 
469a4365d0SYoshinobu Inoue #define MILLION 1000000
47b26e03e9SKris Kennaway #define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\
48b26e03e9SKris Kennaway  (t1)->tv_usec == (t2)->tv_usec)
499a4365d0SYoshinobu Inoue 
509a4365d0SYoshinobu Inoue static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
519a4365d0SYoshinobu Inoue 
529a4365d0SYoshinobu Inoue void
539a4365d0SYoshinobu Inoue rtadvd_timer_init()
549a4365d0SYoshinobu Inoue {
559a4365d0SYoshinobu Inoue 	memset(&timer_head, 0, sizeof(timer_head));
569a4365d0SYoshinobu Inoue 
579a4365d0SYoshinobu Inoue 	timer_head.next = timer_head.prev = &timer_head;
589a4365d0SYoshinobu Inoue 	timer_head.tm = tm_max;
599a4365d0SYoshinobu Inoue }
609a4365d0SYoshinobu Inoue 
619a4365d0SYoshinobu Inoue struct rtadvd_timer *
620a5f3ef4SHajimu UMEMOTO rtadvd_add_timer(struct rtadvd_timer *(*timeout) __P((void *)),
639a4365d0SYoshinobu Inoue     void (*update) __P((void *, struct timeval *)),
649a4365d0SYoshinobu Inoue     void *timeodata, void *updatedata)
659a4365d0SYoshinobu Inoue {
669a4365d0SYoshinobu Inoue 	struct rtadvd_timer *newtimer;
679a4365d0SYoshinobu Inoue 
689a4365d0SYoshinobu Inoue 	if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
699a4365d0SYoshinobu Inoue 		syslog(LOG_ERR,
701533bed0SHajimu UMEMOTO 		       "<%s> can't allocate memory", __func__);
719a4365d0SYoshinobu Inoue 		exit(1);
729a4365d0SYoshinobu Inoue 	}
739a4365d0SYoshinobu Inoue 
749a4365d0SYoshinobu Inoue 	memset(newtimer, 0, sizeof(*newtimer));
759a4365d0SYoshinobu Inoue 
769a4365d0SYoshinobu Inoue 	if (timeout == NULL) {
779a4365d0SYoshinobu Inoue 		syslog(LOG_ERR,
78fa19f9beSHajimu UMEMOTO 		       "<%s> timeout function unspecified", __func__);
799a4365d0SYoshinobu Inoue 		exit(1);
809a4365d0SYoshinobu Inoue 	}
819a4365d0SYoshinobu Inoue 	newtimer->expire = timeout;
829a4365d0SYoshinobu Inoue 	newtimer->update = update;
839a4365d0SYoshinobu Inoue 	newtimer->expire_data = timeodata;
849a4365d0SYoshinobu Inoue 	newtimer->update_data = updatedata;
859a4365d0SYoshinobu Inoue 	newtimer->tm = tm_max;
869a4365d0SYoshinobu Inoue 
879a4365d0SYoshinobu Inoue 	/* link into chain */
889a4365d0SYoshinobu Inoue 	insque(newtimer, &timer_head);
899a4365d0SYoshinobu Inoue 
909a4365d0SYoshinobu Inoue 	return(newtimer);
919a4365d0SYoshinobu Inoue }
929a4365d0SYoshinobu Inoue 
939a4365d0SYoshinobu Inoue void
94b26e03e9SKris Kennaway rtadvd_remove_timer(struct rtadvd_timer **timer)
95b26e03e9SKris Kennaway {
96b26e03e9SKris Kennaway 	remque(*timer);
97b26e03e9SKris Kennaway 	free(*timer);
98b26e03e9SKris Kennaway 	*timer = NULL;
99b26e03e9SKris Kennaway }
100b26e03e9SKris Kennaway 
101b26e03e9SKris Kennaway void
1029a4365d0SYoshinobu Inoue rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
1039a4365d0SYoshinobu Inoue {
1049a4365d0SYoshinobu Inoue 	struct timeval now;
1059a4365d0SYoshinobu Inoue 
1069a4365d0SYoshinobu Inoue 	/* reset the timer */
1079a4365d0SYoshinobu Inoue 	gettimeofday(&now, NULL);
1089a4365d0SYoshinobu Inoue 
1099a4365d0SYoshinobu Inoue 	TIMEVAL_ADD(&now, tm, &timer->tm);
1109a4365d0SYoshinobu Inoue 
1119a4365d0SYoshinobu Inoue 	/* update the next expiration time */
1129a4365d0SYoshinobu Inoue 	if (TIMEVAL_LT(timer->tm, timer_head.tm))
1139a4365d0SYoshinobu Inoue 		timer_head.tm = timer->tm;
1149a4365d0SYoshinobu Inoue 
1159a4365d0SYoshinobu Inoue 	return;
1169a4365d0SYoshinobu Inoue }
1179a4365d0SYoshinobu Inoue 
1189a4365d0SYoshinobu Inoue /*
1190a5f3ef4SHajimu UMEMOTO  * Check expiration for each timer. If a timer expires,
1209a4365d0SYoshinobu Inoue  * call the expire function for the timer and update the timer.
1219a4365d0SYoshinobu Inoue  * Return the next interval for select() call.
1229a4365d0SYoshinobu Inoue  */
1239a4365d0SYoshinobu Inoue struct timeval *
1249a4365d0SYoshinobu Inoue rtadvd_check_timer()
1259a4365d0SYoshinobu Inoue {
1269a4365d0SYoshinobu Inoue 	static struct timeval returnval;
1279a4365d0SYoshinobu Inoue 	struct timeval now;
1280a5f3ef4SHajimu UMEMOTO 	struct rtadvd_timer *tm = timer_head.next, *tm_next;
1299a4365d0SYoshinobu Inoue 
1309a4365d0SYoshinobu Inoue 	gettimeofday(&now, NULL);
1319a4365d0SYoshinobu Inoue 
1329a4365d0SYoshinobu Inoue 	timer_head.tm = tm_max;
1339a4365d0SYoshinobu Inoue 
1340a5f3ef4SHajimu UMEMOTO 	for (tm = timer_head.next; tm != &timer_head; tm = tm_next) {
1350a5f3ef4SHajimu UMEMOTO 		tm_next = tm->next;
1360a5f3ef4SHajimu UMEMOTO 
1379a4365d0SYoshinobu Inoue 		if (TIMEVAL_LEQ(tm->tm, now)) {
1380a5f3ef4SHajimu UMEMOTO 			if (((*tm->expire)(tm->expire_data) == NULL))
1390a5f3ef4SHajimu UMEMOTO 				continue; /* the timer was removed */
1400a5f3ef4SHajimu UMEMOTO 			if (tm->update)
1419a4365d0SYoshinobu Inoue 				(*tm->update)(tm->update_data, &tm->tm);
1429a4365d0SYoshinobu Inoue 			TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
1439a4365d0SYoshinobu Inoue 		}
1449a4365d0SYoshinobu Inoue 
1459a4365d0SYoshinobu Inoue 		if (TIMEVAL_LT(tm->tm, timer_head.tm))
1469a4365d0SYoshinobu Inoue 			timer_head.tm = tm->tm;
1479a4365d0SYoshinobu Inoue 	}
1489a4365d0SYoshinobu Inoue 
149b26e03e9SKris Kennaway 	if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) {
150b26e03e9SKris Kennaway 		/* no need to timeout */
151b26e03e9SKris Kennaway 		return(NULL);
152fa19f9beSHajimu UMEMOTO 	} else if (TIMEVAL_LT(timer_head.tm, now)) {
1539a4365d0SYoshinobu Inoue 		/* this may occur when the interval is too small */
1549a4365d0SYoshinobu Inoue 		returnval.tv_sec = returnval.tv_usec = 0;
155fa19f9beSHajimu UMEMOTO 	} else
1569a4365d0SYoshinobu Inoue 		TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
1579a4365d0SYoshinobu Inoue 	return(&returnval);
1589a4365d0SYoshinobu Inoue }
1599a4365d0SYoshinobu Inoue 
1609a4365d0SYoshinobu Inoue struct timeval *
1619a4365d0SYoshinobu Inoue rtadvd_timer_rest(struct rtadvd_timer *timer)
1629a4365d0SYoshinobu Inoue {
1639a4365d0SYoshinobu Inoue 	static struct timeval returnval, now;
1649a4365d0SYoshinobu Inoue 
1659a4365d0SYoshinobu Inoue 	gettimeofday(&now, NULL);
1669a4365d0SYoshinobu Inoue 	if (TIMEVAL_LEQ(timer->tm, now)) {
1679a4365d0SYoshinobu Inoue 		syslog(LOG_DEBUG,
1689a4365d0SYoshinobu Inoue 		       "<%s> a timer must be expired, but not yet",
1691533bed0SHajimu UMEMOTO 		       __func__);
1709a4365d0SYoshinobu Inoue 		returnval.tv_sec = returnval.tv_usec = 0;
1719a4365d0SYoshinobu Inoue 	}
1729a4365d0SYoshinobu Inoue 	else
1739a4365d0SYoshinobu Inoue 		TIMEVAL_SUB(&timer->tm, &now, &returnval);
1749a4365d0SYoshinobu Inoue 
1759a4365d0SYoshinobu Inoue 	return(&returnval);
1769a4365d0SYoshinobu Inoue }
1779a4365d0SYoshinobu Inoue 
1789a4365d0SYoshinobu Inoue /* result = a + b */
1799a4365d0SYoshinobu Inoue void
1809a4365d0SYoshinobu Inoue TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
1819a4365d0SYoshinobu Inoue {
1829a4365d0SYoshinobu Inoue 	long l;
1839a4365d0SYoshinobu Inoue 
1849a4365d0SYoshinobu Inoue 	if ((l = a->tv_usec + b->tv_usec) < MILLION) {
1859a4365d0SYoshinobu Inoue 		result->tv_usec = l;
1869a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec + b->tv_sec;
1879a4365d0SYoshinobu Inoue 	}
1889a4365d0SYoshinobu Inoue 	else {
1899a4365d0SYoshinobu Inoue 		result->tv_usec = l - MILLION;
1909a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec + b->tv_sec + 1;
1919a4365d0SYoshinobu Inoue 	}
1929a4365d0SYoshinobu Inoue }
1939a4365d0SYoshinobu Inoue 
1949a4365d0SYoshinobu Inoue /*
1959a4365d0SYoshinobu Inoue  * result = a - b
1969a4365d0SYoshinobu Inoue  * XXX: this function assumes that a >= b.
1979a4365d0SYoshinobu Inoue  */
1989a4365d0SYoshinobu Inoue void
1999a4365d0SYoshinobu Inoue TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
2009a4365d0SYoshinobu Inoue {
2019a4365d0SYoshinobu Inoue 	long l;
2029a4365d0SYoshinobu Inoue 
2039a4365d0SYoshinobu Inoue 	if ((l = a->tv_usec - b->tv_usec) >= 0) {
2049a4365d0SYoshinobu Inoue 		result->tv_usec = l;
2059a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec - b->tv_sec;
2069a4365d0SYoshinobu Inoue 	}
2079a4365d0SYoshinobu Inoue 	else {
2089a4365d0SYoshinobu Inoue 		result->tv_usec = MILLION + l;
2099a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec - b->tv_sec - 1;
2109a4365d0SYoshinobu Inoue 	}
2119a4365d0SYoshinobu Inoue }
212