xref: /freebsd/usr.sbin/rtadvd/timer.c (revision 784bddbc5bca158d2fb57eed7c5e4ceebd49ff8b)
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>
3972286081SSUZUKI Shinsuke #include <search.h>
409a4365d0SYoshinobu Inoue #include "timer.h"
419a4365d0SYoshinobu Inoue 
429a4365d0SYoshinobu Inoue static struct rtadvd_timer timer_head;
439a4365d0SYoshinobu Inoue 
449a4365d0SYoshinobu Inoue #define MILLION 1000000
45b26e03e9SKris Kennaway #define TIMEVAL_EQUAL(t1,t2) ((t1)->tv_sec == (t2)->tv_sec &&\
46b26e03e9SKris Kennaway  (t1)->tv_usec == (t2)->tv_usec)
479a4365d0SYoshinobu Inoue 
489a4365d0SYoshinobu Inoue static struct timeval tm_max = {0x7fffffff, 0x7fffffff};
499a4365d0SYoshinobu Inoue 
509a4365d0SYoshinobu Inoue void
519a4365d0SYoshinobu Inoue rtadvd_timer_init()
529a4365d0SYoshinobu Inoue {
539a4365d0SYoshinobu Inoue 	memset(&timer_head, 0, sizeof(timer_head));
549a4365d0SYoshinobu Inoue 
559a4365d0SYoshinobu Inoue 	timer_head.next = timer_head.prev = &timer_head;
569a4365d0SYoshinobu Inoue 	timer_head.tm = tm_max;
579a4365d0SYoshinobu Inoue }
589a4365d0SYoshinobu Inoue 
599a4365d0SYoshinobu Inoue struct rtadvd_timer *
60784bddbcSKevin Lo rtadvd_add_timer(struct rtadvd_timer *(*timeout)(void *),
61784bddbcSKevin Lo     void (*update)(void *, struct timeval *),
629a4365d0SYoshinobu Inoue     void *timeodata, void *updatedata)
639a4365d0SYoshinobu Inoue {
649a4365d0SYoshinobu Inoue 	struct rtadvd_timer *newtimer;
659a4365d0SYoshinobu Inoue 
669a4365d0SYoshinobu Inoue 	if ((newtimer = malloc(sizeof(*newtimer))) == NULL) {
679a4365d0SYoshinobu Inoue 		syslog(LOG_ERR,
681533bed0SHajimu UMEMOTO 		       "<%s> can't allocate memory", __func__);
699a4365d0SYoshinobu Inoue 		exit(1);
709a4365d0SYoshinobu Inoue 	}
719a4365d0SYoshinobu Inoue 
729a4365d0SYoshinobu Inoue 	memset(newtimer, 0, sizeof(*newtimer));
739a4365d0SYoshinobu Inoue 
749a4365d0SYoshinobu Inoue 	if (timeout == NULL) {
759a4365d0SYoshinobu Inoue 		syslog(LOG_ERR,
76fa19f9beSHajimu UMEMOTO 		       "<%s> timeout function unspecified", __func__);
779a4365d0SYoshinobu Inoue 		exit(1);
789a4365d0SYoshinobu Inoue 	}
799a4365d0SYoshinobu Inoue 	newtimer->expire = timeout;
809a4365d0SYoshinobu Inoue 	newtimer->update = update;
819a4365d0SYoshinobu Inoue 	newtimer->expire_data = timeodata;
829a4365d0SYoshinobu Inoue 	newtimer->update_data = updatedata;
839a4365d0SYoshinobu Inoue 	newtimer->tm = tm_max;
849a4365d0SYoshinobu Inoue 
859a4365d0SYoshinobu Inoue 	/* link into chain */
869a4365d0SYoshinobu Inoue 	insque(newtimer, &timer_head);
879a4365d0SYoshinobu Inoue 
889a4365d0SYoshinobu Inoue 	return(newtimer);
899a4365d0SYoshinobu Inoue }
909a4365d0SYoshinobu Inoue 
919a4365d0SYoshinobu Inoue void
92b26e03e9SKris Kennaway rtadvd_remove_timer(struct rtadvd_timer **timer)
93b26e03e9SKris Kennaway {
94b26e03e9SKris Kennaway 	remque(*timer);
95b26e03e9SKris Kennaway 	free(*timer);
96b26e03e9SKris Kennaway 	*timer = NULL;
97b26e03e9SKris Kennaway }
98b26e03e9SKris Kennaway 
99b26e03e9SKris Kennaway void
1009a4365d0SYoshinobu Inoue rtadvd_set_timer(struct timeval *tm, struct rtadvd_timer *timer)
1019a4365d0SYoshinobu Inoue {
1029a4365d0SYoshinobu Inoue 	struct timeval now;
1039a4365d0SYoshinobu Inoue 
1049a4365d0SYoshinobu Inoue 	/* reset the timer */
1059a4365d0SYoshinobu Inoue 	gettimeofday(&now, NULL);
1069a4365d0SYoshinobu Inoue 
1079a4365d0SYoshinobu Inoue 	TIMEVAL_ADD(&now, tm, &timer->tm);
1089a4365d0SYoshinobu Inoue 
1099a4365d0SYoshinobu Inoue 	/* update the next expiration time */
1109a4365d0SYoshinobu Inoue 	if (TIMEVAL_LT(timer->tm, timer_head.tm))
1119a4365d0SYoshinobu Inoue 		timer_head.tm = timer->tm;
1129a4365d0SYoshinobu Inoue 
1139a4365d0SYoshinobu Inoue 	return;
1149a4365d0SYoshinobu Inoue }
1159a4365d0SYoshinobu Inoue 
1169a4365d0SYoshinobu Inoue /*
1170a5f3ef4SHajimu UMEMOTO  * Check expiration for each timer. If a timer expires,
1189a4365d0SYoshinobu Inoue  * call the expire function for the timer and update the timer.
1199a4365d0SYoshinobu Inoue  * Return the next interval for select() call.
1209a4365d0SYoshinobu Inoue  */
1219a4365d0SYoshinobu Inoue struct timeval *
1229a4365d0SYoshinobu Inoue rtadvd_check_timer()
1239a4365d0SYoshinobu Inoue {
1249a4365d0SYoshinobu Inoue 	static struct timeval returnval;
1259a4365d0SYoshinobu Inoue 	struct timeval now;
1260a5f3ef4SHajimu UMEMOTO 	struct rtadvd_timer *tm = timer_head.next, *tm_next;
1279a4365d0SYoshinobu Inoue 
1289a4365d0SYoshinobu Inoue 	gettimeofday(&now, NULL);
1299a4365d0SYoshinobu Inoue 
1309a4365d0SYoshinobu Inoue 	timer_head.tm = tm_max;
1319a4365d0SYoshinobu Inoue 
1320a5f3ef4SHajimu UMEMOTO 	for (tm = timer_head.next; tm != &timer_head; tm = tm_next) {
1330a5f3ef4SHajimu UMEMOTO 		tm_next = tm->next;
1340a5f3ef4SHajimu UMEMOTO 
1359a4365d0SYoshinobu Inoue 		if (TIMEVAL_LEQ(tm->tm, now)) {
1360a5f3ef4SHajimu UMEMOTO 			if (((*tm->expire)(tm->expire_data) == NULL))
1370a5f3ef4SHajimu UMEMOTO 				continue; /* the timer was removed */
1380a5f3ef4SHajimu UMEMOTO 			if (tm->update)
1399a4365d0SYoshinobu Inoue 				(*tm->update)(tm->update_data, &tm->tm);
1409a4365d0SYoshinobu Inoue 			TIMEVAL_ADD(&tm->tm, &now, &tm->tm);
1419a4365d0SYoshinobu Inoue 		}
1429a4365d0SYoshinobu Inoue 
1439a4365d0SYoshinobu Inoue 		if (TIMEVAL_LT(tm->tm, timer_head.tm))
1449a4365d0SYoshinobu Inoue 			timer_head.tm = tm->tm;
1459a4365d0SYoshinobu Inoue 	}
1469a4365d0SYoshinobu Inoue 
147b26e03e9SKris Kennaway 	if (TIMEVAL_EQUAL(&tm_max, &timer_head.tm)) {
148b26e03e9SKris Kennaway 		/* no need to timeout */
149b26e03e9SKris Kennaway 		return(NULL);
150fa19f9beSHajimu UMEMOTO 	} else if (TIMEVAL_LT(timer_head.tm, now)) {
1519a4365d0SYoshinobu Inoue 		/* this may occur when the interval is too small */
1529a4365d0SYoshinobu Inoue 		returnval.tv_sec = returnval.tv_usec = 0;
153fa19f9beSHajimu UMEMOTO 	} else
1549a4365d0SYoshinobu Inoue 		TIMEVAL_SUB(&timer_head.tm, &now, &returnval);
1559a4365d0SYoshinobu Inoue 	return(&returnval);
1569a4365d0SYoshinobu Inoue }
1579a4365d0SYoshinobu Inoue 
1589a4365d0SYoshinobu Inoue struct timeval *
1599a4365d0SYoshinobu Inoue rtadvd_timer_rest(struct rtadvd_timer *timer)
1609a4365d0SYoshinobu Inoue {
1619a4365d0SYoshinobu Inoue 	static struct timeval returnval, now;
1629a4365d0SYoshinobu Inoue 
1639a4365d0SYoshinobu Inoue 	gettimeofday(&now, NULL);
1649a4365d0SYoshinobu Inoue 	if (TIMEVAL_LEQ(timer->tm, now)) {
1659a4365d0SYoshinobu Inoue 		syslog(LOG_DEBUG,
1669a4365d0SYoshinobu Inoue 		       "<%s> a timer must be expired, but not yet",
1671533bed0SHajimu UMEMOTO 		       __func__);
1689a4365d0SYoshinobu Inoue 		returnval.tv_sec = returnval.tv_usec = 0;
1699a4365d0SYoshinobu Inoue 	}
1709a4365d0SYoshinobu Inoue 	else
1719a4365d0SYoshinobu Inoue 		TIMEVAL_SUB(&timer->tm, &now, &returnval);
1729a4365d0SYoshinobu Inoue 
1739a4365d0SYoshinobu Inoue 	return(&returnval);
1749a4365d0SYoshinobu Inoue }
1759a4365d0SYoshinobu Inoue 
1769a4365d0SYoshinobu Inoue /* result = a + b */
1779a4365d0SYoshinobu Inoue void
1789a4365d0SYoshinobu Inoue TIMEVAL_ADD(struct timeval *a, struct timeval *b, struct timeval *result)
1799a4365d0SYoshinobu Inoue {
1809a4365d0SYoshinobu Inoue 	long l;
1819a4365d0SYoshinobu Inoue 
1829a4365d0SYoshinobu Inoue 	if ((l = a->tv_usec + b->tv_usec) < MILLION) {
1839a4365d0SYoshinobu Inoue 		result->tv_usec = l;
1849a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec + b->tv_sec;
1859a4365d0SYoshinobu Inoue 	}
1869a4365d0SYoshinobu Inoue 	else {
1879a4365d0SYoshinobu Inoue 		result->tv_usec = l - MILLION;
1889a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec + b->tv_sec + 1;
1899a4365d0SYoshinobu Inoue 	}
1909a4365d0SYoshinobu Inoue }
1919a4365d0SYoshinobu Inoue 
1929a4365d0SYoshinobu Inoue /*
1939a4365d0SYoshinobu Inoue  * result = a - b
1949a4365d0SYoshinobu Inoue  * XXX: this function assumes that a >= b.
1959a4365d0SYoshinobu Inoue  */
1969a4365d0SYoshinobu Inoue void
1979a4365d0SYoshinobu Inoue TIMEVAL_SUB(struct timeval *a, struct timeval *b, struct timeval *result)
1989a4365d0SYoshinobu Inoue {
1999a4365d0SYoshinobu Inoue 	long l;
2009a4365d0SYoshinobu Inoue 
2019a4365d0SYoshinobu Inoue 	if ((l = a->tv_usec - b->tv_usec) >= 0) {
2029a4365d0SYoshinobu Inoue 		result->tv_usec = l;
2039a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec - b->tv_sec;
2049a4365d0SYoshinobu Inoue 	}
2059a4365d0SYoshinobu Inoue 	else {
2069a4365d0SYoshinobu Inoue 		result->tv_usec = MILLION + l;
2079a4365d0SYoshinobu Inoue 		result->tv_sec = a->tv_sec - b->tv_sec - 1;
2089a4365d0SYoshinobu Inoue 	}
2099a4365d0SYoshinobu Inoue }
210