xref: /openbsd-src/usr.sbin/nsd/mini_event.c (revision 3f21e8cc40aa89506971c1c4154dcba359c18fc3)
1 /*
2  * mini_event.c - implementation of part of libevent api, portably.
3  *
4  * Copyright (c) 2007, NLnet Labs. All rights reserved.
5  *
6  * This software is open source.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * Neither the name of the NLNET LABS nor the names of its contributors may
20  * be used to endorse or promote products derived from this software without
21  * specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  *
35  */
36 
37 /**
38  * \file
39  * fake libevent implementation. Less broad in functionality, and only
40  * supports select(2).
41  */
42 
43 #include "config.h"
44 #ifdef HAVE_TIME_H
45 #include <time.h>
46 #endif
47 #include <string.h>
48 #include <errno.h>
49 #include <sys/time.h>
50 
51 #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
52 #ifdef HAVE_WINSOCK2_H
53 #define FD_SET_T (u_int)
54 #else
55 #define FD_SET_T
56 #endif
57 
58 #include <signal.h>
59 #include "mini_event.h"
60 #include "util.h"
61 
62 /** compare events in tree, based on timevalue, ptr for uniqueness */
63 int
mini_ev_cmp(const void * a,const void * b)64 mini_ev_cmp(const void* a, const void* b)
65 {
66 	const struct event* e = (const struct event*)a;
67 	const struct event* f = (const struct event*)b;
68 	if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
69 		return -1;
70 	if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
71 		return 1;
72 	if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
73 		return -1;
74 	if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
75 		return 1;
76 	if(e < f)
77 		return -1;
78 	if(e > f)
79 		return 1;
80 	return 0;
81 }
82 
83 /** set time */
84 static int
settime(struct event_base * base)85 settime(struct event_base* base)
86 {
87 	if(gettimeofday(base->time_tv, NULL) < 0) {
88 		return -1;
89 	}
90 #ifndef S_SPLINT_S
91 	*base->time_secs = (time_t)base->time_tv->tv_sec;
92 #endif
93 	return 0;
94 }
95 
96 /** create event base */
97 void *
event_init(time_t * time_secs,struct timeval * time_tv)98 event_init(time_t* time_secs, struct timeval* time_tv)
99 {
100 	struct event_base* base = (struct event_base*)malloc(
101 		sizeof(struct event_base));
102 	if(!base)
103 		return NULL;
104 	memset(base, 0, sizeof(*base));
105 	base->region = region_create(xalloc, free);
106 	if(!base->region) {
107 		free(base);
108 		return NULL;
109 	}
110 	base->time_secs = time_secs;
111 	base->time_tv = time_tv;
112 	if(settime(base) < 0) {
113 		event_base_free(base);
114 		return NULL;
115 	}
116 	base->times = rbtree_create(base->region, mini_ev_cmp);
117 	if(!base->times) {
118 		event_base_free(base);
119 		return NULL;
120 	}
121 	base->capfd = MAX_FDS;
122 #ifdef FD_SETSIZE
123 	if((int)FD_SETSIZE < base->capfd)
124 		base->capfd = (int)FD_SETSIZE;
125 #endif
126 	base->fds = (struct event**)calloc((size_t)base->capfd,
127 		sizeof(struct event*));
128 	if(!base->fds) {
129 		event_base_free(base);
130 		return NULL;
131 	}
132 	base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
133 	if(!base->signals) {
134 		event_base_free(base);
135 		return NULL;
136 	}
137 #ifndef S_SPLINT_S
138 	FD_ZERO(&base->reads);
139 	FD_ZERO(&base->writes);
140 #endif
141 	return base;
142 }
143 
144 /** get version */
145 const char *
event_get_version(void)146 event_get_version(void)
147 {
148 	return "mini-event-"PACKAGE_VERSION;
149 }
150 
151 /** get polling method, select */
152 const char *
event_get_method(void)153 event_get_method(void)
154 {
155 	return "select";
156 }
157 
158 /** call timeouts handlers, and return how long to wait for next one or -1 */
159 static int
handle_timeouts(struct event_base * base,struct timeval * now,struct timeval * wait)160 handle_timeouts(struct event_base* base, struct timeval* now,
161 	struct timeval* wait)
162 {
163 	struct event* p;
164 	int tofired = 0;
165 #ifndef S_SPLINT_S
166 	wait->tv_sec = (time_t)-1;
167 #endif
168 
169 	while((rbnode_type*)(p = (struct event*)rbtree_first(base->times))
170 		!=RBTREE_NULL) {
171 #ifndef S_SPLINT_S
172 		if(p->ev_timeout.tv_sec > now->tv_sec ||
173 			(p->ev_timeout.tv_sec==now->tv_sec &&
174 		 	p->ev_timeout.tv_usec > now->tv_usec)) {
175 			/* there is a next larger timeout. wait for it */
176 			wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
177 			if(now->tv_usec > p->ev_timeout.tv_usec) {
178 				wait->tv_sec--;
179 				wait->tv_usec = 1000000 - (now->tv_usec -
180 					p->ev_timeout.tv_usec);
181 			} else {
182 				wait->tv_usec = p->ev_timeout.tv_usec
183 					- now->tv_usec;
184 			}
185 			return tofired;
186 		}
187 #endif
188 		/* event times out, remove it */
189 		tofired = 1;
190 		(void)rbtree_delete(base->times, p);
191 		p->ev_flags &= ~EV_TIMEOUT;
192 		(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
193 	}
194 	return tofired;
195 }
196 
197 /** call select and callbacks for that */
198 static int
handle_select(struct event_base * base,struct timeval * wait)199 handle_select(struct event_base* base, struct timeval* wait)
200 {
201 	fd_set r, w;
202 	int ret, i;
203 
204 #ifndef S_SPLINT_S
205 	if(wait->tv_sec==(time_t)-1)
206 		wait = NULL;
207 #endif
208 	memmove(&r, &base->reads, sizeof(fd_set));
209 	memmove(&w, &base->writes, sizeof(fd_set));
210 	memmove(&base->ready, &base->content, sizeof(fd_set));
211 
212 	if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
213 		ret = errno;
214 		if(settime(base) < 0)
215 			return -1;
216 		errno = ret;
217 		if(ret == EAGAIN || ret == EINTR)
218 			return 0;
219 		return -1;
220 	}
221 	if(settime(base) < 0)
222 		return -1;
223 
224 	for(i=0; i<base->maxfd+1; i++) {
225 		short bits = 0;
226 		if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
227 			continue;
228 		}
229 		if(FD_ISSET(i, &r)) {
230 			bits |= EV_READ;
231 			ret--;
232 		}
233 		if(FD_ISSET(i, &w)) {
234 			bits |= EV_WRITE;
235 			ret--;
236 		}
237 		bits &= base->fds[i]->ev_flags;
238 		if(bits) {
239 			(*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
240 				bits, base->fds[i]->ev_arg);
241 			if(ret==0)
242 				break;
243 		}
244 	}
245 	return 0;
246 }
247 
248 /** run select once */
249 int
event_base_loop(struct event_base * base,int flags)250 event_base_loop(struct event_base* base, int flags)
251 {
252 	struct timeval wait;
253 	if(!(flags & EVLOOP_ONCE))
254 		return event_base_dispatch(base);
255 	/* see if timeouts need handling */
256 	if(handle_timeouts(base, base->time_tv, &wait))
257 		return 0; /* there were timeouts, end of loop */
258 	if(base->need_to_exit)
259 		return 0;
260 	/* do select */
261 	if(handle_select(base, &wait) < 0) {
262 		if(base->need_to_exit)
263 			return 0;
264 		return -1;
265 	}
266 	return 0;
267 }
268 
269 /** run select in a loop */
270 int
event_base_dispatch(struct event_base * base)271 event_base_dispatch(struct event_base* base)
272 {
273 	struct timeval wait;
274 	if(settime(base) < 0)
275 		return -1;
276 	while(!base->need_to_exit)
277 	{
278 		/* see if timeouts need handling */
279 		(void)handle_timeouts(base, base->time_tv, &wait);
280 		if(base->need_to_exit)
281 			return 0;
282 		/* do select */
283 		if(handle_select(base, &wait) < 0) {
284 			if(base->need_to_exit)
285 				return 0;
286 			return -1;
287 		}
288 	}
289 	return 0;
290 }
291 
292 /** exit that loop */
293 int
event_base_loopexit(struct event_base * base,struct timeval * ATTR_UNUSED (tv))294 event_base_loopexit(struct event_base* base,
295 	struct timeval* ATTR_UNUSED(tv))
296 {
297 	base->need_to_exit = 1;
298 	return 0;
299 }
300 
event_base_loopbreak(struct event_base * base)301 int event_base_loopbreak(struct event_base * base)
302 {
303 	return event_base_loopexit(base, NULL);
304 }
305 
306 /* free event base, free events yourself */
307 void
event_base_free(struct event_base * base)308 event_base_free(struct event_base* base)
309 {
310 	if(!base)
311 		return;
312 	/* base->times is allocated in region and is freed with the region */
313 	if(base->fds)
314 		free(base->fds);
315 	if(base->signals)
316 		free(base->signals);
317 	region_destroy(base->region);
318 	free(base);
319 }
320 
321 /** set content of event */
322 void
event_set(struct event * ev,int fd,short bits,void (* cb)(int,short,void *),void * arg)323 event_set(struct event* ev, int fd, short bits,
324 	void (*cb)(int, short, void *), void* arg)
325 {
326 	ev->node.key = ev;
327 	ev->ev_fd = fd;
328 	ev->ev_flags = bits;
329 	ev->ev_callback = cb;
330 	ev->ev_arg = arg;
331 	ev->added = 0;
332 }
333 
334 /* add event to a base */
335 int
event_base_set(struct event_base * base,struct event * ev)336 event_base_set(struct event_base* base, struct event* ev)
337 {
338 	ev->ev_base = base;
339 	ev->added = 0;
340 	return 0;
341 }
342 
343 /* add event to make it active, you may not change it with event_set anymore */
344 int
event_add(struct event * ev,struct timeval * tv)345 event_add(struct event* ev, struct timeval* tv)
346 {
347 	if(ev->added)
348 		event_del(ev);
349 	if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
350 		return -1;
351 	if( (ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
352 		ev->ev_base->fds[ev->ev_fd] = ev;
353 		if(ev->ev_flags&EV_READ) {
354 			FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
355 		}
356 		if(ev->ev_flags&EV_WRITE) {
357 			FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
358 		}
359 		FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
360 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
361 		if(ev->ev_fd > ev->ev_base->maxfd)
362 			ev->ev_base->maxfd = ev->ev_fd;
363 	}
364 	if(tv && (ev->ev_flags&EV_TIMEOUT)) {
365 #ifndef S_SPLINT_S
366 		struct timeval* now = ev->ev_base->time_tv;
367 		ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
368 		ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
369 		while(ev->ev_timeout.tv_usec >= 1000000) {
370 			ev->ev_timeout.tv_usec -= 1000000;
371 			ev->ev_timeout.tv_sec++;
372 		}
373 #endif
374 		(void)rbtree_insert(ev->ev_base->times, &ev->node);
375 	}
376 	ev->added = 1;
377 	return 0;
378 }
379 
380 /* remove event, you may change it again */
381 int
event_del(struct event * ev)382 event_del(struct event* ev)
383 {
384 	if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
385 		return -1;
386 	if((ev->ev_flags&EV_TIMEOUT))
387 		(void)rbtree_delete(ev->ev_base->times, &ev->node);
388 	if((ev->ev_flags&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
389 		ev->ev_base->fds[ev->ev_fd] = NULL;
390 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
391 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
392 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
393 		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
394 	}
395 	ev->added = 0;
396 	return 0;
397 }
398 
399 /** which base gets to handle signals */
400 static struct event_base* signal_base = NULL;
401 
402 /** signal handler */
403 static RETSIGTYPE
sigh(int sig)404 sigh(int sig)
405 {
406 	struct event* ev;
407 	if(!signal_base || sig < 0 || sig >= MAX_SIG)
408 		return;
409 	ev = signal_base->signals[sig];
410 	if(!ev)
411 		return;
412 	(*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
413 }
414 
415 /** install signal handler */
416 int
signal_add(struct event * ev,struct timeval * ATTR_UNUSED (tv))417 signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv))
418 {
419 	struct sigaction action;
420 	if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
421 		return -1;
422 	signal_base = ev->ev_base;
423 	ev->ev_base->signals[ev->ev_fd] = ev;
424 	ev->added = 1;
425 	action.sa_handler = sigh;
426 	sigfillset(&action.sa_mask);
427 	action.sa_flags = 0;
428 	return sigaction(ev->ev_fd, &action, NULL);
429 }
430 
431 /** remove signal handler */
432 int
signal_del(struct event * ev)433 signal_del(struct event* ev)
434 {
435 	if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
436 		return -1;
437 	ev->ev_base->signals[ev->ev_fd] = NULL;
438 	ev->added = 0;
439 	return 0;
440 }
441 
442 #else /* USE_MINI_EVENT */
443 #ifndef USE_WINSOCK
444 int
mini_ev_cmp(const void * ATTR_UNUSED (a),const void * ATTR_UNUSED (b))445 mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
446 {
447 	return 0;
448 }
449 #endif /* not USE_WINSOCK */
450 #endif /* USE_MINI_EVENT */
451