2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2008 Roy Marples <roy@marples.name>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 static struct timeval now
;
44 void (*callback
)(void *);
48 static struct event
*free_events
;
50 static struct timeout
{
52 void (*callback
)(void *);
56 static struct timeout
*free_timeouts
;
58 static struct pollfd
*fds
;
59 static size_t fds_len
;
62 add_event(int fd
, void (*callback
)(void *), void *arg
)
64 struct event
*e
, *last
= NULL
;
66 /* We should only have one callback monitoring the fd */
67 for (e
= events
; e
; e
= e
->next
) {
69 e
->callback
= callback
;
76 /* Allocate a new event if no free ones already allocated */
79 free_events
= e
->next
;
81 e
= xmalloc(sizeof(*e
));
83 e
->callback
= callback
;
95 struct event
*e
, *last
= NULL
;
97 for (e
= events
; e
; e
= e
->next
) {
100 last
->next
= e
->next
;
103 e
->next
= free_events
;
112 add_timeout_tv(const struct timeval
*when
, void (*callback
)(void *), void *arg
)
115 struct timeout
*t
, *tt
= NULL
;
118 timeradd(&now
, when
, &w
);
119 /* Check for time_t overflow. */
120 if (timercmp(&w
, &now
, <)) {
125 /* Remove existing timeout if present */
126 for (t
= timeouts
; t
; t
= t
->next
) {
127 if (t
->callback
== callback
&& t
->arg
== arg
) {
138 /* No existing, so allocate or grab one from the free pool */
141 free_timeouts
= t
->next
;
143 t
= xmalloc(sizeof(*t
));
146 t
->when
.tv_sec
= w
.tv_sec
;
147 t
->when
.tv_usec
= w
.tv_usec
;
148 t
->callback
= callback
;
151 /* The timeout list should be in chronological order,
153 * This is the easiest algorithm - check the head, then middle
154 * and finally the end. */
155 if (!timeouts
|| timercmp(&t
->when
, &timeouts
->when
, <)) {
160 for (tt
= timeouts
; tt
->next
; tt
= tt
->next
)
161 if (timercmp(&t
->when
, &tt
->next
->when
, <)) {
171 add_timeout_sec(time_t when
, void (*callback
)(void *), void *arg
)
177 add_timeout_tv(&tv
, callback
, arg
);
180 /* This deletes all timeouts for the interface EXCEPT for ones with the
181 * callbacks given. Handy for deleting everything apart from the expire
184 delete_timeouts(void *arg
, void (*callback
)(void *), ...)
186 struct timeout
*t
, *tt
, *last
= NULL
;
190 for (t
= timeouts
; t
&& (tt
= t
->next
, 1); t
= tt
) {
191 if (t
->arg
== arg
&& t
->callback
!= callback
) {
192 va_start(va
, callback
);
193 while ((f
= va_arg(va
, void (*)(void *))))
194 if (f
== t
->callback
)
199 last
->next
= t
->next
;
202 t
->next
= free_timeouts
;
212 delete_timeout(void (*callback
)(void *), void *arg
)
214 struct timeout
*t
, *tt
, *last
= NULL
;
216 for (t
= timeouts
; t
&& (tt
= t
->next
, 1); t
= tt
) {
218 (!callback
|| t
->callback
== callback
))
221 last
->next
= t
->next
;
224 t
->next
= free_timeouts
;
233 /* Define this to free all malloced memory.
234 * Normally we don't do this as the OS will do it for us at exit,
235 * but it's handy for debugging other leaks in valgrind. */
247 while (free_events
) {
248 e
= free_events
->next
;
257 while (free_timeouts
) {
258 t
= free_timeouts
->next
;
280 /* Run all timeouts first.
281 * When we have one that has not yet occured,
282 * calculate milliseconds until it does for use in poll. */
284 if (timercmp(&now
, &timeouts
->when
, >)) {
286 timeouts
= timeouts
->next
;
288 t
->next
= free_timeouts
;
292 timersub(&timeouts
->when
, &now
, &tv
);
293 if (tv
.tv_sec
> INT_MAX
/ 1000 ||
294 (tv
.tv_sec
== INT_MAX
/ 1000 &&
295 (tv
.tv_usec
+ 999) / 1000 > INT_MAX
% 1000))
298 msecs
= tv
.tv_sec
* 1000 +
299 (tv
.tv_usec
+ 999) / 1000;
301 /* No timeouts, so wait forever. */
304 /* Allocate memory for our pollfds as and when needed.
305 * We don't bother shrinking it. */
307 for (e
= events
; e
; e
= e
->next
)
309 if (msecs
== -1 && nfds
== 0) {
310 syslog(LOG_ERR
, "nothing to do");
313 if (nfds
> fds_len
) {
315 /* Allocate 5 more than we need for future use */
317 fds
= xmalloc(sizeof(*fds
) * fds_len
);
320 for (e
= events
; e
; e
= e
->next
) {
321 fds
[nfds
].fd
= e
->fd
;
322 fds
[nfds
].events
= POLLIN
;
323 fds
[nfds
].revents
= 0;
326 n
= poll(fds
, nfds
, msecs
);
328 if (errno
== EAGAIN
|| errno
== EINTR
) {
332 syslog(LOG_ERR
, "poll: %m");
336 /* Get the now time and process any triggered events. */
340 for (i
= 0; i
< nfds
; i
++) {
341 if (!(fds
[i
].revents
& (POLLIN
| POLLHUP
)))
343 for (e
= events
; e
; e
= e
->next
) {
344 if (e
->fd
== fds
[i
].fd
) {