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