2 * dhcpcd - DHCP client daemon
3 * Copyright (c) 2006-2015 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
45 /* Handy function to get the time.
46 * We only care about time advancements, not the actual time itself
47 * Which is why we use CLOCK_MONOTONIC, but it is not available on all
50 #define NO_MONOTONIC "host does not support a monotonic clock - timing can skew"
52 get_monotonic(struct timespec *ts)
55 #if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
56 return clock_gettime(CLOCK_MONOTONIC, ts);
58 #elif defined(__APPLE__)
59 /* We can use mach kernel functions here.
60 * This is crap though - why can't they implement clock_gettime?*/
61 static struct mach_timebase_info info = { 0, 0 };
62 static double factor = 0.0;
66 if (!posix_clock_set) {
67 if (mach_timebase_info(&info) == KERN_SUCCESS) {
68 factor = (double)info.numer / (double)info.denom;
69 clock_monotonic = posix_clock_set = 1;
72 if (clock_monotonic) {
73 nano = mach_absolute_time();
74 if ((info.denom != 1 || info.numer != 1) && factor != 0.0)
76 ts->tv_sec = nano / NSEC_PER_SEC;
77 ts->tv_nsec = nano % NSEC_PER_SEC;
78 if (ts->tv_nsec < 0) {
80 ts->tv_nsec += NSEC_PER_SEC;
87 /* Something above failed, so fall back to gettimeofday */
88 if (!posix_clock_set) {
89 syslog(LOG_WARNING, NO_MONOTONIC);
95 if (gettimeofday(&tv, NULL) == 0) {
96 TIMEVAL_TO_TIMESPEC(&tv, ts);
105 eloop_event_setup_fds(ELOOP_CTX *ctx)
107 struct eloop_event *e;
111 TAILQ_FOREACH(e, &ctx->events, next) {
112 ctx->fds[i].fd = e->fd;
113 ctx->fds[i].events = 0;
115 ctx->fds[i].events |= POLLIN;
117 ctx->fds[i].events |= POLLOUT;
118 ctx->fds[i].revents = 0;
119 e->pollfd = &ctx->fds[i];
125 eloop_event_add(ELOOP_CTX *ctx, int fd,
126 void (*read_cb)(void *), void *read_cb_arg,
127 void (*write_cb)(void *), void *write_cb_arg)
129 struct eloop_event *e;
132 /* We should only have one callback monitoring the fd */
133 TAILQ_FOREACH(e, &ctx->events, next) {
136 e->read_cb = read_cb;
137 e->read_cb_arg = read_cb_arg;
140 e->write_cb = write_cb;
141 e->write_cb_arg = write_cb_arg;
143 eloop_event_setup_fds(ctx);
148 /* Allocate a new event if no free ones already allocated */
149 if ((e = TAILQ_FIRST(&ctx->free_events))) {
150 TAILQ_REMOVE(&ctx->free_events, e, next);
152 e = malloc(sizeof(*e));
154 syslog(LOG_ERR, "%s: %m", __func__);
159 /* Ensure we can actually listen to it */
161 if (ctx->events_len > ctx->fds_len) {
163 nfds = malloc(sizeof(*ctx->fds) * (ctx->fds_len + 5));
165 syslog(LOG_ERR, "%s: %m", __func__);
167 TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
175 /* Now populate the structure and add it to the list */
177 e->read_cb = read_cb;
178 e->read_cb_arg = read_cb_arg;
179 e->write_cb = write_cb;
180 e->write_cb_arg = write_cb_arg;
181 /* The order of events should not matter.
182 * However, some PPP servers love to close the link right after
183 * sending their final message. So to ensure dhcpcd processes this
184 * message (which is likely to be that the DHCP addresses are wrong)
185 * we insert new events at the queue head as the link fd will be
186 * the first event added. */
187 TAILQ_INSERT_HEAD(&ctx->events, e, next);
188 eloop_event_setup_fds(ctx);
193 eloop_event_delete(ELOOP_CTX *ctx, int fd, void (*callback)(void *), void *arg,
196 struct eloop_event *e;
198 TAILQ_FOREACH(e, &ctx->events, next) {
200 e->read_cb == callback || (arg && e->read_cb_arg == arg))
204 e->write_cb_arg = NULL;
206 TAILQ_REMOVE(&ctx->events, e, next);
207 TAILQ_INSERT_TAIL(&ctx->free_events, e, next);
210 eloop_event_setup_fds(ctx);
217 eloop_q_timeout_add_tv(ELOOP_CTX *ctx, int queue,
218 const struct timespec *when, void (*callback)(void *), void *arg)
222 struct eloop_timeout *t, *tt = NULL;
225 timespecadd(&now, when, &w);
226 /* Check for time_t overflow. */
227 if (timespeccmp(&w, &now, <)) {
232 /* Remove existing timeout if present */
233 TAILQ_FOREACH(t, &ctx->timeouts, next) {
234 if (t->callback == callback && t->arg == arg) {
235 TAILQ_REMOVE(&ctx->timeouts, t, next);
241 /* No existing, so allocate or grab one from the free pool */
242 if ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
243 TAILQ_REMOVE(&ctx->free_timeouts, t, next);
245 t = malloc(sizeof(*t));
247 syslog(LOG_ERR, "%s: %m", __func__);
254 t->callback = callback;
258 /* The timeout list should be in chronological order,
260 TAILQ_FOREACH(tt, &ctx->timeouts, next) {
261 if (timespeccmp(&t->when, &tt->when, <)) {
262 TAILQ_INSERT_BEFORE(tt, t, next);
266 TAILQ_INSERT_TAIL(&ctx->timeouts, t, next);
271 eloop_q_timeout_add_sec(ELOOP_CTX *ctx, int queue, time_t when,
272 void (*callback)(void *), void *arg)
278 return eloop_q_timeout_add_tv(ctx, queue, &tv, callback, arg);
282 eloop_q_timeout_add_msec(ELOOP_CTX *ctx, int queue, suseconds_t when,
283 void (*callback)(void *), void *arg)
288 tv.tv_nsec = when * MSEC_PER_NSEC;
290 return eloop_q_timeout_add_tv(ctx, queue, &tv, callback, arg);
294 eloop_timeout_add_now(ELOOP_CTX *ctx,
295 void (*callback)(void *), void *arg)
298 if (ctx->timeout0 != NULL) {
299 syslog(LOG_WARNING, "%s: timeout0 already set", __func__);
300 return eloop_q_timeout_add_sec(ctx, 0, 0, callback, arg);
303 ctx->timeout0 = callback;
304 ctx->timeout0_arg = arg;
309 eloop_q_timeout_delete(ELOOP_CTX *ctx, int queue,
310 void (*callback)(void *), void *arg)
312 struct eloop_timeout *t, *tt;
314 TAILQ_FOREACH_SAFE(t, &ctx->timeouts, next, tt) {
315 if ((queue == 0 || t->queue == queue) &&
317 (!callback || t->callback == callback))
319 TAILQ_REMOVE(&ctx->timeouts, t, next);
320 TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
326 eloop_exit(ELOOP_CTX *ctx, int code)
329 ctx->exitcode = code;
338 ctx = calloc(1, sizeof(*ctx));
340 TAILQ_INIT(&ctx->events);
341 TAILQ_INIT(&ctx->free_events);
342 TAILQ_INIT(&ctx->timeouts);
343 TAILQ_INIT(&ctx->free_timeouts);
344 ctx->exitcode = EXIT_FAILURE;
350 void eloop_free(ELOOP_CTX *ctx)
352 struct eloop_event *e;
353 struct eloop_timeout *t;
358 while ((e = TAILQ_FIRST(&ctx->events))) {
359 TAILQ_REMOVE(&ctx->events, e, next);
362 while ((e = TAILQ_FIRST(&ctx->free_events))) {
363 TAILQ_REMOVE(&ctx->free_events, e, next);
366 while ((t = TAILQ_FIRST(&ctx->timeouts))) {
367 TAILQ_REMOVE(&ctx->timeouts, t, next);
370 while ((t = TAILQ_FIRST(&ctx->free_timeouts))) {
371 TAILQ_REMOVE(&ctx->free_timeouts, t, next);
379 eloop_start(ELOOP_CTX *ctx)
382 struct eloop_event *e;
383 struct eloop_timeout *t;
384 struct timespec now, ts, tv, *tsp;
392 /* Run all timeouts first */
395 ctx->timeout0 = NULL;
396 t0(ctx->timeout0_arg);
399 if ((t = TAILQ_FIRST(&ctx->timeouts))) {
401 if (timespeccmp(&now, &t->when, >)) {
402 TAILQ_REMOVE(&ctx->timeouts, t, next);
404 TAILQ_INSERT_TAIL(&ctx->free_timeouts, t, next);
407 timespecsub(&t->when, &now, &tv);
410 /* No timeouts, so wait forever */
413 if (tsp == NULL && ctx->events_len == 0) {
414 syslog(LOG_ERR, "nothing to do");
420 else if (tsp->tv_sec > INT_MAX / 1000 ||
421 (tsp->tv_sec == INT_MAX / 1000 &&
422 (tsp->tv_nsec + 999999) / 1000000 > INT_MAX % 1000000))
425 timeout = (int)(tsp->tv_sec * 1000 +
426 (tsp->tv_nsec + 999999) / 1000000);
427 n = poll(ctx->fds, ctx->events_len, timeout);
431 syslog(LOG_ERR, "poll: %m");
435 /* Process any triggered events. */
437 TAILQ_FOREACH(e, &ctx->events, next) {
438 if (e->pollfd->revents & POLLOUT &&
441 e->write_cb(e->write_cb_arg);
442 /* We need to break here as the
443 * callback could destroy the next
447 if (e->pollfd->revents) {
448 e->read_cb(e->read_cb_arg);
449 /* We need to break here as the
450 * callback could destroy the next
458 return ctx->exitcode;