1238106Sdes/*
2238106Sdes * mini_event.c - implementation of part of libevent api, portably.
3238106Sdes *
4238106Sdes * Copyright (c) 2007, NLnet Labs. All rights reserved.
5238106Sdes *
6238106Sdes * This software is open source.
7238106Sdes *
8238106Sdes * Redistribution and use in source and binary forms, with or without
9238106Sdes * modification, are permitted provided that the following conditions
10238106Sdes * are met:
11238106Sdes *
12238106Sdes * Redistributions of source code must retain the above copyright notice,
13238106Sdes * this list of conditions and the following disclaimer.
14238106Sdes *
15238106Sdes * Redistributions in binary form must reproduce the above copyright notice,
16238106Sdes * this list of conditions and the following disclaimer in the documentation
17238106Sdes * and/or other materials provided with the distribution.
18238106Sdes *
19238106Sdes * Neither the name of the NLNET LABS nor the names of its contributors may
20238106Sdes * be used to endorse or promote products derived from this software without
21238106Sdes * specific prior written permission.
22238106Sdes *
23238106Sdes * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24269257Sdes * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25269257Sdes * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26269257Sdes * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27269257Sdes * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28269257Sdes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29269257Sdes * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30269257Sdes * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31269257Sdes * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32269257Sdes * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33269257Sdes * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34238106Sdes *
35238106Sdes */
36238106Sdes
37238106Sdes/**
38238106Sdes * \file
39238106Sdes * fake libevent implementation. Less broad in functionality, and only
40238106Sdes * supports select(2).
41238106Sdes */
42238106Sdes
43238106Sdes#include "config.h"
44238106Sdes#ifdef HAVE_TIME_H
45238106Sdes#include <time.h>
46238106Sdes#endif
47238106Sdes#include <sys/time.h>
48238106Sdes
49238106Sdes#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
50238106Sdes#include <signal.h>
51238106Sdes#include "util/mini_event.h"
52238106Sdes#include "util/fptr_wlist.h"
53238106Sdes
54238106Sdes/** compare events in tree, based on timevalue, ptr for uniqueness */
55238106Sdesint mini_ev_cmp(const void* a, const void* b)
56238106Sdes{
57238106Sdes	const struct event *e = (const struct event*)a;
58238106Sdes	const struct event *f = (const struct event*)b;
59238106Sdes	if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
60238106Sdes		return -1;
61238106Sdes	if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
62238106Sdes		return 1;
63238106Sdes	if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
64238106Sdes		return -1;
65238106Sdes	if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
66238106Sdes		return 1;
67238106Sdes	if(e < f)
68238106Sdes		return -1;
69238106Sdes	if(e > f)
70238106Sdes		return 1;
71238106Sdes	return 0;
72238106Sdes}
73238106Sdes
74238106Sdes/** set time */
75238106Sdesstatic int
76238106Sdessettime(struct event_base* base)
77238106Sdes{
78238106Sdes	if(gettimeofday(base->time_tv, NULL) < 0) {
79238106Sdes		return -1;
80238106Sdes	}
81238106Sdes#ifndef S_SPLINT_S
82269257Sdes	*base->time_secs = (time_t)base->time_tv->tv_sec;
83238106Sdes#endif
84238106Sdes	return 0;
85238106Sdes}
86238106Sdes
87238106Sdes/** create event base */
88269257Sdesvoid *event_init(time_t* time_secs, struct timeval* time_tv)
89238106Sdes{
90238106Sdes	struct event_base* base = (struct event_base*)malloc(
91238106Sdes		sizeof(struct event_base));
92238106Sdes	if(!base)
93238106Sdes		return NULL;
94238106Sdes	memset(base, 0, sizeof(*base));
95238106Sdes	base->time_secs = time_secs;
96238106Sdes	base->time_tv = time_tv;
97238106Sdes	if(settime(base) < 0) {
98238106Sdes		event_base_free(base);
99238106Sdes		return NULL;
100238106Sdes	}
101238106Sdes	base->times = rbtree_create(mini_ev_cmp);
102238106Sdes	if(!base->times) {
103238106Sdes		event_base_free(base);
104238106Sdes		return NULL;
105238106Sdes	}
106238106Sdes	base->capfd = MAX_FDS;
107238106Sdes#ifdef FD_SETSIZE
108238106Sdes	if((int)FD_SETSIZE < base->capfd)
109238106Sdes		base->capfd = (int)FD_SETSIZE;
110238106Sdes#endif
111238106Sdes	base->fds = (struct event**)calloc((size_t)base->capfd,
112238106Sdes		sizeof(struct event*));
113238106Sdes	if(!base->fds) {
114238106Sdes		event_base_free(base);
115238106Sdes		return NULL;
116238106Sdes	}
117238106Sdes	base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
118238106Sdes	if(!base->signals) {
119238106Sdes		event_base_free(base);
120238106Sdes		return NULL;
121238106Sdes	}
122238106Sdes#ifndef S_SPLINT_S
123238106Sdes	FD_ZERO(&base->reads);
124238106Sdes	FD_ZERO(&base->writes);
125238106Sdes#endif
126238106Sdes	return base;
127238106Sdes}
128238106Sdes
129238106Sdes/** get version */
130238106Sdesconst char *event_get_version(void)
131238106Sdes{
132238106Sdes	return "mini-event-"PACKAGE_VERSION;
133238106Sdes}
134238106Sdes
135238106Sdes/** get polling method, select */
136238106Sdesconst char *event_get_method(void)
137238106Sdes{
138238106Sdes	return "select";
139238106Sdes}
140238106Sdes
141238106Sdes/** call timeouts handlers, and return how long to wait for next one or -1 */
142238106Sdesstatic void handle_timeouts(struct event_base* base, struct timeval* now,
143238106Sdes	struct timeval* wait)
144238106Sdes{
145238106Sdes	struct event* p;
146238106Sdes#ifndef S_SPLINT_S
147238106Sdes	wait->tv_sec = (time_t)-1;
148238106Sdes#endif
149238106Sdes
150238106Sdes	while((rbnode_t*)(p = (struct event*)rbtree_first(base->times))
151238106Sdes		!=RBTREE_NULL) {
152238106Sdes#ifndef S_SPLINT_S
153238106Sdes		if(p->ev_timeout.tv_sec > now->tv_sec ||
154238106Sdes			(p->ev_timeout.tv_sec==now->tv_sec &&
155238106Sdes		 	p->ev_timeout.tv_usec > now->tv_usec)) {
156238106Sdes			/* there is a next larger timeout. wait for it */
157238106Sdes			wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
158238106Sdes			if(now->tv_usec > p->ev_timeout.tv_usec) {
159238106Sdes				wait->tv_sec--;
160238106Sdes				wait->tv_usec = 1000000 - (now->tv_usec -
161238106Sdes					p->ev_timeout.tv_usec);
162238106Sdes			} else {
163238106Sdes				wait->tv_usec = p->ev_timeout.tv_usec
164238106Sdes					- now->tv_usec;
165238106Sdes			}
166238106Sdes			return;
167238106Sdes		}
168238106Sdes#endif
169238106Sdes		/* event times out, remove it */
170238106Sdes		(void)rbtree_delete(base->times, p);
171238106Sdes		p->ev_events &= ~EV_TIMEOUT;
172238106Sdes		fptr_ok(fptr_whitelist_event(p->ev_callback));
173238106Sdes		(*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
174238106Sdes	}
175238106Sdes}
176238106Sdes
177238106Sdes/** call select and callbacks for that */
178238106Sdesstatic int handle_select(struct event_base* base, struct timeval* wait)
179238106Sdes{
180238106Sdes	fd_set r, w;
181238106Sdes	int ret, i;
182238106Sdes
183238106Sdes#ifndef S_SPLINT_S
184238106Sdes	if(wait->tv_sec==(time_t)-1)
185238106Sdes		wait = NULL;
186238106Sdes#endif
187238106Sdes	memmove(&r, &base->reads, sizeof(fd_set));
188238106Sdes	memmove(&w, &base->writes, sizeof(fd_set));
189238106Sdes	memmove(&base->ready, &base->content, sizeof(fd_set));
190238106Sdes
191238106Sdes	if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
192238106Sdes		ret = errno;
193238106Sdes		if(settime(base) < 0)
194238106Sdes			return -1;
195238106Sdes		errno = ret;
196238106Sdes		if(ret == EAGAIN || ret == EINTR)
197238106Sdes			return 0;
198238106Sdes		return -1;
199238106Sdes	}
200238106Sdes	if(settime(base) < 0)
201238106Sdes		return -1;
202238106Sdes
203238106Sdes	for(i=0; i<base->maxfd+1; i++) {
204238106Sdes		short bits = 0;
205238106Sdes		if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
206238106Sdes			continue;
207238106Sdes		}
208238106Sdes		if(FD_ISSET(i, &r)) {
209238106Sdes			bits |= EV_READ;
210238106Sdes			ret--;
211238106Sdes		}
212238106Sdes		if(FD_ISSET(i, &w)) {
213238106Sdes			bits |= EV_WRITE;
214238106Sdes			ret--;
215238106Sdes		}
216238106Sdes		bits &= base->fds[i]->ev_events;
217238106Sdes		if(bits) {
218238106Sdes			fptr_ok(fptr_whitelist_event(
219238106Sdes				base->fds[i]->ev_callback));
220238106Sdes			(*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
221238106Sdes				bits, base->fds[i]->ev_arg);
222238106Sdes			if(ret==0)
223238106Sdes				break;
224238106Sdes		}
225238106Sdes	}
226238106Sdes	return 0;
227238106Sdes}
228238106Sdes
229238106Sdes/** run select in a loop */
230238106Sdesint event_base_dispatch(struct event_base* base)
231238106Sdes{
232238106Sdes	struct timeval wait;
233238106Sdes	if(settime(base) < 0)
234238106Sdes		return -1;
235238106Sdes	while(!base->need_to_exit)
236238106Sdes	{
237238106Sdes		/* see if timeouts need handling */
238238106Sdes		handle_timeouts(base, base->time_tv, &wait);
239238106Sdes		if(base->need_to_exit)
240238106Sdes			return 0;
241238106Sdes		/* do select */
242238106Sdes		if(handle_select(base, &wait) < 0) {
243238106Sdes			if(base->need_to_exit)
244238106Sdes				return 0;
245238106Sdes			return -1;
246238106Sdes		}
247238106Sdes	}
248238106Sdes	return 0;
249238106Sdes}
250238106Sdes
251238106Sdes/** exit that loop */
252238106Sdesint event_base_loopexit(struct event_base* base,
253238106Sdes	struct timeval* ATTR_UNUSED(tv))
254238106Sdes{
255238106Sdes	base->need_to_exit = 1;
256238106Sdes	return 0;
257238106Sdes}
258238106Sdes
259238106Sdes/* free event base, free events yourself */
260238106Sdesvoid event_base_free(struct event_base* base)
261238106Sdes{
262238106Sdes	if(!base)
263238106Sdes		return;
264238106Sdes	if(base->times)
265238106Sdes		free(base->times);
266238106Sdes	if(base->fds)
267238106Sdes		free(base->fds);
268238106Sdes	if(base->signals)
269238106Sdes		free(base->signals);
270238106Sdes	free(base);
271238106Sdes}
272238106Sdes
273238106Sdes/** set content of event */
274238106Sdesvoid event_set(struct event* ev, int fd, short bits,
275238106Sdes	void (*cb)(int, short, void *), void* arg)
276238106Sdes{
277238106Sdes	ev->node.key = ev;
278238106Sdes	ev->ev_fd = fd;
279238106Sdes	ev->ev_events = bits;
280238106Sdes	ev->ev_callback = cb;
281238106Sdes	fptr_ok(fptr_whitelist_event(ev->ev_callback));
282238106Sdes	ev->ev_arg = arg;
283238106Sdes	ev->added = 0;
284238106Sdes}
285238106Sdes
286238106Sdes/* add event to a base */
287238106Sdesint event_base_set(struct event_base* base, struct event* ev)
288238106Sdes{
289238106Sdes	ev->ev_base = base;
290238106Sdes	ev->added = 0;
291238106Sdes	return 0;
292238106Sdes}
293238106Sdes
294238106Sdes/* add event to make it active, you may not change it with event_set anymore */
295238106Sdesint event_add(struct event* ev, struct timeval* tv)
296238106Sdes{
297238106Sdes	if(ev->added)
298238106Sdes		event_del(ev);
299238106Sdes	if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
300238106Sdes		return -1;
301238106Sdes	if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
302238106Sdes		ev->ev_base->fds[ev->ev_fd] = ev;
303238106Sdes		if(ev->ev_events&EV_READ) {
304238106Sdes			FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
305238106Sdes		}
306238106Sdes		if(ev->ev_events&EV_WRITE) {
307238106Sdes			FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
308238106Sdes		}
309238106Sdes		FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
310238106Sdes		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
311238106Sdes		if(ev->ev_fd > ev->ev_base->maxfd)
312238106Sdes			ev->ev_base->maxfd = ev->ev_fd;
313238106Sdes	}
314238106Sdes	if(tv && (ev->ev_events&EV_TIMEOUT)) {
315238106Sdes#ifndef S_SPLINT_S
316238106Sdes		struct timeval *now = ev->ev_base->time_tv;
317238106Sdes		ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
318238106Sdes		ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
319238106Sdes		while(ev->ev_timeout.tv_usec > 1000000) {
320238106Sdes			ev->ev_timeout.tv_usec -= 1000000;
321238106Sdes			ev->ev_timeout.tv_sec++;
322238106Sdes		}
323238106Sdes#endif
324238106Sdes		(void)rbtree_insert(ev->ev_base->times, &ev->node);
325238106Sdes	}
326238106Sdes	ev->added = 1;
327238106Sdes	return 0;
328238106Sdes}
329238106Sdes
330238106Sdes/* remove event, you may change it again */
331238106Sdesint event_del(struct event* ev)
332238106Sdes{
333238106Sdes	if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
334238106Sdes		return -1;
335238106Sdes	if((ev->ev_events&EV_TIMEOUT))
336238106Sdes		(void)rbtree_delete(ev->ev_base->times, &ev->node);
337238106Sdes	if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
338238106Sdes		ev->ev_base->fds[ev->ev_fd] = NULL;
339238106Sdes		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
340238106Sdes		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
341238106Sdes		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
342238106Sdes		FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
343238106Sdes	}
344238106Sdes	ev->added = 0;
345238106Sdes	return 0;
346238106Sdes}
347238106Sdes
348238106Sdes/** which base gets to handle signals */
349238106Sdesstatic struct event_base* signal_base = NULL;
350238106Sdes/** signal handler */
351238106Sdesstatic RETSIGTYPE sigh(int sig)
352238106Sdes{
353238106Sdes	struct event* ev;
354238106Sdes	if(!signal_base || sig < 0 || sig >= MAX_SIG)
355238106Sdes		return;
356238106Sdes	ev = signal_base->signals[sig];
357238106Sdes	if(!ev)
358238106Sdes		return;
359238106Sdes	fptr_ok(fptr_whitelist_event(ev->ev_callback));
360238106Sdes	(*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
361238106Sdes}
362238106Sdes
363238106Sdes/** install signal handler */
364238106Sdesint signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv))
365238106Sdes{
366238106Sdes	if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
367238106Sdes		return -1;
368238106Sdes	signal_base = ev->ev_base;
369238106Sdes	ev->ev_base->signals[ev->ev_fd] = ev;
370238106Sdes	ev->added = 1;
371238106Sdes	if(signal(ev->ev_fd, sigh) == SIG_ERR) {
372238106Sdes		return -1;
373238106Sdes	}
374238106Sdes	return 0;
375238106Sdes}
376238106Sdes
377238106Sdes/** remove signal handler */
378238106Sdesint signal_del(struct event* ev)
379238106Sdes{
380238106Sdes	if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
381238106Sdes		return -1;
382238106Sdes	ev->ev_base->signals[ev->ev_fd] = NULL;
383238106Sdes	ev->added = 0;
384238106Sdes	return 0;
385238106Sdes}
386238106Sdes
387238106Sdes#else /* USE_MINI_EVENT */
388238106Sdes#ifndef USE_WINSOCK
389238106Sdesint mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
390238106Sdes{
391238106Sdes	return 0;
392238106Sdes}
393238106Sdes#endif /* not USE_WINSOCK */
394238106Sdes#endif /* USE_MINI_EVENT */
395