--- /dev/null
+/*
+ * mini_event.c - implementation of part of libevent api, portably.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/**
+ * \file
+ * fake libevent implementation. Less broad in functionality, and only
+ * supports select(2).
+ */
+
+#include "config.h"
+
+#ifdef USE_MINI_EVENT
+#include <signal.h>
+#include "util/mini_event.h"
+
+/** compare events in tree, based on timevalue, ptr for uniqueness */
+static int ev_cmp(const void* a, const void* b)
+{
+ const struct event *e = (const struct event*)a;
+ const struct event *f = (const struct event*)b;
+ if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
+ return -1;
+ if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
+ return 1;
+ if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
+ return -1;
+ if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
+ return 1;
+ if(e < f)
+ return -1;
+ if(e > f)
+ return 1;
+ return 0;
+}
+
+/** create event base */
+void *event_init(void)
+{
+ struct event_base* base = (struct event_base*)malloc(
+ sizeof(struct event_base));
+ if(!base)
+ return NULL;
+ memset(base, 0, sizeof(*base));
+ base->times = rbtree_create(ev_cmp);
+ if(!base->times) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->fds = (struct event**)calloc(MAX_FDS, sizeof(struct event*));
+ if(!base->fds) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
+ if(!base->signals) {
+ event_base_free(base);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ FD_ZERO(&base->reads);
+ FD_ZERO(&base->writes);
+#endif
+ return base;
+}
+
+/** get version */
+const char *event_get_version(void)
+{
+ return "mini-event-"PACKAGE_VERSION;
+}
+
+/** get polling method, select */
+const char *event_get_method(void)
+{
+ return "select";
+}
+
+/** call timeouts handlers, and return how long to wait for next one or -1 */
+static void handle_timeouts(struct event_base* base, time_t now, time_t *wait)
+{
+ struct event* p, *np;
+ *wait = (time_t)-1;
+
+ p = (struct event*)rbtree_first(base->times);
+ while((rbnode_t*)p!=RBTREE_NULL) {
+ /* store next to make deletion possible */
+ np = (struct event*)rbtree_next((rbnode_t*)p);
+ if(!p || p->ev_timeout.tv_sec > now ||
+ (p->ev_timeout.tv_sec==now && p->ev_timeout.tv_usec>0)) {
+ /* there is a next larger timeout. wait for it */
+ *wait = p->ev_timeout.tv_sec - now;
+ if(p->ev_timeout.tv_usec > 0)
+ *wait+=1; /* wait a bit longer */
+ return;
+ }
+ /* event times out, remove it */
+ (void)rbtree_delete(base->times, p);
+ p->ev_events &= ~EV_TIMEOUT;
+ (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
+ /* next is a valid pointer and next larger element */
+ p = np;
+ }
+}
+
+/** call select and callbacks for that */
+static int handle_select(struct event_base* base, time_t wait)
+{
+ struct timeval tv;
+ fd_set r, w;
+ int ret, i;
+
+ tv.tv_sec = wait;
+ tv.tv_usec = 0;
+ memmove(&r, &base->reads, sizeof(fd_set));
+ memmove(&w, &base->writes, sizeof(fd_set));
+
+ if((ret = select(base->maxfd+1, &r, &w, NULL,
+ (wait==(time_t)-1)?NULL:&tv)) == -1) {
+ return -1;
+ }
+
+ for(i=0; i<base->maxfd+1; i++) {
+ short bits = 0;
+ if(!base->fds[i]) {
+ continue;
+ }
+ if(FD_ISSET(i, &r)) {
+ bits |= EV_READ;
+ ret--;
+ }
+ if(FD_ISSET(i, &w)) {
+ bits |= EV_WRITE;
+ ret--;
+ }
+ bits &= base->fds[i]->ev_events;
+ if(bits) {
+ (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
+ bits, base->fds[i]->ev_arg);
+ if(ret==0)
+ break;
+ }
+ }
+ return 0;
+}
+
+/** run select in a loop */
+int event_base_dispatch(struct event_base* base)
+{
+ while(!base->need_to_exit)
+ {
+ time_t now = time(NULL), wait;
+ /* see if timeouts need handling */
+ handle_timeouts(base, now, &wait);
+ /* do select */
+ if(handle_select(base, wait) < 0) {
+ if(base->need_to_exit)
+ return 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/** exit that loop */
+int event_base_loopexit(struct event_base* base,
+ struct timeval* ATTR_UNUSED(tv))
+{
+ base->need_to_exit = 1;
+ return 0;
+}
+
+/** free event base, free events yourself */
+void event_base_free(struct event_base* base)
+{
+ if(base->times)
+ free(base->times);
+ if(base->fds)
+ free(base->fds);
+ if(base->signals)
+ free(base->signals);
+ free(base);
+}
+
+/** set content of event */
+void event_set(struct event* ev, int fd, short bits,
+ void (*cb)(int, short, void *), void* arg)
+{
+ ev->node.key = ev;
+ ev->ev_fd = fd;
+ ev->ev_events = bits;
+ ev->ev_callback = cb;
+ ev->ev_arg = arg;
+ ev->added = 0;
+}
+
+/** add event to a base */
+int event_base_set(struct event_base* base, struct event* ev)
+{
+ ev->ev_base = base;
+ ev->added = 0;
+ return 0;
+}
+
+/** add event to make it active, you may not change it with event_set anymore */
+int event_add(struct event* ev, struct timeval* tv)
+{
+ if(ev->added)
+ event_del(ev);
+ if(ev->ev_fd != -1 && ev->ev_fd >= MAX_FDS)
+ return -1;
+ if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
+ ev->ev_base->fds[ev->ev_fd] = ev;
+ if(ev->ev_events&EV_READ)
+ FD_SET(ev->ev_fd, &ev->ev_base->reads);
+ if(ev->ev_events&EV_WRITE)
+ FD_SET(ev->ev_fd, &ev->ev_base->writes);
+ if(ev->ev_fd > ev->ev_base->maxfd)
+ ev->ev_base->maxfd = ev->ev_fd;
+ }
+ if(tv && ev->ev_events&EV_TIMEOUT) {
+#ifndef S_SPLINT_S
+ ev->ev_timeout.tv_sec = tv->tv_sec + time(NULL);
+ ev->ev_timeout.tv_usec = tv->tv_usec;
+#endif
+ (void)rbtree_insert(ev->ev_base->times, &ev->node);
+ }
+ ev->added = 1;
+ return 0;
+}
+
+/** remove event, you may change it again */
+int event_del(struct event* ev)
+{
+ if(ev->ev_fd != -1 && ev->ev_fd >= MAX_FDS)
+ return -1;
+ if(ev->ev_events&EV_TIMEOUT)
+ (void)rbtree_delete(ev->ev_base->times, &ev->node);
+ if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
+ ev->ev_base->fds[ev->ev_fd] = NULL;
+ FD_CLR(ev->ev_fd, &ev->ev_base->reads);
+ FD_CLR(ev->ev_fd, &ev->ev_base->writes);
+ }
+ ev->added = 0;
+ return 0;
+}
+
+/** which base gets to handle signals */
+static struct event_base* signal_base = NULL;
+/** signal handler */
+static RETSIGTYPE sigh(int sig)
+{
+ struct event* ev;
+ if(!signal_base || sig < 0 || sig >= MAX_SIG)
+ return;
+ ev = signal_base->signals[sig];
+ if(!ev)
+ return;
+ (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
+}
+
+/** install signal handler */
+int signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv))
+{
+ if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
+ return -1;
+ signal_base = ev->ev_base;
+ ev->ev_base->signals[ev->ev_fd] = ev;
+ ev->added = 1;
+ if(signal(ev->ev_fd, sigh) == SIG_ERR) {
+ return -1;
+ }
+ return 0;
+}
+
+/** remove signal handler */
+int signal_del(struct event* ev)
+{
+ if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
+ return -1;
+ ev->ev_base->signals[ev->ev_fd] = NULL;
+ ev->added = 0;
+ return 0;
+}
+
+#endif /* USE_MINI_EVENT */
--- /dev/null
+/*
+ * mini-event.h - micro implementation of libevent api, using select() only.
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ * This file implements part of the event(3) libevent api.
+ * The back end is only select. Max number of fds is limited.
+ */
+
+#ifndef MINI_EVENT_H
+#define MINI_EVENT_H
+
+#ifdef USE_MINI_EVENT
+
+#ifndef HAVE_EVENT_BASE_FREE
+#define HAVE_EVENT_BASE_FREE
+#endif
+
+/** event timeout */
+#define EV_TIMEOUT 0x01
+/** event fd readable */
+#define EV_READ 0x02
+/** event fd writable */
+#define EV_WRITE 0x04
+/** event signal */
+#define EV_SIGNAL 0x08
+/** event must persist */
+#define EV_PERSIST 0x10
+
+/* needs our redblack tree */
+#include "rbtree.h"
+
+/** max number of file descriptors to support */
+#define MAX_FDS 1024
+/** max number of signals to support */
+#define MAX_SIG 32
+
+/** event base */
+struct event_base
+{
+ /** sorted by timeout (absolute), ptr */
+ rbtree_t* times;
+ /** array of 0 - maxfd of ptr to event for it */
+ struct event** fds;
+ /** max fd in use */
+ int maxfd;
+ /** fdset for read write */
+ fd_set reads, writes;
+ /** array of 0 - maxsig of ptr to event for it */
+ struct event** signals;
+ /** if we need to exit */
+ int need_to_exit;
+};
+
+/**
+ * Event structure. Has some of the event elements.
+ */
+struct event {
+ /** node in timeout rbtree */
+ rbnode_t node;
+ /** is event already added */
+ int added;
+
+ /** event base it belongs to */
+ struct event_base *ev_base;
+ /** fd to poll or -1 for timeouts */
+ int ev_fd;
+ /** events this event is interested in */
+ short ev_events;
+ /** timeout value */
+ struct timeval ev_timeout;
+
+ /** callback to call: fd, eventbits, userarg */
+ void (*ev_callback)(int, short, void *arg);
+ /** callback user arg */
+ void *ev_arg;
+};
+
+/* function prototypes as they appear in event.h */
+/** create event base */
+void *event_init(void);
+/** get version */
+const char *event_get_version(void);
+/** get polling method, select */
+const char *event_get_method(void);
+/** run select in a loop */
+int event_base_dispatch(struct event_base *);
+/** exit that loop */
+int event_base_loopexit(struct event_base *, struct timeval *);
+/** free event base. Free events yourself */
+void event_base_free(struct event_base *);
+/** set content of event */
+void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
+/** add event to a base */
+int event_base_set(struct event_base *, struct event *);
+/** add event to make it active. You may not change it with event_set anymore */
+int event_add(struct event *, struct timeval *);
+/** remove event. You may change it again */
+int event_del(struct event *);
+
+#define evtimer_add(ev, tv) event_add(ev, tv)
+#define evtimer_del(ev) event_del(ev)
+
+/* uses different implementation. Cannot mix fd/timeouts and signals. */
+/** install signal handler */
+int signal_add(struct event *, struct timeval *);
+/** set signal event contents */
+#define signal_set(ev, x, cb, arg) \
+ event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
+/** remove signal handler */
+int signal_del(struct event *);
+
+#endif /* USE_MINI_EVENT */
+#endif /* MINI_EVENT_H */