Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2010 Roy Marples <roy (at) marples.name>
      4  * All rights reserved
      5 
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      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.
     14  *
     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
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/time.h>
     29 
     30 #include <errno.h>
     31 #include <limits.h>
     32 #include <poll.h>
     33 #include <stdarg.h>
     34 #include <stdlib.h>
     35 #include <syslog.h>
     36 
     37 #include "common.h"
     38 #include "eloop.h"
     39 
     40 static struct timeval now;
     41 
     42 static struct event {
     43 	int fd;
     44 	void (*callback)(void *);
     45 	void *arg;
     46 	struct event *next;
     47 } *events;
     48 static struct event *free_events;
     49 
     50 static struct timeout {
     51 	struct timeval when;
     52 	void (*callback)(void *);
     53 	void *arg;
     54 	int queue;
     55 	struct timeout *next;
     56 } *timeouts;
     57 static struct timeout *free_timeouts;
     58 
     59 static struct pollfd *fds;
     60 static size_t fds_len;
     61 
     62 void
     63 add_event(int fd, void (*callback)(void *), void *arg)
     64 {
     65 	struct event *e, *last = NULL;
     66 
     67 	/* We should only have one callback monitoring the fd */
     68 	for (e = events; e; e = e->next) {
     69 		if (e->fd == fd) {
     70 			e->callback = callback;
     71 			e->arg = arg;
     72 			return;
     73 		}
     74 		last = e;
     75 	}
     76 
     77 	/* Allocate a new event if no free ones already allocated */
     78 	if (free_events) {
     79 		e = free_events;
     80 		free_events = e->next;
     81 	} else
     82 		e = xmalloc(sizeof(*e));
     83 	e->fd = fd;
     84 	e->callback = callback;
     85 	e->arg = arg;
     86 	e->next = NULL;
     87 	if (last)
     88 		last->next = e;
     89 	else
     90 		events = e;
     91 }
     92 
     93 void
     94 delete_event(int fd)
     95 {
     96 	struct event *e, *last = NULL;
     97 
     98 	for (e = events; e; e = e->next) {
     99 		if (e->fd == fd) {
    100 			if (last)
    101 				last->next = e->next;
    102 			else
    103 				events = e->next;
    104 			e->next = free_events;
    105 			free_events = e;
    106 			break;
    107 		}
    108 		last = e;
    109 	}
    110 }
    111 
    112 void
    113 add_q_timeout_tv(int queue,
    114     const struct timeval *when, void (*callback)(void *), void *arg)
    115 {
    116 	struct timeval w;
    117 	struct timeout *t, *tt = NULL;
    118 
    119 	get_monotonic(&now);
    120 	timeradd(&now, when, &w);
    121 	/* Check for time_t overflow. */
    122 	if (timercmp(&w, &now, <)) {
    123 		errno = ERANGE;
    124 		return;
    125 	}
    126 
    127 	/* Remove existing timeout if present */
    128 	for (t = timeouts; t; t = t->next) {
    129 		if (t->callback == callback && t->arg == arg) {
    130 			if (tt)
    131 				tt->next = t->next;
    132 			else
    133 				timeouts = t->next;
    134 			break;
    135 		}
    136 		tt = t;
    137 	}
    138 
    139 	if (!t) {
    140 		/* No existing, so allocate or grab one from the free pool */
    141 		if (free_timeouts) {
    142 			t = free_timeouts;
    143 			free_timeouts = t->next;
    144 		} else
    145 			t = xmalloc(sizeof(*t));
    146 	}
    147 
    148 	t->when.tv_sec = w.tv_sec;
    149 	t->when.tv_usec = w.tv_usec;
    150 	t->callback = callback;
    151 	t->arg = arg;
    152 	t->queue = queue;
    153 
    154 	/* The timeout list should be in chronological order,
    155 	 * soonest first.
    156 	 * This is the easiest algorithm - check the head, then middle
    157 	 * and finally the end. */
    158 	if (!timeouts || timercmp(&t->when, &timeouts->when, <)) {
    159 		t->next = timeouts;
    160 		timeouts = t;
    161 		return;
    162 	}
    163 	for (tt = timeouts; tt->next; tt = tt->next)
    164 		if (timercmp(&t->when, &tt->next->when, <)) {
    165 			t->next = tt->next;
    166 			tt->next = t;
    167 			return;
    168 		}
    169 	tt->next = t;
    170 	t->next = NULL;
    171 }
    172 
    173 void
    174 add_q_timeout_sec(int queue, time_t when, void (*callback)(void *), void *arg)
    175 {
    176 	struct timeval tv;
    177 
    178 	tv.tv_sec = when;
    179 	tv.tv_usec = 0;
    180 	add_q_timeout_tv(queue, &tv, callback, arg);
    181 }
    182 
    183 /* This deletes all timeouts for the interface EXCEPT for ones with the
    184  * callbacks given. Handy for deleting everything apart from the expire
    185  * timeout. */
    186 static void
    187 v_delete_q_timeouts(int queue, void *arg, void (*callback)(void *), va_list v)
    188 {
    189 	struct timeout *t, *tt, *last = NULL;
    190 	va_list va;
    191 	void (*f)(void *);
    192 
    193 	for (t = timeouts; t && (tt = t->next, 1); t = tt) {
    194 		if (t->queue == queue && t->arg == arg &&
    195 		    t->callback != callback)
    196 		{
    197 			va_copy(va, v);
    198 			while ((f = va_arg(va, void (*)(void *))))
    199 				if (f == t->callback)
    200 					break;
    201 			va_end(va);
    202 			if (!f) {
    203 				if (last)
    204 					last->next = t->next;
    205 				else
    206 					timeouts = t->next;
    207 				t->next = free_timeouts;
    208 				free_timeouts = t;
    209 				continue;
    210 			}
    211 		}
    212 		last = t;
    213 	}
    214 }
    215 
    216 void
    217 delete_q_timeouts(int queue, void *arg, void (*callback)(void *), ...)
    218 {
    219 	va_list va;
    220 
    221 	va_start(va, callback);
    222 	v_delete_q_timeouts(queue, arg, callback, va);
    223 	va_end(va);
    224 }
    225 
    226 void
    227 delete_q_timeout(int queue, void (*callback)(void *), void *arg)
    228 {
    229 	struct timeout *t, *tt, *last = NULL;
    230 
    231 	for (t = timeouts; t && (tt = t->next, 1); t = tt) {
    232 		if (t->queue == queue && t->arg == arg &&
    233 		    (!callback || t->callback == callback))
    234 		{
    235 			if (last)
    236 				last->next = t->next;
    237 			else
    238 				timeouts = t->next;
    239 			t->next = free_timeouts;
    240 			free_timeouts = t;
    241 			continue;
    242 		}
    243 		last = t;
    244 	}
    245 }
    246 
    247 #ifdef DEBUG_MEMORY
    248 /* Define this to free all malloced memory.
    249  * Normally we don't do this as the OS will do it for us at exit,
    250  * but it's handy for debugging other leaks in valgrind. */
    251 static void
    252 cleanup(void)
    253 {
    254 	struct event *e;
    255 	struct timeout *t;
    256 
    257 	while (events) {
    258 		e = events->next;
    259 		free(events);
    260 		events = e;
    261 	}
    262 	while (free_events) {
    263 		e = free_events->next;
    264 		free(free_events);
    265 		free_events = e;
    266 	}
    267 	while (timeouts) {
    268 		t = timeouts->next;
    269 		free(timeouts);
    270 		timeouts = t;
    271 	}
    272 	while (free_timeouts) {
    273 		t = free_timeouts->next;
    274 		free(free_timeouts);
    275 		free_timeouts = t;
    276 	}
    277 	free(fds);
    278 }
    279 #endif
    280 
    281 _noreturn void
    282 start_eloop(void)
    283 {
    284 	int msecs, n;
    285 	nfds_t nfds, i;
    286 	struct event *e;
    287 	struct timeout *t;
    288 	struct timeval tv;
    289 
    290 #ifdef DEBUG_MEMORY
    291 	atexit(cleanup);
    292 #endif
    293 
    294 	for (;;) {
    295 		/* Run all timeouts first.
    296 		 * When we have one that has not yet occured,
    297 		 * calculate milliseconds until it does for use in poll. */
    298 		if (timeouts) {
    299 			if (timercmp(&now, &timeouts->when, >)) {
    300 				t = timeouts;
    301 				timeouts = timeouts->next;
    302 				t->callback(t->arg);
    303 				t->next = free_timeouts;
    304 				free_timeouts = t;
    305 				continue;
    306 			}
    307 			timersub(&timeouts->when, &now, &tv);
    308 			if (tv.tv_sec > INT_MAX / 1000 ||
    309 			    (tv.tv_sec == INT_MAX / 1000 &&
    310 				(tv.tv_usec + 999) / 1000 > INT_MAX % 1000))
    311 				msecs = INT_MAX;
    312 			else
    313 				msecs = tv.tv_sec * 1000 +
    314 				    (tv.tv_usec + 999) / 1000;
    315 		} else
    316 			/* No timeouts, so wait forever. */
    317 			msecs = -1;
    318 
    319 		/* Allocate memory for our pollfds as and when needed.
    320 		 * We don't bother shrinking it. */
    321 		nfds = 0;
    322 		for (e = events; e; e = e->next)
    323 			nfds++;
    324 		if (msecs == -1 && nfds == 0) {
    325 			syslog(LOG_ERR, "nothing to do");
    326 			exit(EXIT_FAILURE);
    327 		}
    328 		if (nfds > fds_len) {
    329 			free(fds);
    330 			/* Allocate 5 more than we need for future use */
    331 			fds_len = nfds + 5;
    332 			fds = xmalloc(sizeof(*fds) * fds_len);
    333 		}
    334 		nfds = 0;
    335 		for (e = events; e; e = e->next) {
    336 			fds[nfds].fd = e->fd;
    337 			fds[nfds].events = POLLIN;
    338 			fds[nfds].revents = 0;
    339 			nfds++;
    340 		}
    341 		n = poll(fds, nfds, msecs);
    342 		if (n == -1) {
    343 			if (errno == EAGAIN || errno == EINTR) {
    344 				get_monotonic(&now);
    345 				continue;
    346 			}
    347 			syslog(LOG_ERR, "poll: %m");
    348 			exit(EXIT_FAILURE);
    349 		}
    350 
    351 		/* Get the now time and process any triggered events. */
    352 		get_monotonic(&now);
    353 		if (n == 0)
    354 			continue;
    355 		for (i = 0; i < nfds; i++) {
    356 			if (!(fds[i].revents & (POLLIN | POLLHUP)))
    357 				continue;
    358 			for (e = events; e; e = e->next) {
    359 				if (e->fd == fds[i].fd) {
    360 					e->callback(e->arg);
    361 					break;
    362 				}
    363 			}
    364 		}
    365 	}
    366 }
    367