1933707f3Ssthen /*
2933707f3Ssthen * mini_event.c - implementation of part of libevent api, portably.
3933707f3Ssthen *
4933707f3Ssthen * Copyright (c) 2007, NLnet Labs. All rights reserved.
5933707f3Ssthen *
6933707f3Ssthen * This software is open source.
7933707f3Ssthen *
8933707f3Ssthen * Redistribution and use in source and binary forms, with or without
9933707f3Ssthen * modification, are permitted provided that the following conditions
10933707f3Ssthen * are met:
11933707f3Ssthen *
12933707f3Ssthen * Redistributions of source code must retain the above copyright notice,
13933707f3Ssthen * this list of conditions and the following disclaimer.
14933707f3Ssthen *
15933707f3Ssthen * Redistributions in binary form must reproduce the above copyright notice,
16933707f3Ssthen * this list of conditions and the following disclaimer in the documentation
17933707f3Ssthen * and/or other materials provided with the distribution.
18933707f3Ssthen *
19933707f3Ssthen * Neither the name of the NLNET LABS nor the names of its contributors may
20933707f3Ssthen * be used to endorse or promote products derived from this software without
21933707f3Ssthen * specific prior written permission.
22933707f3Ssthen *
23933707f3Ssthen * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
245d76a658Ssthen * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
255d76a658Ssthen * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
265d76a658Ssthen * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
275d76a658Ssthen * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
285d76a658Ssthen * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
295d76a658Ssthen * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
305d76a658Ssthen * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
315d76a658Ssthen * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
325d76a658Ssthen * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
335d76a658Ssthen * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34933707f3Ssthen *
35933707f3Ssthen */
36933707f3Ssthen
37933707f3Ssthen /**
38933707f3Ssthen * \file
39933707f3Ssthen * fake libevent implementation. Less broad in functionality, and only
40933707f3Ssthen * supports select(2).
41933707f3Ssthen */
42933707f3Ssthen
43933707f3Ssthen #include "config.h"
44f6b99bafSsthen #include "util/mini_event.h"
45933707f3Ssthen #ifdef HAVE_TIME_H
46933707f3Ssthen #include <time.h>
47933707f3Ssthen #endif
48933707f3Ssthen #include <sys/time.h>
49933707f3Ssthen
50933707f3Ssthen #if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
51933707f3Ssthen #include <signal.h>
52933707f3Ssthen #include "util/fptr_wlist.h"
53933707f3Ssthen
54933707f3Ssthen /** compare events in tree, based on timevalue, ptr for uniqueness */
mini_ev_cmp(const void * a,const void * b)55933707f3Ssthen int mini_ev_cmp(const void* a, const void* b)
56933707f3Ssthen {
57933707f3Ssthen const struct event *e = (const struct event*)a;
58933707f3Ssthen const struct event *f = (const struct event*)b;
59933707f3Ssthen if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
60933707f3Ssthen return -1;
61933707f3Ssthen if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
62933707f3Ssthen return 1;
63933707f3Ssthen if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
64933707f3Ssthen return -1;
65933707f3Ssthen if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
66933707f3Ssthen return 1;
67933707f3Ssthen if(e < f)
68933707f3Ssthen return -1;
69933707f3Ssthen if(e > f)
70933707f3Ssthen return 1;
71933707f3Ssthen return 0;
72933707f3Ssthen }
73933707f3Ssthen
74933707f3Ssthen /** set time */
75933707f3Ssthen static int
settime(struct event_base * base)76933707f3Ssthen settime(struct event_base* base)
77933707f3Ssthen {
78933707f3Ssthen if(gettimeofday(base->time_tv, NULL) < 0) {
79933707f3Ssthen return -1;
80933707f3Ssthen }
81933707f3Ssthen #ifndef S_SPLINT_S
82229e174cSsthen *base->time_secs = (time_t)base->time_tv->tv_sec;
83933707f3Ssthen #endif
84933707f3Ssthen return 0;
85933707f3Ssthen }
86933707f3Ssthen
87933707f3Ssthen /** create event base */
event_init(time_t * time_secs,struct timeval * time_tv)88229e174cSsthen void *event_init(time_t* time_secs, struct timeval* time_tv)
89933707f3Ssthen {
90933707f3Ssthen struct event_base* base = (struct event_base*)malloc(
91933707f3Ssthen sizeof(struct event_base));
92933707f3Ssthen if(!base)
93933707f3Ssthen return NULL;
94933707f3Ssthen memset(base, 0, sizeof(*base));
95933707f3Ssthen base->time_secs = time_secs;
96933707f3Ssthen base->time_tv = time_tv;
97933707f3Ssthen if(settime(base) < 0) {
98933707f3Ssthen event_base_free(base);
99933707f3Ssthen return NULL;
100933707f3Ssthen }
101933707f3Ssthen base->times = rbtree_create(mini_ev_cmp);
102933707f3Ssthen if(!base->times) {
103933707f3Ssthen event_base_free(base);
104933707f3Ssthen return NULL;
105933707f3Ssthen }
106933707f3Ssthen base->capfd = MAX_FDS;
107933707f3Ssthen #ifdef FD_SETSIZE
108933707f3Ssthen if((int)FD_SETSIZE < base->capfd)
109933707f3Ssthen base->capfd = (int)FD_SETSIZE;
110933707f3Ssthen #endif
111933707f3Ssthen base->fds = (struct event**)calloc((size_t)base->capfd,
112933707f3Ssthen sizeof(struct event*));
113933707f3Ssthen if(!base->fds) {
114933707f3Ssthen event_base_free(base);
115933707f3Ssthen return NULL;
116933707f3Ssthen }
117933707f3Ssthen base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
118933707f3Ssthen if(!base->signals) {
119933707f3Ssthen event_base_free(base);
120933707f3Ssthen return NULL;
121933707f3Ssthen }
122933707f3Ssthen #ifndef S_SPLINT_S
123933707f3Ssthen FD_ZERO(&base->reads);
124933707f3Ssthen FD_ZERO(&base->writes);
125933707f3Ssthen #endif
126933707f3Ssthen return base;
127933707f3Ssthen }
128933707f3Ssthen
129933707f3Ssthen /** get version */
event_get_version(void)130933707f3Ssthen const char *event_get_version(void)
131933707f3Ssthen {
132933707f3Ssthen return "mini-event-"PACKAGE_VERSION;
133933707f3Ssthen }
134933707f3Ssthen
135933707f3Ssthen /** get polling method, select */
event_get_method(void)136933707f3Ssthen const char *event_get_method(void)
137933707f3Ssthen {
138933707f3Ssthen return "select";
139933707f3Ssthen }
140933707f3Ssthen
141933707f3Ssthen /** call timeouts handlers, and return how long to wait for next one or -1 */
handle_timeouts(struct event_base * base,struct timeval * now,struct timeval * wait)142933707f3Ssthen static void handle_timeouts(struct event_base* base, struct timeval* now,
143933707f3Ssthen struct timeval* wait)
144933707f3Ssthen {
145933707f3Ssthen struct event* p;
146933707f3Ssthen #ifndef S_SPLINT_S
147933707f3Ssthen wait->tv_sec = (time_t)-1;
148933707f3Ssthen #endif
149933707f3Ssthen
15077079be7Ssthen while((rbnode_type*)(p = (struct event*)rbtree_first(base->times))
151933707f3Ssthen !=RBTREE_NULL) {
152933707f3Ssthen #ifndef S_SPLINT_S
153933707f3Ssthen if(p->ev_timeout.tv_sec > now->tv_sec ||
154933707f3Ssthen (p->ev_timeout.tv_sec==now->tv_sec &&
155933707f3Ssthen p->ev_timeout.tv_usec > now->tv_usec)) {
156933707f3Ssthen /* there is a next larger timeout. wait for it */
157933707f3Ssthen wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
158933707f3Ssthen if(now->tv_usec > p->ev_timeout.tv_usec) {
159933707f3Ssthen wait->tv_sec--;
160933707f3Ssthen wait->tv_usec = 1000000 - (now->tv_usec -
161933707f3Ssthen p->ev_timeout.tv_usec);
162933707f3Ssthen } else {
163933707f3Ssthen wait->tv_usec = p->ev_timeout.tv_usec
164933707f3Ssthen - now->tv_usec;
165933707f3Ssthen }
166933707f3Ssthen return;
167933707f3Ssthen }
168933707f3Ssthen #endif
169933707f3Ssthen /* event times out, remove it */
170933707f3Ssthen (void)rbtree_delete(base->times, p);
171933707f3Ssthen p->ev_events &= ~EV_TIMEOUT;
172933707f3Ssthen fptr_ok(fptr_whitelist_event(p->ev_callback));
173933707f3Ssthen (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
174933707f3Ssthen }
175933707f3Ssthen }
176933707f3Ssthen
177933707f3Ssthen /** call select and callbacks for that */
handle_select(struct event_base * base,struct timeval * wait)178933707f3Ssthen static int handle_select(struct event_base* base, struct timeval* wait)
179933707f3Ssthen {
180933707f3Ssthen fd_set r, w;
181933707f3Ssthen int ret, i;
182933707f3Ssthen
183933707f3Ssthen #ifndef S_SPLINT_S
184933707f3Ssthen if(wait->tv_sec==(time_t)-1)
185933707f3Ssthen wait = NULL;
186933707f3Ssthen #endif
187933707f3Ssthen memmove(&r, &base->reads, sizeof(fd_set));
188933707f3Ssthen memmove(&w, &base->writes, sizeof(fd_set));
189933707f3Ssthen memmove(&base->ready, &base->content, sizeof(fd_set));
190933707f3Ssthen
191933707f3Ssthen if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
192933707f3Ssthen ret = errno;
193933707f3Ssthen if(settime(base) < 0)
194933707f3Ssthen return -1;
195933707f3Ssthen errno = ret;
196933707f3Ssthen if(ret == EAGAIN || ret == EINTR)
197933707f3Ssthen return 0;
198933707f3Ssthen return -1;
199933707f3Ssthen }
200933707f3Ssthen if(settime(base) < 0)
201933707f3Ssthen return -1;
202933707f3Ssthen
203933707f3Ssthen for(i=0; i<base->maxfd+1; i++) {
204933707f3Ssthen short bits = 0;
205933707f3Ssthen if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
206933707f3Ssthen continue;
207933707f3Ssthen }
208933707f3Ssthen if(FD_ISSET(i, &r)) {
209933707f3Ssthen bits |= EV_READ;
210933707f3Ssthen ret--;
211933707f3Ssthen }
212933707f3Ssthen if(FD_ISSET(i, &w)) {
213933707f3Ssthen bits |= EV_WRITE;
214933707f3Ssthen ret--;
215933707f3Ssthen }
216933707f3Ssthen bits &= base->fds[i]->ev_events;
217933707f3Ssthen if(bits) {
218933707f3Ssthen fptr_ok(fptr_whitelist_event(
219933707f3Ssthen base->fds[i]->ev_callback));
220933707f3Ssthen (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
221933707f3Ssthen bits, base->fds[i]->ev_arg);
222933707f3Ssthen if(ret==0)
223933707f3Ssthen break;
224933707f3Ssthen }
225933707f3Ssthen }
226933707f3Ssthen return 0;
227933707f3Ssthen }
228933707f3Ssthen
229933707f3Ssthen /** run select in a loop */
event_base_dispatch(struct event_base * base)230933707f3Ssthen int event_base_dispatch(struct event_base* base)
231933707f3Ssthen {
232933707f3Ssthen struct timeval wait;
233933707f3Ssthen if(settime(base) < 0)
234933707f3Ssthen return -1;
235933707f3Ssthen while(!base->need_to_exit)
236933707f3Ssthen {
237933707f3Ssthen /* see if timeouts need handling */
238933707f3Ssthen handle_timeouts(base, base->time_tv, &wait);
239933707f3Ssthen if(base->need_to_exit)
240933707f3Ssthen return 0;
241933707f3Ssthen /* do select */
242933707f3Ssthen if(handle_select(base, &wait) < 0) {
243933707f3Ssthen if(base->need_to_exit)
244933707f3Ssthen return 0;
245933707f3Ssthen return -1;
246933707f3Ssthen }
247933707f3Ssthen }
248933707f3Ssthen return 0;
249933707f3Ssthen }
250933707f3Ssthen
251933707f3Ssthen /** exit that loop */
event_base_loopexit(struct event_base * base,struct timeval * ATTR_UNUSED (tv))252933707f3Ssthen int event_base_loopexit(struct event_base* base,
253933707f3Ssthen struct timeval* ATTR_UNUSED(tv))
254933707f3Ssthen {
255933707f3Ssthen base->need_to_exit = 1;
256933707f3Ssthen return 0;
257933707f3Ssthen }
258933707f3Ssthen
259933707f3Ssthen /* free event base, free events yourself */
event_base_free(struct event_base * base)260933707f3Ssthen void event_base_free(struct event_base* base)
261933707f3Ssthen {
262933707f3Ssthen if(!base)
263933707f3Ssthen return;
264933707f3Ssthen free(base->times);
265933707f3Ssthen free(base->fds);
266933707f3Ssthen free(base->signals);
267933707f3Ssthen free(base);
268933707f3Ssthen }
269933707f3Ssthen
270933707f3Ssthen /** set content of event */
event_set(struct event * ev,int fd,short bits,void (* cb)(int,short,void *),void * arg)271933707f3Ssthen void event_set(struct event* ev, int fd, short bits,
272933707f3Ssthen void (*cb)(int, short, void *), void* arg)
273933707f3Ssthen {
274933707f3Ssthen ev->node.key = ev;
275933707f3Ssthen ev->ev_fd = fd;
276933707f3Ssthen ev->ev_events = bits;
277933707f3Ssthen ev->ev_callback = cb;
278933707f3Ssthen fptr_ok(fptr_whitelist_event(ev->ev_callback));
279933707f3Ssthen ev->ev_arg = arg;
280933707f3Ssthen ev->added = 0;
281933707f3Ssthen }
282933707f3Ssthen
283933707f3Ssthen /* add event to a base */
event_base_set(struct event_base * base,struct event * ev)284933707f3Ssthen int event_base_set(struct event_base* base, struct event* ev)
285933707f3Ssthen {
286933707f3Ssthen ev->ev_base = base;
287933707f3Ssthen ev->added = 0;
288933707f3Ssthen return 0;
289933707f3Ssthen }
290933707f3Ssthen
291933707f3Ssthen /* add event to make it active, you may not change it with event_set anymore */
event_add(struct event * ev,struct timeval * tv)292933707f3Ssthen int event_add(struct event* ev, struct timeval* tv)
293933707f3Ssthen {
294933707f3Ssthen if(ev->added)
295933707f3Ssthen event_del(ev);
296933707f3Ssthen if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
297933707f3Ssthen return -1;
298933707f3Ssthen if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
299933707f3Ssthen ev->ev_base->fds[ev->ev_fd] = ev;
300933707f3Ssthen if(ev->ev_events&EV_READ) {
301933707f3Ssthen FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
302933707f3Ssthen }
303933707f3Ssthen if(ev->ev_events&EV_WRITE) {
304933707f3Ssthen FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
305933707f3Ssthen }
306933707f3Ssthen FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
307933707f3Ssthen FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
308933707f3Ssthen if(ev->ev_fd > ev->ev_base->maxfd)
309933707f3Ssthen ev->ev_base->maxfd = ev->ev_fd;
310933707f3Ssthen }
311933707f3Ssthen if(tv && (ev->ev_events&EV_TIMEOUT)) {
312933707f3Ssthen #ifndef S_SPLINT_S
313933707f3Ssthen struct timeval *now = ev->ev_base->time_tv;
314933707f3Ssthen ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
315933707f3Ssthen ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
3168240c1b9Ssthen while(ev->ev_timeout.tv_usec >= 1000000) {
317933707f3Ssthen ev->ev_timeout.tv_usec -= 1000000;
318933707f3Ssthen ev->ev_timeout.tv_sec++;
319933707f3Ssthen }
320933707f3Ssthen #endif
321933707f3Ssthen (void)rbtree_insert(ev->ev_base->times, &ev->node);
322933707f3Ssthen }
323933707f3Ssthen ev->added = 1;
324933707f3Ssthen return 0;
325933707f3Ssthen }
326933707f3Ssthen
327933707f3Ssthen /* remove event, you may change it again */
event_del(struct event * ev)328933707f3Ssthen int event_del(struct event* ev)
329933707f3Ssthen {
330933707f3Ssthen if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
331933707f3Ssthen return -1;
332933707f3Ssthen if((ev->ev_events&EV_TIMEOUT))
333933707f3Ssthen (void)rbtree_delete(ev->ev_base->times, &ev->node);
334933707f3Ssthen if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
335933707f3Ssthen ev->ev_base->fds[ev->ev_fd] = NULL;
336933707f3Ssthen FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
337933707f3Ssthen FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
338933707f3Ssthen FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
339933707f3Ssthen FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
340*e21c60efSsthen if(ev->ev_fd == ev->ev_base->maxfd) {
341*e21c60efSsthen int i = ev->ev_base->maxfd - 1;
342*e21c60efSsthen for (; i > 3; i--) {
343*e21c60efSsthen if (NULL != ev->ev_base->fds[i]) {
344*e21c60efSsthen break;
345*e21c60efSsthen }
346*e21c60efSsthen }
347*e21c60efSsthen ev->ev_base->maxfd = i;
348*e21c60efSsthen }
349933707f3Ssthen }
350933707f3Ssthen ev->added = 0;
351933707f3Ssthen return 0;
352933707f3Ssthen }
353933707f3Ssthen
354933707f3Ssthen /** which base gets to handle signals */
355933707f3Ssthen static struct event_base* signal_base = NULL;
356933707f3Ssthen /** signal handler */
sigh(int sig)357933707f3Ssthen static RETSIGTYPE sigh(int sig)
358933707f3Ssthen {
359933707f3Ssthen struct event* ev;
360933707f3Ssthen if(!signal_base || sig < 0 || sig >= MAX_SIG)
361933707f3Ssthen return;
362933707f3Ssthen ev = signal_base->signals[sig];
363933707f3Ssthen if(!ev)
364933707f3Ssthen return;
365933707f3Ssthen fptr_ok(fptr_whitelist_event(ev->ev_callback));
366933707f3Ssthen (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
367933707f3Ssthen }
368933707f3Ssthen
369933707f3Ssthen /** install signal handler */
signal_add(struct event * ev,struct timeval * ATTR_UNUSED (tv))370933707f3Ssthen int signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv))
371933707f3Ssthen {
372933707f3Ssthen if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
373933707f3Ssthen return -1;
374933707f3Ssthen signal_base = ev->ev_base;
375933707f3Ssthen ev->ev_base->signals[ev->ev_fd] = ev;
376933707f3Ssthen ev->added = 1;
377933707f3Ssthen if(signal(ev->ev_fd, sigh) == SIG_ERR) {
378933707f3Ssthen return -1;
379933707f3Ssthen }
380933707f3Ssthen return 0;
381933707f3Ssthen }
382933707f3Ssthen
383933707f3Ssthen /** remove signal handler */
signal_del(struct event * ev)384933707f3Ssthen int signal_del(struct event* ev)
385933707f3Ssthen {
386933707f3Ssthen if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
387933707f3Ssthen return -1;
388933707f3Ssthen ev->ev_base->signals[ev->ev_fd] = NULL;
389933707f3Ssthen ev->added = 0;
390933707f3Ssthen return 0;
391933707f3Ssthen }
392933707f3Ssthen
393933707f3Ssthen #else /* USE_MINI_EVENT */
394933707f3Ssthen #ifndef USE_WINSOCK
mini_ev_cmp(const void * ATTR_UNUSED (a),const void * ATTR_UNUSED (b))395933707f3Ssthen int mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
396933707f3Ssthen {
397933707f3Ssthen return 0;
398933707f3Ssthen }
399933707f3Ssthen #endif /* not USE_WINSOCK */
400933707f3Ssthen #endif /* USE_MINI_EVENT */
401