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