r98 - in trunk/varnish-cache/contrib/libevent: . WIN32-Code WIN32-Prj test

des at projects.linpro.no des at projects.linpro.no
Mon Apr 3 13:59:08 CEST 2006


Author: des
Date: 2006-04-03 13:59:08 +0200 (Mon, 03 Apr 2006)
New Revision: 98

Added:
   trunk/varnish-cache/contrib/libevent/event_rpcgen.py
   trunk/varnish-cache/contrib/libevent/event_tagging.c
   trunk/varnish-cache/contrib/libevent/http.c
   trunk/varnish-cache/contrib/libevent/http.h
   trunk/varnish-cache/contrib/libevent/strlcpy.c
   trunk/varnish-cache/contrib/libevent/test/regress.h
   trunk/varnish-cache/contrib/libevent/test/regress.rpc
   trunk/varnish-cache/contrib/libevent/test/regress_http.c
Modified:
   trunk/varnish-cache/contrib/libevent/Makefile.am
   trunk/varnish-cache/contrib/libevent/README
   trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c
   trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp
   trunk/varnish-cache/contrib/libevent/buffer.c
   trunk/varnish-cache/contrib/libevent/configure.in
   trunk/varnish-cache/contrib/libevent/devpoll.c
   trunk/varnish-cache/contrib/libevent/epoll.c
   trunk/varnish-cache/contrib/libevent/evbuffer.c
   trunk/varnish-cache/contrib/libevent/event.3
   trunk/varnish-cache/contrib/libevent/event.c
   trunk/varnish-cache/contrib/libevent/event.h
   trunk/varnish-cache/contrib/libevent/kqueue.c
   trunk/varnish-cache/contrib/libevent/log.h
   trunk/varnish-cache/contrib/libevent/poll.c
   trunk/varnish-cache/contrib/libevent/rtsig.c
   trunk/varnish-cache/contrib/libevent/select.c
   trunk/varnish-cache/contrib/libevent/signal.c
   trunk/varnish-cache/contrib/libevent/test/Makefile.am
   trunk/varnish-cache/contrib/libevent/test/regress.c
   trunk/varnish-cache/contrib/libevent/test/test-weof.c
   trunk/varnish-cache/contrib/libevent/test/test.sh
Log:
Update from libevent CVS trunk.

Modified: trunk/varnish-cache/contrib/libevent/Makefile.am
===================================================================
--- trunk/varnish-cache/contrib/libevent/Makefile.am	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/Makefile.am	2006-04-03 11:59:08 UTC (rev 98)
@@ -2,9 +2,11 @@
 
 SUBDIRS = . sample test
 
+bin_SCRIPTS = event_rpcgen.py
+
 EXTRA_DIST = acconfig.h event.h event-internal.h log.h evsignal.h event.3 \
 	kqueue.c epoll_sub.c epoll.c select.c rtsig.c poll.c signal.c \
-	devpoll.c \
+	devpoll.c event_rpcgen.py \
 	sample/Makefile.am sample/Makefile.in sample/event-test.c \
 	sample/signal-test.c sample/time-test.c \
 	test/Makefile.am test/Makefile.in test/bench.c test/regress.c \
@@ -21,9 +23,10 @@
 
 lib_LTLIBRARIES = libevent.la
 
-libevent_la_SOURCES = event.c buffer.c evbuffer.c log.c
+libevent_la_SOURCES = event.c buffer.c evbuffer.c log.c event_tagging.c \
+	 http.c http.h
 libevent_la_LIBADD = @LTLIBOBJS@
-libevent_la_LDFLAGS = -release @VERSION@ -version-info 1:2:0
+libevent_la_LDFLAGS = -release @VERSION@ -version-info 1:3:0
 
 include_HEADERS = event.h
 

Modified: trunk/varnish-cache/contrib/libevent/README
===================================================================
--- trunk/varnish-cache/contrib/libevent/README	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/README	2006-04-03 11:59:08 UTC (rev 98)
@@ -12,6 +12,10 @@
 
 Before, reporting any problems, please run the regression tests.
 
+To enable the low-level tracing build the library as:
+
+CFLAGS=-DUSE_DEBUG ./configure [...]
+ 
 Acknowledgements:
 -----------------
 
@@ -24,5 +28,8 @@
   Mike Davis
   William Ahern
   Alexander von Gernler
+  Artur Grabowski
+  Stas Bekman
+  Tassilo von Parseval
 
 If I have forgotten your name, please contact me.

Modified: trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/WIN32-Code/win32.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -81,6 +81,7 @@
 int win32_del	(void *, struct event *);
 int win32_recalc	(struct event_base *base, void *, int);
 int win32_dispatch	(struct event_base *base, void *, struct timeval *);
+void win32_dealloc	(void *);
 
 struct eventop win32ops = {
 	"win32",
@@ -88,7 +89,8 @@
 	win32_insert,
 	win32_del,
 	win32_recalc,
-	win32_dispatch
+	win32_dispatch,
+	win32_dealloc
 };
 
 #define FD_SET_ALLOC_SIZE(n) ((sizeof(struct win_fd_set) + ((n)-1)*sizeof(SOCKET)))
@@ -135,6 +137,8 @@
 	if (set->fd_count == op->fd_setsz) {
 		if (realloc_fd_sets(op, op->fd_setsz*2))
 			return (-1);
+		/* set pointer will have changed and needs reiniting! */
+		set = read ? op->readset_in : op->writeset_in;
 	}
 	set->fd_array[set->fd_count] = s;
 	return (set->fd_count++);
@@ -363,7 +367,28 @@
 	return (0);
 }
 
+void
+win32_dealloc(void *arg)
+{
+	struct win32op *win32op = arg;
 
+	if (win32op->readset_in)
+		free(win32op->readset_in);
+	if (win32op->writeset_in)
+		free(win32op->writeset_in);
+	if (win32op->readset_out)
+		free(win32op->readset_out);
+	if (win32op->writeset_out)
+		free(win32op->writeset_out);
+	if (win32op->exset_out)
+		free(win32op->exset_out);
+	if (win32op->events)
+		free(win32op->events);
+
+	memset(win32op, 0, sizeof(win32op));
+	free(win32op);
+}
+
 static int
 signal_handler(int sig)
 {

Modified: trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp
===================================================================
--- trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/WIN32-Prj/libevent.dsp	2006-04-03 11:59:08 UTC (rev 98)
@@ -85,7 +85,7 @@
 # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
 # Begin Source File
 
-SOURCE=..\err.c
+SOURCE=..\log.c
 # End Source File
 # Begin Source File
 

Modified: trunk/varnish-cache/contrib/libevent/buffer.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/buffer.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/buffer.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -117,45 +117,55 @@
 	}
 
 	res = evbuffer_add(outbuf, inbuf->buffer, inbuf->off);
-	if (res == 0)
+	if (res == 0) {
+		/* We drain the input buffer on success */
 		evbuffer_drain(inbuf, inbuf->off);
+	}
 
 	return (res);
 }
 
 int
-evbuffer_add_printf(struct evbuffer *buf, char *fmt, ...)
+evbuffer_add_vprintf(struct evbuffer *buf, const char *fmt, va_list ap)
 {
-	int res = -1;
-	char *msg;
-#ifndef HAVE_VASPRINTF
-	static char buffer[4096];
-#endif
-	va_list ap;
+	char *buffer;
+	size_t space;
+	size_t oldoff = buf->off;
+	int sz;
 
-	va_start(ap, fmt);
+	for (;;) {
+		buffer = buf->buffer + buf->off;
+		space = buf->totallen - buf->misalign - buf->off;
 
-#ifdef HAVE_VASPRINTF
-	if (vasprintf(&msg, fmt, ap) == -1)
-		goto end;
+#ifdef WIN32
+		sz = vsnprintf(buffer, space - 1, fmt, ap);
+		buffer[space - 1] = '\0';
 #else
-#  ifdef WIN32
-	_vsnprintf(buffer, sizeof(buffer) - 1, fmt, ap);
-	buffer[sizeof(buffer)-1] = '\0';
-#  else /* ! WIN32 */
-	vsnprintf(buffer, sizeof(buffer), fmt, ap);
-#  endif
-	msg = buffer;
+		sz = vsnprintf(buffer, space, fmt, ap);
 #endif
-	
-	res = strlen(msg);
-	if (evbuffer_add(buf, msg, res) == -1)
-		res = -1;
-#ifdef HAVE_VASPRINTF
-	free(msg);
+		if (sz == -1)
+			return (-1);
+		if (sz < space) {
+			buf->off += sz;
+			if (buf->cb != NULL)
+				(*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
+			return (sz);
+		}
+		if (evbuffer_expand(buf, sz + 1) == -1)
+			return (-1);
 
-end:
-#endif
+	}
+	/* NOTREACHED */
+}
+
+int
+evbuffer_add_printf(struct evbuffer *buf, const char *fmt, ...)
+{
+	int res = -1;
+	va_list ap;
+
+	va_start(ap, fmt);
+	res = evbuffer_add_vprintf(buf, fmt, ap);
 	va_end(ap);
 
 	return (res);
@@ -184,16 +194,16 @@
 char *
 evbuffer_readline(struct evbuffer *buffer)
 {
-	char *data = EVBUFFER_DATA(buffer);
+	u_char *data = EVBUFFER_DATA(buffer);
 	size_t len = EVBUFFER_LENGTH(buffer);
 	char *line;
-	int i;
+	u_int i;
 
 	for (i = 0; i < len; i++) {
 		if (data[i] == '\r' || data[i] == '\n')
 			break;
 	}
-	
+
 	if (i == len)
 		return (NULL);
 
@@ -332,8 +342,21 @@
 #endif
 
 #ifdef FIONREAD
-	if (ioctl(fd, FIONREAD, &n) == -1 || n == 0)
+	if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
 		n = EVBUFFER_MAX_READ;
+	} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
+		/*
+		 * It's possible that a lot of data is available for
+		 * reading.  We do not want to exhaust resources
+		 * before the reader has a chance to do something
+		 * about it.  If the reader does not tell us how much
+		 * data we should read, we artifically limit it.
+		 */
+		if (n > buf->totallen << 2)
+			n = buf->totallen << 2;
+		if (n < EVBUFFER_MAX_READ)
+			n = EVBUFFER_MAX_READ;
+	}
 #endif	
 	if (howmuch < 0 || howmuch > n)
 		howmuch = n;
@@ -397,7 +420,7 @@
 }
 
 u_char *
-evbuffer_find(struct evbuffer *buffer, u_char *what, size_t len)
+evbuffer_find(struct evbuffer *buffer, const u_char *what, size_t len)
 {
 	size_t remain = buffer->off;
 	u_char *search = buffer->buffer;

Modified: trunk/varnish-cache/contrib/libevent/configure.in
===================================================================
--- trunk/varnish-cache/contrib/libevent/configure.in	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/configure.in	2006-04-03 11:59:08 UTC (rev 98)
@@ -2,7 +2,7 @@
 dnl Dug Song <dugsong at monkey.org>
 AC_INIT(event.c)
 
-AM_INIT_AUTOMAKE(libevent,1.1a)
+AM_INIT_AUTOMAKE(libevent,1.2)
 AM_CONFIG_HEADER(config.h)
 AM_MAINTAINER_MODE
 
@@ -117,7 +117,8 @@
 AC_HEADER_TIME
 
 dnl Checks for library functions.
-AC_CHECK_FUNCS(gettimeofday vasprintf fcntl)
+AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime)
+AC_REPLACE_FUNCS(strlcpy)
 
 AC_MSG_CHECKING(for F_SETFD in fcntl.h)
 AC_EGREP_CPP(yes,

Modified: trunk/varnish-cache/contrib/libevent/devpoll.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/devpoll.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/devpoll.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -76,6 +76,7 @@
 int devpoll_del	(void *, struct event *);
 int devpoll_recalc	(struct event_base *, void *, int);
 int devpoll_dispatch	(struct event_base *, void *, struct timeval *);
+void devpoll_dealloc	(void *);
 
 struct eventop devpollops = {
 	"devpoll",
@@ -83,7 +84,8 @@
 	devpoll_add,
 	devpoll_del,
 	devpoll_recalc,
-	devpoll_dispatch
+	devpoll_dispatch,
+	devpoll_dealloc
 };
 
 #define NEVENT	32000
@@ -401,3 +403,21 @@
 
 	return (0);
 }
+
+void
+devpoll_dealloc(void *arg)
+{
+	struct devpollop *devpollop = arg;
+
+	if (devpollop->fds)
+		free(devpollop->fds);
+	if (devpollop->events)
+		free(devpollop->events);
+	if (devpollop->changes)
+		free(devpollop->changes);
+	if (devpollop->dpfd >= 0)
+		close(devpollop->dpfd);
+
+	memset(devpollop, 0, sizeof(struct devpollop));
+	free(devpollop);
+}

Modified: trunk/varnish-cache/contrib/libevent/epoll.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/epoll.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/epoll.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -76,6 +76,7 @@
 int epoll_del	(void *, struct event *);
 int epoll_recalc	(struct event_base *, void *, int);
 int epoll_dispatch	(struct event_base *, void *, struct timeval *);
+void epoll_dealloc	(void *);
 
 struct eventop epollops = {
 	"epoll",
@@ -83,7 +84,8 @@
 	epoll_add,
 	epoll_del,
 	epoll_recalc,
-	epoll_dispatch
+	epoll_dispatch,
+	epoll_dealloc
 };
 
 #ifdef HAVE_SETFD
@@ -109,8 +111,14 @@
 		return (NULL);
 
 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
-	    rl.rlim_cur != RLIM_INFINITY)
-		nfiles = rl.rlim_cur;
+	    rl.rlim_cur != RLIM_INFINITY) {
+		/*
+		 * Solaris is somewhat retarded - it's important to drop
+		 * backwards compatibility when making changes.  So, don't
+		 * dare to put rl.rlim_cur here.
+		 */
+		nfiles = rl.rlim_cur - 1;
+	}
 
 	/* Initalize the kernel queue */
 
@@ -343,3 +351,19 @@
 
 	return (0);
 }
+
+void
+epoll_dealloc(void *arg)
+{
+	struct epollop *epollop = arg;
+
+	if (epollop->fds)
+		free(epollop->fds);
+	if (epollop->events)
+		free(epollop->events);
+	if (epollop->epfd >= 0)
+		close(epollop->epfd);
+
+	memset(epollop, 0, sizeof(struct epollop));
+	free(epollop);
+}

Modified: trunk/varnish-cache/contrib/libevent/evbuffer.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/evbuffer.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/evbuffer.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -74,7 +74,7 @@
     void *arg) {
 	struct bufferevent *bufev = arg;
 	/* 
-	 * If we are below the watermak then reschedule reading if it's
+	 * If we are below the watermark then reschedule reading if it's
 	 * still enabled.
 	 */
 	if (bufev->wm_read.high == 0 || now < bufev->wm_read.high) {
@@ -92,13 +92,21 @@
 	int res = 0;
 	short what = EVBUFFER_READ;
 	size_t len;
+	int howmuch = -1;
 
 	if (event == EV_TIMEOUT) {
 		what |= EVBUFFER_TIMEOUT;
 		goto error;
 	}
 
-	res = evbuffer_read(bufev->input, fd, -1);
+	/*
+	 * If we have a high watermark configured then we don't want to
+	 * read more data than would make us reach the watermark.
+	 */
+	if (bufev->wm_read.high != 0)
+		howmuch = bufev->wm_read.high;
+
+	res = evbuffer_read(bufev->input, fd, howmuch);
 	if (res == -1) {
 		if (errno == EAGAIN || errno == EINTR)
 			goto reschedule;
@@ -226,7 +234,12 @@
 
 	bufev->cbarg = cbarg;
 
-	bufev->enabled = EV_READ | EV_WRITE;
+	/*
+	 * Set to EV_WRITE so that using bufferevent_write is going to
+	 * trigger a callback.  Reading needs to be explicitly enabled
+	 * because otherwise no data will be available.
+	 */
+	bufev->enabled = EV_WRITE;
 
 	return (bufev);
 }
@@ -372,3 +385,16 @@
 	bufferevent_read_pressure_cb(bufev->input,
 	    0, EVBUFFER_LENGTH(bufev->input), bufev);
 }
+
+int
+bufferevent_base_set(struct event_base *base, struct bufferevent *bufev)
+{
+	int res;
+
+	res = event_base_set(base, &bufev->ev_read);
+	if (res == -1)
+		return (res);
+
+	res = event_base_set(base, &bufev->ev_write);
+	return (res);
+}

Modified: trunk/varnish-cache/contrib/libevent/event.3
===================================================================
--- trunk/varnish-cache/contrib/libevent/event.3	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/event.3	2006-04-03 11:59:08 UTC (rev 98)
@@ -34,9 +34,11 @@
 .Nm event_dispatch ,
 .Nm event_loop ,
 .Nm event_loopexit ,
+.Nm event_set ,
+.Nm event_base_dispatch ,
 .Nm event_base_loop ,
 .Nm event_base_loopexit ,
-.Nm event_set ,
+.Nm event_base_set ,
 .Nm event_add ,
 .Nm event_del ,
 .Nm event_once ,
@@ -46,12 +48,12 @@
 .Nm event_priority_set ,
 .Nm evtimer_set ,
 .Nm evtimer_add ,
-.Nm evtimer_del
+.Nm evtimer_del ,
 .Nm evtimer_pending ,
 .Nm evtimer_initialized ,
 .Nm signal_set ,
 .Nm signal_add ,
-.Nm signal_del
+.Nm signal_del ,
 .Nm signal_pending ,
 .Nm signal_initialized ,
 .Nm bufferevent_new ,
@@ -62,16 +64,20 @@
 .Nm bufferevent_enable ,
 .Nm bufferevent_disable ,
 .Nm bufferevent_settimeout ,
+.Nm bufferevent_base_set ,
 .Nm evbuffer_new ,
 .Nm evbuffer_free ,
 .Nm evbuffer_add ,
 .Nm evbuffer_add_buffer ,
 .Nm evbuffer_add_printf ,
+.Nm evbuffer_add_vprintf ,
 .Nm evbuffer_drain ,
 .Nm evbuffer_write ,
 .Nm evbuffer_read ,
 .Nm evbuffer_find ,
-.Nm evbuffer_readline
+.Nm evbuffer_readline ,
+.Nm evhttp_start ,
+.Nm evhttp_free
 .Nd execute a function when a specific event occurs
 .Sh SYNOPSIS
 .Fd #include <sys/time.h>
@@ -84,13 +90,17 @@
 .Fn "event_loop" "int flags"
 .Ft int
 .Fn "event_loopexit" "struct timeval *tv"
-.Ft int
-.Fn "event_base_loop" "struct event_base *" "int flags"
-.Ft int
-.Fn "event_base_loopexit" "struct event_base *" "struct timeval *tv"
 .Ft void
 .Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
 .Ft int
+.Fn "event_base_dispatch" "struct event_base *base"
+.Ft int
+.Fn "event_base_loop" "struct event_base *base" "int flags"
+.Ft int
+.Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
+.Ft int
+.Fn "event_base_set" "struct event_base *base" "struct event *"
+.Ft int
 .Fn "event_add" "struct event *ev" "struct timeval *tv"
 .Ft int
 .Fn "event_del" "struct event *ev"
@@ -140,6 +150,8 @@
 .Fn "bufferevent_disable" "struct bufferevent *bufev" "short event"
 .Ft void
 .Fn "bufferevent_settimeout" "struct bufferevent *bufev" "int timeout_read" "int timeout_write"
+.Ft int
+.Fn "bufferevent_base_set" "struct event_base *base" "struct bufferevent *bufev"
 .Ft "struct evbuffer *"
 .Fn "evbuffer_new" "void"
 .Ft void
@@ -150,6 +162,8 @@
 .Fn "evbuffer_add_buffer" "struct evbuffer *dst" "struct evbuffer *src"
 .Ft int
 .Fn "evbuffer_add_printf" "struct evbuffer *buf" "char *fmt" "..."
+.Ft int
+.Fn "evbuffer_add_vprintf" "struct evbuffer *buf" "const char *fmt" "va_list ap"
 .Ft void
 .Fn "evbuffer_drain" "struct evbuffer *buf" "size_t size"
 .Ft int
@@ -160,6 +174,10 @@
 .Fn "evbuffer_find" "struct evbuffer *buf" "u_char *data" "size_t size"
 .Ft "char *"
 .Fn "evbuffer_readline" "struct evbuffer *buf"
+.Ft "struct evhttp *"
+.Fn "evhttp_start" "const char *address" "u_short port"
+.Ft "void"
+.Fn "evhttp_free" "struct evhttp* http"
 .Ft int
 .Fa (*event_sigcb)(void) ;
 .Ft int
@@ -193,24 +211,26 @@
 to indicate that a signal has been received.
 The application sets
 .Va event_sigcb
-to a callback function.  After the signal handler sets
+to a callback function.
+After the signal handler sets
 .Va event_gotsig ,
 .Nm event_dispatch
-will execute the callback function to process received signals.  The
-callback returns 1 when no events are registered any more.  It can
-return -1 to indicate an error to the
+will execute the callback function to process received signals.
+The callback returns 1 when no events are registered any more.
+It can return -1 to indicate an error to the
 .Nm event
 library, causing
 .Fn event_dispatch
 to terminate with
 .Va errno
 set to
-.Er EINTR.
+.Er EINTR .
 .Pp
 The
 .Nm event_loop
 function provides an interface for single pass execution of pending
-events.  The flags
+events.
+The flags
 .Va EVLOOP_ONCE
 and
 .Va EVLOOP_NONBLOCK
@@ -243,14 +263,14 @@
 argument given in the
 .Fa arg
 argument.
-The 
+The
 .Fa fd
 indicates the file descriptor that should be monitored for events.
 The events can be either
 .Va EV_READ ,
 .Va EV_WRITE ,
-or both.
-Indicating that an application can read or write from the file descriptor
+or both,
+indicating that an application can read or write from the file descriptor
 respectively without blocking.
 .Pp
 The function
@@ -278,18 +298,18 @@
 .Fn event_del
 and does not need to be reinitialized unless the function called and/or
 the argument to it are to be changed.
-However, when an 
+However, when an
 .Fa ev
-structure has been added to libevent using 
+structure has been added to libevent using
 .Fn event_add
-the structure must persist until the event occurs (assuming 
-.Fa EV_PERSIST 
-is not set) or is removed 
-using 
-.Fn event_del .  
+the structure must persist until the event occurs (assuming
+.Fa EV_PERSIST
+is not set) or is removed
+using
+.Fn event_del .
 You may not reuse the same
-.Fa ev 
-structure for multiple monitored descriptors; each descriptor 
+.Fa ev
+structure for multiple monitored descriptors; each descriptor
 needs its own
 .Fa ev .
 .Pp
@@ -297,13 +317,15 @@
 .Fn event_add
 schedules the execution of the
 .Fa ev
-event when the event specified in 
+event when the event specified in
 .Fn event_set
 occurs or in at least the time specified in the
 .Fa tv .
 If
 .Fa tv
-is NULL, no timeout occurs and the function will only be called
+is
+.Dv NULL ,
+no timeout occurs and the function will only be called
 if a matching event occurs on the file descriptor.
 The event in the
 .Fa ev
@@ -335,7 +357,7 @@
 structure.
 This function supports
 .Fa EV_TIMEOUT ,
-.Fa EV_READ
+.Fa EV_READ ,
 and
 .Fa EV_WRITE .
 .Pp
@@ -346,10 +368,10 @@
 is pending to run.
 If
 .Va EV_TIMEOUT
-was specified and 
+was specified and
 .Fa tv
 is not
-.Va NULL ,
+.Dv NULL ,
 the expiration time of the event will be returned in
 .Fa tv .
 .Pp
@@ -365,10 +387,9 @@
 and
 .Fn evtimer_pending
 are abbreviations for common situations where only a timeout is required.
-The file descriptor passed will be -1, and the event type will be
+The file descriptor passed will be \-1, and the event type will be
 .Va EV_TIMEOUT .
 .Pp
-.Pp
 The functions
 .Fn signal_set ,
 .Fn signal_add ,
@@ -385,23 +406,23 @@
 .Va EV_PERSIST .
 .Pp
 It is possible to disable support for
-.Va epoll , kqueue , devpoll, poll
+.Va epoll , kqueue , devpoll , poll
 or
 .Va select
 by setting the environment variable
-.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL, EVENT_NOPOLL
+.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
 or
-.Va EVENT_NOSELECT .
+.Va EVENT_NOSELECT ,
+respectively.
 By setting the environment variable
 .Va EVENT_SHOW_METHOD ,
 .Nm libevent
 displays the kernel notification method that it uses.
-.Pp
 .Sh EVENT PRIORITIES
 By default
 .Nm libevent
 schedules all active events with the same priority.
-However, sometime it is desirable to process some events with a higher
+However, sometimes it is desirable to process some events with a higher
 priority than others.
 For that reason,
 .Nm libevent
@@ -421,7 +442,6 @@
 .Nm libevent
 assigns the middle priority to all events unless their priority
 is explicitly set.
-.Pp
 .Sh THREAD SAFE EVENTS
 .Nm Libevent
 has experimental support for thread-safe events.
@@ -429,24 +449,27 @@
 .Fn event_init ,
 an event base is returned.
 This event base can be used in conjunction with calls to
-.Fn event_base_set
+.Fn event_base_set ,
 .Fn event_base_dispatch ,
 .Fn event_base_loop ,
+.Fn event_base_loopexit ,
 and
-.Fn event_base_loopexit .
-.Fn event_base_set 
+.Fn bufferevent_base_set .
+.Fn event_base_set
 should be called after preparing an event with
-.Fn event_set , 
+.Fn event_set ,
 as
-.Fn event_set 
+.Fn event_set
 assigns the provided event to the most recently created event base.
-.Pp
+.Fn bufferevent_base_set
+should be called after preparing a bufferevent with
+.Fn bufferevent_new .
 .Sh BUFFERED EVENTS
 .Nm libevent
 provides an abstraction on top of the regular event callbacks.
 This abstraction is called a
 .Va "buffered event" .
-A buffered event provides input and output buffer that get filled
+A buffered event provides input and output buffers that get filled
 and drained automatically.
 The user of a buffered event no longer deals directly with the IO,
 but instead is reading from input and writing to output buffers.
@@ -454,21 +477,33 @@
 A new bufferevent is created by
 .Fn bufferevent_new .
 The parameter
-.Fa "fd"
+.Fa fd
 specifies the file descriptor from which data is read and written to.
-This file descriptor is not allowed to be a 
+This file descriptor is not allowed to be a
 .Xr pipe 2 .
 The next three parameters are callbacks.
-The read and write callback have the following form
+The read and write callback have the following form:
 .Ft void
-.Fn "(*cb)" "struct bufferevent *bufev" "void *arg"
+.Fn "(*cb)" "struct bufferevent *bufev" "void *arg" .
+The error callback has the following form:
+.Ft void
+.Fn "(*cb)" "struct bufferevent *bufev" "short what" "void *arg" .
 The argument is specified by the fourth parameter
 .Fa "cbarg" .
+A
+.Fa bufferevent struct
+pointer is returned on success, NULL on error.
 .Pp
-By default the buffered event is read enabled and will try to read
-from the file descriptor.
-The write callback is executed whenever the output buffer is drained
-below the write low watermark which is
+Once initialized, the bufferevent structure can be used repeatedly with
+bufferevent_enable() and bufferevent_disable().  The flags parameter can
+be a combination of 
+.Va EV_READ
+and
+.Va EV_WRITE .
+When read enabled the bufferevent will try to read from the file 
+descriptor and call the read callback. The write callback is executed
+whenever the output buffer is drained below the write low watermark, 
+which is
 .Va 0
 by default.
 .Pp
@@ -482,18 +517,43 @@
 function is used to read data from the input buffer.
 Both functions return the amount of data written or read.
 .Pp
+If multiple bases are in use, bufferevent_base_set() must be called before
+enabling the bufferevent for the first time.
+.Sh NON-BLOCKING HTTP SUPPORT
+.Nm libevent
+provides a very thin HTTP layer that can be used both to host an HTTP
+server and also to make HTTP requests.
+An HTTP server can be created by calling
+.Fn evhttp_start .
+When the HTTP server is no longer used, it can be freed via
+.Fn evhttp_free .
+.Pp
+To be notified of HTTP requests, a user needs to register callbacks with the
+HTTP server.
+This can be done by calling
+.Fn evhttp_set_cb .
+The second argument is the URI for which a callback is being registered.
+The corresponding callback will receive an
+.Va struct evhttp_request
+object that contains all information about the request. 
+.Pp
+This section does not document all the possible function calls, please
+check
+.Va event.h
+for the public interfaces.
 .Sh RETURN VALUES
 Upon successful completion
 .Fn event_add
 and
 .Fn event_del
 return 0.
-Otherwise, -1 is returned and the global variable errno is
+Otherwise, \-1 is returned and the global variable errno is
 set to indicate the error.
 .Sh SEE ALSO
-.Xr timeout 9 ,
+.Xr kqueue 2 ,
+.Xr poll 2 ,
 .Xr select 2 ,
-.Xr kqueue 2
+.Xr timeout 9
 .Sh HISTORY
 The
 .Nm event
@@ -508,7 +568,6 @@
 The
 .Nm event
 library was written by Niels Provos.
-.Pp
 .Sh BUGS
 This documentation is neither complete nor authoritative.
 If you are in doubt about the usage of this API then

Modified: trunk/varnish-cache/contrib/libevent/event.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/event.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/event.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -24,7 +24,9 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+#ifdef HAVE_CONFIG_H
 #include "config.h"
+#endif
 
 #ifdef WIN32
 #define WIN32_LEAN_AND_MEAN
@@ -46,6 +48,7 @@
 #include <unistd.h>
 #endif
 #include <errno.h>
+#include <signal.h>
 #include <string.h>
 #include <assert.h>
 
@@ -107,8 +110,8 @@
 struct event_base *current_base = NULL;
 
 /* Handle signals - This is a deprecated interface */
-int (*event_sigcb)(void);	/* Signal callback when gotsig is set */
-volatile int event_gotsig;	/* Set in signal handler */
+int (*event_sigcb)(void);		/* Signal callback when gotsig is set */
+volatile sig_atomic_t event_gotsig;	/* Set in signal handler */
 
 /* Prototypes */
 static void	event_queue_insert(struct event_base *, struct event *, int);
@@ -135,6 +138,23 @@
 	return (0);
 }
 
+static int
+gettime(struct timeval *tp)
+{
+#ifdef HAVE_CLOCK_GETTIME
+	struct timespec	ts;
+	
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+		return (-1);
+	tp->tv_sec = ts.tv_sec;
+	tp->tv_usec = ts.tv_nsec / 1000;
+#else
+	gettimeofday(tp, NULL);
+#endif
+
+	return (0);
+}
+
 RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
 
 RB_GENERATE(event_tree, event, ev_timeout_node, compare);
@@ -150,7 +170,7 @@
 
 	event_sigcb = NULL;
 	event_gotsig = 0;
-	gettimeofday(&current_base->event_tv, NULL);
+	gettime(&current_base->event_tv);
 	
 	RB_INIT(&current_base->timetree);
 	TAILQ_INIT(&current_base->eventqueue);
@@ -176,6 +196,33 @@
 	return (current_base);
 }
 
+void
+event_base_free(struct event_base *base)
+{
+	int i;
+
+	if (base == NULL && current_base)
+		base = current_base;
+        if (base == current_base)
+		current_base = NULL;
+
+	assert(base);
+	assert(TAILQ_EMPTY(&base->eventqueue));
+	for (i=0; i < base->nactivequeues; ++i)
+		assert(TAILQ_EMPTY(base->activequeues[i]));
+
+	assert(RB_EMPTY(&base->timetree));
+
+	for (i = 0; i < base->nactivequeues; ++i)
+		free(base->activequeues[i]);
+	free(base->activequeues);
+
+	if (base->evsel->dealloc != NULL)
+		base->evsel->dealloc(base->evbase);
+
+	free(base);
+}
+
 int
 event_priority_init(int npriorities)
 {
@@ -313,12 +360,12 @@
 	struct timeval tv;
 	int res, done;
 
-	/* Calculate the initial events that we are waiting for */
-	if (evsel->recalc(base, evbase, 0) == -1)
-		return (-1);
-
 	done = 0;
 	while (!done) {
+		/* Calculate the initial events that we are waiting for */
+		if (evsel->recalc(base, evbase, 0) == -1)
+			return (-1);
+
 		/* Terminate the loop if we have been asked to */
 		if (base->event_gotterm) {
 			base->event_gotterm = 0;
@@ -338,7 +385,7 @@
 		}
 
 		/* Check if time is running backwards */
-		gettimeofday(&tv, NULL);
+		gettime(&tv);
 		if (timercmp(&tv, &base->event_tv, <)) {
 			struct timeval off;
 			event_debug(("%s: time is running backwards, corrected",
@@ -372,9 +419,6 @@
 				done = 1;
 		} else if (flags & EVLOOP_NONBLOCK)
 			done = 1;
-
-		if (evsel->recalc(base, evbase, 0) == -1)
-			return (-1);
 	}
 
 	event_debug(("%s: asked to terminate loop.", __func__));
@@ -499,6 +543,7 @@
 int
 event_pending(struct event *ev, short event, struct timeval *tv)
 {
+	struct timeval	now, res;
 	int flags = 0;
 
 	if (ev->ev_flags & EVLIST_INSERTED)
@@ -513,8 +558,13 @@
 	event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
 
 	/* See if there is a timeout that we should report */
-	if (tv != NULL && (flags & event & EV_TIMEOUT))
-		*tv = ev->ev_timeout;
+	if (tv != NULL && (flags & event & EV_TIMEOUT)) {
+		gettime(&now);
+		timersub(&ev->ev_timeout, &now, &res);
+		/* correctly remap to real time */
+		gettimeofday(&now, NULL);
+		timeradd(&now, &res, tv);
+	}
 
 	return (flags & event);
 }
@@ -558,7 +608,7 @@
 			event_queue_remove(base, ev, EVLIST_ACTIVE);
 		}
 
-		gettimeofday(&now, NULL);
+		gettime(&now);
 		timeradd(&now, tv, &ev->ev_timeout);
 
 		event_debug((
@@ -654,7 +704,7 @@
 		return (0);
 	}
 
-	if (gettimeofday(&now, NULL) == -1)
+	if (gettime(&now) == -1)
 		return (-1);
 
 	if (timercmp(&ev->ev_timeout, &now, <=)) {
@@ -690,7 +740,7 @@
 	struct timeval now;
 	struct event *ev, *next;
 
-	gettimeofday(&now, NULL);
+	gettime(&now);
 
 	for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) {
 		if (timercmp(&ev->ev_timeout, &now, >))

Modified: trunk/varnish-cache/contrib/libevent/event.h
===================================================================
--- trunk/varnish-cache/contrib/libevent/event.h	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/event.h	2006-04-03 11:59:08 UTC (rev 98)
@@ -31,6 +31,8 @@
 extern "C" {
 #endif
 
+#include <stdarg.h>
+
 #ifdef WIN32
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
@@ -101,11 +103,25 @@
 #define EVENT_SIGNAL(ev)	(int)ev->ev_fd
 #define EVENT_FD(ev)		(int)ev->ev_fd
 
+/*
+ * Key-Value pairs.  Can be used for HTTP headers but also for
+ * query argument parsing.
+ */
+struct evkeyval {
+	TAILQ_ENTRY(evkeyval) next;
+
+	char *key;
+	char *value;
+};
+
 #ifdef _EVENT_DEFINED_TQENTRY
 #undef TAILQ_ENTRY
+struct event_list;
+struct evkeyvalq;
 #undef _EVENT_DEFINED_TQENTRY
 #else
 TAILQ_HEAD (event_list, event);
+TAILQ_HEAD (evkeyvalq, evkeyval);
 #endif /* _EVENT_DEFINED_TQENTRY */
 #ifdef _EVENT_DEFINED_RBENTRY
 #undef RB_ENTRY
@@ -119,6 +135,7 @@
 	int (*del)(void *, struct event *);
 	int (*recalc)(struct event_base *, void *, int);
 	int (*dispatch)(struct event_base *, void *, struct timeval *);
+	void (*dealloc)(void *);
 };
 
 #define TIMEOUT_DEFAULT	{5, 0}
@@ -126,6 +143,7 @@
 void *event_init(void);
 int event_dispatch(void);
 int event_base_dispatch(struct event_base *);
+void event_base_free(struct event_base *);
 
 #define _EVENT_LOG_DEBUG 0
 #define _EVENT_LOG_MSG   1
@@ -263,13 +281,115 @@
 int evbuffer_remove(struct evbuffer *, void *, size_t);
 char *evbuffer_readline(struct evbuffer *);
 int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
-int evbuffer_add_printf(struct evbuffer *, char *fmt, ...);
+int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...);
+int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
 void evbuffer_drain(struct evbuffer *, size_t);
 int evbuffer_write(struct evbuffer *, int);
 int evbuffer_read(struct evbuffer *, int, int);
-u_char *evbuffer_find(struct evbuffer *, u_char *, size_t);
+u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
 void evbuffer_setcb(struct evbuffer *, void (*)(struct evbuffer *, size_t, size_t, void *), void *);
 
+/* 
+ * Marshaling tagged data - We assume that all tags are inserted in their
+ * numeric order - so that unknown tags will always be higher than the
+ * known ones - and we can just ignore the end of an event buffer.
+ */
+
+void evtag_init(void);
+
+void evtag_marshal(struct evbuffer *evbuf, u_int8_t tag, const void *data,
+    u_int16_t len);
+
+void encode_int(struct evbuffer *evbuf, u_int32_t number);
+
+void evtag_marshal_int(struct evbuffer *evbuf, u_int8_t tag,
+    u_int32_t integer);
+
+void evtag_marshal_string(struct evbuffer *buf, u_int8_t tag,
+    const char *string);
+
+void evtag_marshal_timeval(struct evbuffer *evbuf, u_int8_t tag,
+    struct timeval *tv);
+
+void evtag_test(void);
+
+int evtag_unmarshal(struct evbuffer *src, u_int8_t *ptag,
+    struct evbuffer *dst);
+int evtag_peek(struct evbuffer *evbuf, u_int8_t *ptag);
+int evtag_peek_length(struct evbuffer *evbuf, u_int32_t *plength);
+int evtag_payload_length(struct evbuffer *evbuf, u_int32_t *plength);
+int evtag_consume(struct evbuffer *evbuf);
+
+int evtag_unmarshal_int(struct evbuffer *evbuf, u_int8_t need_tag,
+    u_int32_t *pinteger);
+
+int evtag_unmarshal_fixed(struct evbuffer *src, u_int8_t need_tag, void *data,
+    size_t len);
+
+int evtag_unmarshal_string(struct evbuffer *evbuf, u_int8_t need_tag,
+    char **pstring);
+
+int evtag_unmarshal_timeval(struct evbuffer *evbuf, u_int8_t need_tag,
+    struct timeval *ptv);
+
+/*
+ * Basic support for HTTP serving.
+ *
+ * As libevent is a library for dealing with event notification and most
+ * interesting applications are networked today, I have often found the
+ * need to write HTTP code.  The following prototypes and definitions provide
+ * an application with a minimal interface for making HTTP requests and for
+ * creating a very simple HTTP server.
+ */
+
+/* Response codes */	
+#define HTTP_OK			200
+#define HTTP_MOVEPERM		301
+#define HTTP_MOVETEMP		302
+#define HTTP_NOTFOUND		404
+
+struct evhttp;
+struct evhttp_request;
+
+/* Start an HTTP server on the specified address and port */
+struct evhttp *evhttp_start(const char *address, u_short port);
+
+/*
+ * Free the previously create HTTP server.  Works only if no requests are
+ * currently being served.
+ */
+void evhttp_free(struct evhttp* http);
+
+/* Set a callback for a specified URI */
+void evhttp_set_cb(struct evhttp *, const char *,
+    void (*)(struct evhttp_request *, void *), void *);
+
+/* Set a callback for all requests that are not caught by specific callbacks */
+void evhttp_set_gencb(struct evhttp *,
+    void (*)(struct evhttp_request *, void *), void *);
+
+void evhttp_send_error(struct evhttp_request *, int, const char *);
+void evhttp_send_reply(struct evhttp_request *, int, const char *,
+    struct evbuffer *);
+
+/* Interfaces for making requests */
+enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD };
+
+struct evhttp_request *evhttp_request_new(
+	void (*cb)(struct evhttp_request *, void *), void *arg);
+void evhttp_request_free(struct evhttp_request *req);
+const char *evhttp_request_uri(struct evhttp_request *req);
+
+/* Interfaces for dealing with HTTP headers */
+
+const char *evhttp_find_header(struct evkeyvalq *, const char *);
+int evhttp_remove_header(struct evkeyvalq *, const char *);
+int evhttp_add_header(struct evkeyvalq *, const char *, const char *);
+void evhttp_clear_headers(struct evkeyvalq *);
+
+/* Miscellaneous utility functions */
+void evhttp_parse_query(const char *uri, struct evkeyvalq *);
+char *evhttp_htmlescape(const char *html);
 #ifdef __cplusplus
 }
 #endif

Added: trunk/varnish-cache/contrib/libevent/event_rpcgen.py
===================================================================
--- trunk/varnish-cache/contrib/libevent/event_rpcgen.py	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/event_rpcgen.py	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,1378 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2005 Niels Provos <provos at citi.umich.edu>
+# All rights reserved.
+#
+# Generates marshalling code based on libevent.
+
+import sys
+import re
+
+#
+_NAME = "event_rpcgen.py"
+_VERSION = "0.1"
+_STRUCT_RE = '[a-z][a-z_0-9]*'
+
+# Globals
+line_count = 0
+
+leading = re.compile(r'^\s+')
+trailing = re.compile(r'\s+$')
+white = re.compile(r'^\s+')
+cppcomment = re.compile(r'\/\/.*$')
+cppdirect = []
+
+# Holds everything that makes a struct
+class Struct:
+    def __init__(self, name):
+        self._name = name
+        self._entries = []
+        self._tags = {}
+        print >>sys.stderr, '  Created struct: %s' % name
+
+    def AddEntry(self, entry):
+        if self._tags.has_key(entry.Tag()):
+            print >>sys.stderr, ( 'Entry "%s" duplicates tag number '
+                                  '%d from "%s" around line %d' ) % (
+                entry.Name(), entry.Tag(),
+                self._tags[entry.Tag()], line_count)
+            sys.exit(1)
+        self._entries.append(entry)
+        self._tags[entry.Tag()] = entry.Name()
+        print >>sys.stderr, '    Added entry: %s' % entry.Name()
+
+    def Name(self):
+        return self._name
+
+    def EntryTagName(self, entry):
+        """Creates the name inside an enumeration for distinguishing data
+        types."""
+        name = "%s_%s" % (self._name, entry.Name())
+        return name.upper()
+
+    def PrintIdented(self, file, ident, code):
+        """Takes an array, add indentation to each entry and prints it."""
+        for entry in code:
+            print >>file, '%s%s' % (ident, entry)
+
+    def PrintTags(self, file):
+        """Prints the tag definitions for a structure."""
+        print >>file, '/* Tag definition for %s */' % self._name
+        print >>file, 'enum %s_ {' % self._name.lower()
+        for entry in self._entries:
+            print >>file, '  %s=%d,' % (self.EntryTagName(entry),
+                                        entry.Tag())
+        print >>file, '  %s_MAX_TAGS' % (self._name.upper())
+        print >>file, '} %s_tags;\n' % (self._name.lower())
+
+    def PrintForwardDeclaration(self, file):
+        print >>file, 'struct %s;' % self._name
+
+    def PrintDeclaration(self, file):
+        print >>file, '/* Structure declaration for %s */' % self._name
+        print >>file, 'struct %s {' % self._name
+        for entry in self._entries:
+            dcl = entry.Declaration()
+            dcl.extend(
+                entry.AssignDeclaration('(*%s_assign)' % entry.Name()))
+            dcl.extend(
+                entry.GetDeclaration('(*%s_get)' % entry.Name()))
+            if entry.Array():
+                dcl.extend(
+                    entry.AddDeclaration('(*%s_add)' % entry.Name()))
+            self.PrintIdented(file, '  ', dcl)
+        print >>file, ''
+        for entry in self._entries:
+            print >>file, '  u_int8_t %s_set;' % entry.Name()
+        print >>file, '};\n'
+
+        print >>file, (
+            'struct %s *%s_new();\n' % (self._name, self._name) +
+            'void %s_free(struct %s *);\n' % (self._name, self._name) +
+            'void %s_clear(struct %s *);\n' % (self._name, self._name) +
+            'void %s_marshal(struct evbuffer *, const struct %s *);\n' % (
+            self._name, self._name) +
+            'int %s_unmarshal(struct %s *, struct evbuffer *);\n' % (
+            self._name, self._name) +
+            'int %s_complete(struct %s *);' % (self._name, self._name)
+            )
+        print >>file, ('void evtag_marshal_%s(struct evbuffer *, u_int8_t, '
+                       'const struct %s *);') % ( self._name, self._name)
+        print >>file, ('int evtag_unmarshal_%s(struct evbuffer *, u_int8_t, '
+                       'struct %s *);') % ( self._name, self._name)
+
+        # Write a setting function of every variable
+        for entry in self._entries:
+            self.PrintIdented(file, '', entry.AssignDeclaration(
+                entry.AssignFuncName()))
+            self.PrintIdented(file, '', entry.GetDeclaration(
+                entry.GetFuncName()))
+            if entry.Array():
+                self.PrintIdented(file, '', entry.AddDeclaration(
+                    entry.AddFuncName()))
+
+        print >>file, '/* --- %s done --- */\n' % self._name
+
+    def PrintCode(self, file):
+        print >>file, ('/*\n'
+                       ' * Implementation of %s\n'
+                       ' */\n') % self._name
+
+        # Creation
+        print >>file, ( 'struct %s *\n' % self._name +
+                        '%s_new()\n' % self._name +
+                        '{\n'
+                        '  struct %s *tmp;\n' % self._name +
+                        '  if ((tmp = malloc(sizeof(struct %s))) == NULL) {\n'
+                        '    event_warn("%%s: malloc", __func__);\n'
+                        '    return (NULL);\n' % self._name +
+                        '  }'
+                        )
+        for entry in self._entries:
+            self.PrintIdented(file, '  ', entry.CodeNew('tmp'))
+            print >>file, '  tmp->%s_set = 0;\n' % entry.Name()
+
+        print >>file, ('  return (tmp);\n'
+                       '}\n')
+
+        # Adding
+        for entry in self._entries:
+            if entry.Array():
+                self.PrintIdented(file, '', entry.CodeAdd())
+            print >>file, ''
+            
+        # Assigning
+        for entry in self._entries:
+            self.PrintIdented(file, '', entry.CodeAssign())
+            print >>file, ''
+
+        # Getting
+        for entry in self._entries:
+            self.PrintIdented(file, '', entry.CodeGet())
+            print >>file, ''
+            
+        # Clearing
+        print >>file, ( 'void\n'
+                        '%s_clear(struct %s *tmp)\n' % (
+            self._name, self._name)+
+                        '{'
+                        )
+        for entry in self._entries:
+            self.PrintIdented(file, '  ', entry.CodeClear('tmp'))
+
+        print >>file, '}\n'
+
+        # Freeing
+        print >>file, ( 'void\n'
+                        '%s_free(struct %s *tmp)\n' % (
+            self._name, self._name)+
+                        '{'
+                        )
+        for entry in self._entries:
+            self.PrintIdented(file, '  ', entry.CodeFree('tmp'))
+
+        print >>file, ('  free(tmp);\n'
+                       '}\n')
+
+        # Marshaling
+        print >>file, ('void\n'
+                       '%s_marshal(struct evbuffer *evbuf, '
+                       'const struct %s *tmp)' % (self._name, self._name) +
+                       '{')
+        for entry in self._entries:
+            indent = '  '
+            # Optional entries do not have to be set
+            if entry.Optional():
+                indent += '  '
+                print >>file, '  if (tmp->%s_set) {' % entry.Name()
+            self.PrintIdented(
+                file, indent,
+                entry.CodeMarshal('evbuf', self.EntryTagName(entry), 'tmp'))
+            if entry.Optional():
+                print >>file, '  }'
+
+        print >>file, '}\n'
+                       
+        # Unmarshaling
+        print >>file, ('int\n'
+                       '%s_unmarshal(struct %s *tmp, '
+                       ' struct evbuffer *evbuf)\n' % (
+            self._name, self._name) +
+                       '{\n'
+                       '  u_int8_t tag;\n'
+                       '  while (EVBUFFER_LENGTH(evbuf) > 0) {\n'
+                       '    if (evtag_peek(evbuf, &tag) == -1)\n'
+                       '      return (-1);\n'
+                       '    switch (tag) {\n'
+                       )
+        for entry in self._entries:
+            print >>file, '      case %s:\n' % self.EntryTagName(entry)
+            if not entry.Array():
+                print >>file, (
+                    '        if (tmp->%s_set)\n'
+                    '          return (-1);'
+                    ) % (entry.Name())
+
+            self.PrintIdented(
+                file, '        ',
+                entry.CodeUnmarshal('evbuf',
+                                    self.EntryTagName(entry), 'tmp'))
+
+            print >>file, ( '        tmp->%s_set = 1;\n' % entry.Name() +
+                            '        break;\n' )
+        print >>file, ( '      default:\n'
+                        '        return -1;\n'
+                        '    }\n'
+                        '  }\n' )
+        # Check if it was decoded completely
+        print >>file, ( '  if (%s_complete(tmp) == -1)\n' % self._name +
+                        '    return (-1);')
+
+        # Successfully decoded
+        print >>file, ( '  return (0);\n'
+                        '}\n')
+
+        # Checking if a structure has all the required data
+        print >>file, (
+            'int\n'
+            '%s_complete(struct %s *msg)\n' % (self._name, self._name) +
+            '{' )
+        for entry in self._entries:
+            self.PrintIdented(
+                file, '  ',
+                entry.CodeComplete('msg'))
+        print >>file, (
+            '  return (0);\n'
+            '}\n' )
+
+        # Complete message unmarshaling
+        print >>file, (
+            'int\n'
+            'evtag_unmarshal_%s(struct evbuffer *evbuf, u_int8_t need_tag, '
+            ' struct %s *msg)'
+            ) % (self._name, self._name)
+        print >>file, (
+            '{\n'
+            '  u_int8_t tag;\n'
+            '  int res = -1;\n'
+            '\n'
+            '  struct evbuffer *tmp = evbuffer_new();\n'
+            '\n'
+            '  if (evtag_unmarshal(evbuf, &tag, tmp) == -1'
+            ' || tag != need_tag)\n'
+            '    goto error;\n'
+            '\n'
+            '  if (%s_unmarshal(msg, tmp) == -1)\n'
+            '    goto error;\n'
+            '\n'
+            '  res = 0;\n'
+            '\n'
+            ' error:\n'
+            '  evbuffer_free(tmp);\n'
+            '  return (res);\n'
+            '}\n' ) % self._name
+
+        # Complete message marshaling
+        print >>file, (
+            'void\n'
+            'evtag_marshal_%s(struct evbuffer *evbuf, u_int8_t tag, '
+            'const struct %s *msg)\n' % (self._name, self._name) +
+            '{\n'
+            '  struct evbuffer *_buf = evbuffer_new();\n'
+            '  assert(_buf != NULL);\n'
+            '  evbuffer_drain(_buf, -1);\n'
+            '  %s_marshal(_buf, msg);\n' % self._name +
+            '  evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), '
+            'EVBUFFER_LENGTH(_buf));\n'
+            '  evbuffer_free(_buf);\n'
+            '}\n' )
+
+class Entry:
+    def __init__(self, type, name, tag):
+        self._type = type
+        self._name = name
+        self._tag = int(tag)
+        self._ctype = type
+        self._optional = 0
+        self._can_be_array = 0
+        self._array = 0
+        self._line_count = -1
+        self._struct = None
+
+    def SetStruct(self, struct):
+        self._struct = struct
+
+    def LineCount(self):
+        assert self._line_count != -1
+        return self._line_count
+
+    def SetLineCount(self, number):
+        self._line_count = number
+
+    def Array(self):
+        return self._array
+
+    def Optional(self):
+        return self._optional
+
+    def Tag(self):
+        return self._tag
+
+    def Name(self):
+        return self._name
+
+    def Type(self):
+        return self._type
+
+    def MakeArray(self, yes=1):
+        self._array = yes
+        
+    def MakeOptional(self):
+        self._optional = 1
+
+    def GetFuncName(self):
+        return '%s_%s_get' % (self._struct.Name(), self._name)
+    
+    def GetDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, %s *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+
+    def CodeGet(self):
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, %s *value)' % (
+            self._struct.Name(), self._name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1)' % self._name,
+                 '    return (-1);',
+                 '  *value = msg->%s_data;' % self._name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def AssignFuncName(self):
+        return '%s_%s_assign' % (self._struct.Name(), self._name)
+    
+    def AddFuncName(self):
+        return '%s_%s_add' % (self._struct.Name(), self._name)
+    
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, const %s);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+
+    def CodeAssign(self):
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, const %s value)' % (
+            self._struct.Name(), self._name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  msg->%s_set = 1;' % self._name,
+                 '  msg->%s_data = value;' % self._name,
+                 '  return (0);',
+                 '}' ]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ '%s->%s_set = 0;' % (structname, self.Name()) ]
+
+        return code
+        
+    def CodeComplete(self, structname):
+        if self.Optional():
+            return []
+        
+        code = [ 'if (!%s->%s_set)' % (structname, self.Name()),
+                 '  return (-1);' ]
+
+        return code
+
+    def CodeFree(self, name):
+        return []
+
+    def CodeNew(self, name):
+        code = [ '%s->%s_assign = %s_%s_assign;' % (
+            name, self._name, self._struct.Name(), self._name ),
+                 '%s->%s_get = %s_%s_get;' % (
+            name, self._name, self._struct.Name(), self._name ),
+        ]
+        if self.Array():
+            code.append(
+                '%s->%s_add = %s_%s_add;' % (
+                name, self._name, self._struct.Name(), self._name ) )
+        return code
+
+    def Verify(self):
+        if self.Array() and not self._can_be_array:
+            print >>sys.stderr, (
+                'Entry "%s" cannot be created as an array '
+                'around line %d' ) % (self._name, self.LineCount())
+            sys.exit(1)
+        if not self._struct:
+            print >>sys.stderr, (
+                'Entry "%s" does not know which struct it belongs to '
+                'around line %d' ) % (self._name, self.LineCount())
+            sys.exit(1)
+        if self._optional and self._array:
+            print >>sys.stderr,  ( 'Entry "%s" has illegal combination of '
+                                   'optional and array around line %d' ) % (
+                self._name, self.LineCount() )
+            sys.exit(1)
+
+class EntryBytes(Entry):
+    def __init__(self, type, name, tag, length):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._length = length
+        self._ctype = 'u_int8_t'
+
+    def GetDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, %s **);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, const %s *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def Declaration(self):
+        dcl  = ['u_int8_t %s_data[%s];' % (self._name, self._length)]
+        
+        return dcl
+
+    def CodeGet(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, %s **value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1)' % name,
+                 '    return (-1);',
+                 '  *value = msg->%s_data;' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeAssign(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, const %s *value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  msg->%s_set = 1;' % name,
+                 '  memcpy(msg->%s_data, value, %s);' % (
+            name, self._length),
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = [  'if (evtag_unmarshal_fixed(%s, %s, ' % (buf, tag_name) +
+                  '%s->%s_data, ' % (var_name, self._name) +
+                  'sizeof(%s->%s_data)) == -1) {' % (
+            var_name, self._name),
+                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                  '  return (-1);',
+                  '}'
+                  ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal(%s, %s, %s->%s_data, sizeof(%s->%s_data));' % (
+            buf, tag_name, var_name, self._name, var_name, self._name )]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ '%s->%s_set = 0;' % (structname, self.Name()),
+                 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+            structname, self._name, structname, self._name)]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % (
+            name, self._name, name, self._name)]
+        code.extend(Entry.CodeNew(self, name))
+        return code
+
+    def Verify(self):
+        if not self._length:
+            print >>sys.stderr, 'Entry "%s" needs a length around line %d' % (
+                self._name, self.LineCount() )
+            sys.exit(1)
+
+        Entry.Verify(self)
+
+class EntryInt(Entry):
+    def __init__(self, type, name, tag):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._ctype = 'u_int32_t'
+
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['if (evtag_unmarshal_int(%s, %s, &%s->%s_data) == -1) {' % (
+            buf, tag_name, var_name, self._name),
+                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}' ] 
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal_int(%s, %s, %s->%s_data);' % (
+            buf, tag_name, var_name, self._name)]
+        return code
+
+    def Declaration(self):
+        dcl  = ['u_int32_t %s_data;' % self._name]
+
+        return dcl
+
+class EntryString(Entry):
+    def __init__(self, type, name, tag):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._ctype = 'char *'
+
+    def CodeAssign(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, const %s value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_data != NULL)' % name,
+                 '    free(msg->%s_data);' % name,
+                 '  if ((msg->%s_data = strdup(value)) == NULL)' % name,
+                 '    return (-1);',
+                 '  msg->%s_set = 1;' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['if (evtag_unmarshal_string(%s, %s, &%s->%s_data) == -1) {' % (
+            buf, tag_name, var_name, self._name),
+                '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}'
+                ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal_string(%s, %s, %s->%s_data);' % (
+            buf, tag_name, var_name, self._name)]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  free (%s->%s_data);' % (structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name)]
+        code.extend(Entry.CodeNew(self, name))
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
+                 '    free (%s->%s_data); ' % (name, self._name)]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['char *%s_data;' % self._name]
+
+        return dcl
+
+class EntryStruct(Entry):
+    def __init__(self, type, name, tag, refname):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._can_be_array = 1
+        self._refname = refname
+        self._ctype = 'struct %s' % refname
+
+    def GetDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, %s **);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, const %s *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def CodeGet(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, %s **value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1) {' % name,
+                 '    msg->%s_data = %s_new();' % (name, self._refname),
+                 '    if (msg->%s_data == NULL)' % name,
+                 '      return (-1);',
+                 '    msg->%s_set = 1;' % name,
+                 '  }',
+                 '  *value = msg->%s_data;' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeAssign(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, const %s *value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  struct evbuffer *tmp = NULL;',
+                 '  if (msg->%s_set) {' % name,
+                 '    %s_clear(msg->%s_data);' % (self._refname, name),
+                 '    msg->%s_set = 0;' % name,
+                 '  } else {',
+                 '    msg->%s_data = %s_new();' % (name, self._refname),
+                 '    if (msg->%s_data == NULL) {' % name,
+                 '      event_warn("%%s: %s_new()", __func__);' % (
+            self._refname),
+                 '      goto error;',
+                 '    }',
+                 '  }',
+                 '  if ((tmp = evbuffer_new()) == NULL) {',
+                 '    event_warn("%s: evbuffer_new()", __func__);',
+                 '    goto error;',
+                 '  }',
+                 '  %s_marshal(tmp, value); ' % self._refname,
+                 '  if (%s_unmarshal(msg->%s_data, tmp) == -1) {' % (
+            self._refname, name ),
+                 '    event_warnx("%%s: %s_unmarshal", __func__);' % (
+            self._refname),
+                 '    goto error;',
+                 '  }',
+                 '  msg->%s_set = 1;' % name,
+                 '  evbuffer_free(tmp);',
+                 '  return (0);',
+                 ' error:',
+                 '  if (tmp != NULL)',
+                 '    evbuffer_free(tmp);',
+                 '  if (msg->%s_data != NULL) {' % name,
+                 '    %s_free(msg->%s_data);' % (self._refname, name),
+                 '    msg->%s_data = NULL;' % name,
+                 '  }',
+                 '  return (-1);',
+                 '}' ]
+        return code
+        
+    def CodeComplete(self, structname):
+        if self.Optional():
+            code = [ 'if (%s->%s_set && %s_complete(%s->%s_data) == -1)' % (
+                structname, self.Name(),
+                self._refname, structname, self.Name()),
+                     '  return (-1);' ]
+        else:
+            code = [ 'if (%s_complete(%s->%s_data) == -1)' % (
+                self._refname, structname, self.Name()),
+                     '  return (-1);' ]
+
+        return code
+    
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['%s->%s_data = %s_new();' % (
+            var_name, self._name, self._refname),
+                'if (%s->%s_data == NULL)' % (var_name, self._name),
+                '  return (-1);',
+                'if (evtag_unmarshal_%s(%s, %s, %s->%s_data) == -1) {' % (
+            self._refname, buf, tag_name, var_name, self._name),
+                  '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}'
+                ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal_%s(%s, %s, %s->%s_data);' % (
+            self._refname, buf, tag_name, var_name, self._name)]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  %s_free(%s->%s_data);' % (
+            self._refname, structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name)]
+        code.extend(Entry.CodeNew(self, name))
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
+                 '    %s_free(%s->%s_data); ' % (
+            self._refname, name, self._name)]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['struct %s *%s_data;' % (self._refname, self._name)]
+
+        return dcl
+
+class EntryVarBytes(Entry):
+    def __init__(self, type, name, tag):
+        # Init base class
+        Entry.__init__(self, type, name, tag)
+
+        self._ctype = 'u_int8_t *'
+
+    def GetDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, %s *, u_int32_t *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, const %s, u_int32_t);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def CodeAssign(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, '
+                 'const %s value, u_int32_t len)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_data != NULL)' % name,
+                 '    free (msg->%s_data);' % name,
+                 '  msg->%s_data = malloc(len);' % name,
+                 '  if (msg->%s_data == NULL)' % name,
+                 '    return (-1);',
+                 '  msg->%s_set = 1;' % name,
+                 '  msg->%s_length = len;' % name,
+                 '  memcpy(msg->%s_data, value, len);' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeGet(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, %s *value, u_int32_t *plen)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1)' % name,
+                 '    return (-1);',
+                 '  *value = msg->%s_data;' % name,
+                 '  *plen = msg->%s_length;' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['if (evtag_payload_length(%s, &%s->%s_length) == -1)' % (
+            buf, var_name, self._name),
+                '  return (-1);',
+                # We do not want DoS opportunities
+                'if (%s->%s_length > EVBUFFER_LENGTH(%s))' % (
+            var_name, self._name, buf),
+                '  return (-1);',
+                'if ((%s->%s_data = malloc(%s->%s_length)) == NULL)' % (
+            var_name, self._name, var_name, self._name),
+                '  return (-1);',
+                'if (evtag_unmarshal_fixed(%s, %s, %s->%s_data, '
+                '%s->%s_length) == -1) {' % (
+            buf, tag_name, var_name, self._name, var_name, self._name),
+                '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}'
+                ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['evtag_marshal(%s, %s, %s->%s_data, %s->%s_length);' % (
+            buf, tag_name, var_name, self._name, var_name, self._name)]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  free (%s->%s_data);' % (structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_length = 0;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name),
+                 '%s->%s_length = 0;' % (name, self._name) ]
+        code.extend(Entry.CodeNew(self, name))
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL)' % (name, self._name),
+                 '    free (%s->%s_data); ' % (name, self._name)]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['u_int8_t *%s_data;' % self._name,
+                'u_int32_t %s_length;' % self._name]
+
+        return dcl
+
+class EntryArray(Entry):
+    def __init__(self, entry):
+        # Init base class
+        Entry.__init__(self, entry._type, entry._name, entry._tag)
+
+        self._entry = entry
+        self._refname = entry._refname
+        self._ctype = 'struct %s' % self._refname
+
+    def GetDeclaration(self, funcname):
+        """Allows direct access to elements of the array."""
+        code = [ 'int %s(struct %s *, int, %s **);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AssignDeclaration(self, funcname):
+        code = [ 'int %s(struct %s *, int, const %s *);' % (
+            funcname, self._struct.Name(), self._ctype ) ]
+        return code
+        
+    def AddDeclaration(self, funcname):
+        code = [ '%s *%s(struct %s *);' % (
+            self._ctype, funcname, self._struct.Name() ) ]
+        return code
+        
+    def CodeGet(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_get(struct %s *msg, int offset, %s **value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  if (msg->%s_set != 1)' % name,
+                 '    return (-1);',
+                 '  if (offset >= msg->%s_length)' % name,
+                 '    return (-1);',
+                 '  *value = msg->%s_data[offset];' % name,
+                 '  return (0);',
+                 '}' ]
+        return code
+        
+    def CodeAssign(self):
+        name = self._name
+        code = [ 'int',
+                 '%s_%s_assign(struct %s *msg, int off, const %s *value)' % (
+            self._struct.Name(), name,
+            self._struct.Name(), self._ctype),
+                 '{',
+                 '  struct evbuffer *tmp = NULL;',
+                 '  if (msg->%s_set != 1)' % name,
+                 '    return (-1);',
+                 '  if (off >= msg->%s_length)' % name,
+                 '    return (-1);',
+                 '',
+                 '  %s_clear(msg->%s_data[off]);' % (self._refname, name),
+                 '  if ((tmp = evbuffer_new()) == NULL) {',
+                 '    event_warn("%s: evbuffer_new()", __func__);',
+                 '    goto error;',
+                 '  }',
+                 '  %s_marshal(tmp, value); ' % self._refname,
+                 '  if (%s_unmarshal(msg->%s_data[off], tmp) == -1) {' % (
+            self._refname, name ),
+                 '    event_warnx("%%s: %s_unmarshal", __func__);' % (
+            self._refname),
+                 '    goto error;',
+                 '  }',
+                 '  evbuffer_free(tmp);',
+                 '  return (0);',
+                 ' error:',
+                 '  if (tmp != NULL)',
+                 '    evbuffer_free(tmp);',
+                 '  %s_clear(msg->%s_data[off]);' % (self._refname, name),
+                 '  return (-1);',
+                 '}' ]
+        return code
+        
+    def CodeAdd(self):
+        name = self._name
+        code = [
+            '%s *' % self._ctype, 
+            '%s_%s_add(struct %s *msg)' % (
+            self._struct.Name(), name, self._struct.Name()),
+            '{',
+            '  msg->%s_length++;' % name,
+            '  msg->%s_data = (struct %s**)realloc(msg->%s_data, '
+            '  msg->%s_length * sizeof(struct %s*));' % (
+            name, self._refname, name, name, self._refname ),
+            '  if (msg->%s_data == NULL)' % name,
+            '    return (NULL);',
+            '  msg->%s_data[msg->%s_length - 1] = %s_new();' % (
+            name, name, self._refname),
+            '  if (msg->%s_data[msg->%s_length - 1] == NULL) {' % (name, name),
+            '    msg->%s_length--; ' % name,
+            '    return (NULL);',
+            '  }',
+            '  msg->%s_set = 1;' % name,
+            '  return (msg->%s_data[msg->%s_length - 1]);' % (name, name),
+            '}'
+            ]
+        return code
+        
+    def CodeComplete(self, structname):
+        code = []
+        if self.Optional():
+            code.append( 'if (%s->%s_set)'  % (structname, self.Name()))
+
+        code.extend(['{',
+                     '  int i;',
+                     '  for (i = 0; i < %s->%s_length; ++i) {' % (
+                structname, self.Name()),
+                     '    if (%s_complete(%s->%s_data[i]) == -1)' % (
+                self._refname, structname, self.Name()),
+                     '      return (-1);',
+                     '  }',
+                     '}'
+                     ])
+
+        return code
+    
+    def CodeUnmarshal(self, buf, tag_name, var_name):
+        code = ['if (%s_%s_add(%s) == NULL)' % (
+            self._struct.Name(), self._name, var_name),
+                '  return (-1);',
+                'if (evtag_unmarshal_%s(%s, %s, '
+                '%s->%s_data[%s->%s_length - 1]) == -1) {' % (
+            self._refname, buf, tag_name, var_name, self._name,
+            var_name, self._name),
+                '  %s->%s_length--; ' % (var_name, self._name),
+                '  event_warnx("%%s: failed to unmarshal %s", __func__);' % (
+            self._name ),
+                '  return (-1);',
+                '}'
+                ]
+        return code
+
+    def CodeMarshal(self, buf, tag_name, var_name):
+        code = ['{',
+                '  int i;',
+                '  for (i = 0; i < %s->%s_length; ++i) {' % (
+            var_name, self._name),
+                '    evtag_marshal_%s(%s, %s, %s->%s_data[i]);' % (
+            self._refname, buf, tag_name, var_name, self._name),
+                '  }',
+                '}'
+                ]
+        return code
+
+    def CodeClear(self, structname):
+        code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()),
+                 '  int i;',
+                 '  for (i = 0; i < %s->%s_length; ++i) {' % (
+            structname, self.Name()),
+                 '    %s_free(%s->%s_data[i]);' % (
+            self._refname, structname, self.Name()),
+                 '  }',
+                 '  free(%s->%s_data);' % (structname, self.Name()),
+                 '  %s->%s_data = NULL;' % (structname, self.Name()),
+                 '  %s->%s_set = 0;' % (structname, self.Name()),
+                 '  %s->%s_length = 0;' % (structname, self.Name()),
+                 '}'
+                 ]
+
+        return code
+        
+    def CodeNew(self, name):
+        code  = ['%s->%s_data = NULL;' % (name, self._name),
+                 '%s->%s_length = 0;' % (name, self._name)]
+        code.extend(Entry.CodeNew(self, name))
+        return code
+
+    def CodeFree(self, name):
+        code  = ['if (%s->%s_data != NULL) {' % (name, self._name),
+                 '  int i;',
+                 '  for (i = 0; i < %s->%s_length; ++i) {' % (
+            name, self._name),
+                 '    %s_free(%s->%s_data[i]); ' % (
+            self._refname, name, self._name),
+                 '    %s->%s_data[i] = NULL;' % (name, self._name),
+                 '  }',
+                 '  free(%s->%s_data);' % (name, self._name),
+                 '  %s->%s_data = NULL;' % (name, self._name),
+                 '  %s->%s_length = 0;' % (name, self._name),
+                 '}'
+                 ]
+
+        return code
+
+    def Declaration(self):
+        dcl  = ['struct %s **%s_data;' % (self._refname, self._name),
+                'int %s_length;' % self._name]
+
+        return dcl
+
+def NormalizeLine(line):
+    global leading
+    global trailing
+    global white
+    global cppcomment
+    
+    line = cppcomment.sub('', line)
+    line = leading.sub('', line)
+    line = trailing.sub('', line)
+    line = white.sub(' ', line)
+
+    return line
+
+def ProcessOneEntry(newstruct, entry):
+    optional = 0
+    array = 0
+    type = ''
+    name = ''
+    tag = ''
+    tag_set = None
+    separator = ''
+    fixed_length = ''
+
+    tokens = entry.split(' ')
+    while tokens:
+        token = tokens[0]
+        tokens = tokens[1:]
+
+        if not type:
+            if not optional and token == 'optional':
+                optional = 1
+                continue
+
+            if not array and token == 'array':
+                array = 1
+                continue
+
+        if not type:
+            type = token
+            continue
+
+        if not name:
+            res = re.match(r'^([^\[\]]+)(\[.*\])?$', token)
+            if not res:
+                print >>sys.stderr, 'Cannot parse name: \"%s\" around %d' % (
+                    entry, line_count)
+                sys.exit(1)
+            name = res.group(1)
+            fixed_length = res.group(2)
+            if fixed_length:
+                fixed_length = fixed_length[1:-1]
+            continue
+
+        if not separator:
+            separator = token
+            if separator != '=':
+                print >>sys.stderr, 'Expected "=" after name \"%s\" got %s' % (
+                    name, token)
+                sys.exit(1)
+            continue
+
+        if not tag_set:
+            tag_set = 1
+            if not re.match(r'^[0-9]+$', token):
+                print >>sys.stderr, 'Expected tag number: \"%s\"' % entry
+                sys.exit(1)
+            tag = int(token)
+            continue
+
+        print >>sys.stderr, 'Cannot parse \"%s\"' % entry
+        sys.exit(1)
+
+    if not tag_set:
+        print >>sys.stderr, 'Need tag number: \"%s\"' % entry
+        sys.exit(1)
+
+    # Create the right entry
+    if type == 'bytes':
+        if fixed_length:
+            newentry = EntryBytes(type, name, tag, fixed_length)
+        else:
+            newentry = EntryVarBytes(type, name, tag)
+    elif type == 'int' and not fixed_length:
+        newentry = EntryInt(type, name, tag)
+    elif type == 'string' and not fixed_length:
+        newentry = EntryString(type, name, tag)
+    else:
+        res = re.match(r'^struct\[(%s)\]$' % _STRUCT_RE, type, re.IGNORECASE)
+        if res:
+            # References another struct defined in our file
+            newentry = EntryStruct(type, name, tag, res.group(1))
+        else:
+            print >>sys.stderr, 'Bad type: "%s" in "%s"' % (type, entry)
+            sys.exit(1)
+
+    structs = []
+        
+    if optional:
+        newentry.MakeOptional()
+    if array:
+        newentry.MakeArray()
+
+    newentry.SetStruct(newstruct)
+    newentry.SetLineCount(line_count)
+    newentry.Verify()
+
+    if array:
+        # We need to encapsulate this entry into a struct
+        newname = newentry.Name()+ '_array'
+
+        # Now borgify the new entry.
+        newentry = EntryArray(newentry)
+        newentry.SetStruct(newstruct)
+        newentry.SetLineCount(line_count)
+        newentry.MakeArray()
+
+    newstruct.AddEntry(newentry)
+
+    return structs
+
+def ProcessStruct(data):
+    tokens = data.split(' ')
+
+    # First three tokens are: 'struct' 'name' '{'
+    newstruct = Struct(tokens[1])
+
+    inside = ' '.join(tokens[3:-1])
+
+    tokens = inside.split(';')
+
+    structs = []
+
+    for entry in tokens:
+        entry = NormalizeLine(entry)
+        if not entry:
+            continue
+
+        # It's possible that new structs get defined in here
+        structs.extend(ProcessOneEntry(newstruct, entry))
+
+    structs.append(newstruct)
+    return structs
+
+def GetNextStruct(file):
+    global line_count
+    global cppdirect
+
+    got_struct = 0
+
+    processed_lines = []
+
+    have_c_comment = 0
+    data = ''
+    for line in file:
+        line_count += 1
+        line = line[:-1]
+
+        if not have_c_comment and re.search(r'/\*', line):
+            if re.search(r'/\*.*\*/', line):
+                line = re.sub(r'/\*.*\*/', '', line)
+            else:
+                line = re.sub(r'/\*.*$', '', line)
+                have_c_comment = 1
+
+        if have_c_comment:
+            if not re.search(r'\*/', line):
+                continue
+            have_c_comment = 0
+            line = re.sub(r'^.*\*/', '', line)
+
+        line = NormalizeLine(line)
+
+        if not line:
+            continue
+
+        if not got_struct:
+            if re.match(r'#include ["<].*[>"]', line):
+                cppdirect.append(line)
+                continue
+            
+            if re.match(r'^#(if( |def)|endif)', line):
+                cppdirect.append(line)
+                continue
+
+            if not re.match(r'^struct %s {$' % _STRUCT_RE,
+                            line, re.IGNORECASE):
+                print >>sys.stderr, 'Missing struct on line %d: %s' % (
+                    line_count, line)
+                sys.exit(1)
+            else:
+                got_struct = 1
+                data += line
+            continue
+
+        # We are inside the struct
+        tokens = line.split('}')
+        if len(tokens) == 1:
+            data += ' ' + line
+            continue
+
+        if len(tokens[1]):
+            print >>sys.stderr, 'Trailing garbage after struct on line %d' % (
+                line_count )
+            sys.exit(1)
+
+        # We found the end of the struct
+        data += ' %s}' % tokens[0]
+        break
+
+    # Remove any comments, that might be in there
+    data = re.sub(r'/\*.*\*/', '', data)
+    
+    return data
+        
+
+def Parse(file):
+    """Parses the input file and returns C code and corresponding header
+    file."""
+
+    entities = []
+
+    while 1:
+        # Just gets the whole struct nicely formatted
+        data = GetNextStruct(file)
+
+        if not data:
+            break
+
+        entities.extend(ProcessStruct(data))
+
+    return entities
+
+def GuardName(name):
+    name = '_'.join(name.split('.'))
+    name = '_'.join(name.split('/'))
+    guard = '_'+name.upper()+'_'
+
+    return guard
+
+def HeaderPreamble(name):
+    guard = GuardName(name)
+    pre = (
+        '/*\n'
+        ' * Automatically generated from %s\n'
+        ' */\n\n'
+        '#ifndef %s\n'
+        '#define %s\n\n' ) % (
+        name, guard, guard)
+    pre += (
+        '#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)\n'
+        '#define EVTAG_ASSIGN(msg, member, args...) '
+        '(*(msg)->member##_assign)(msg, ## args)\n'
+        '#define EVTAG_GET(msg, member, args...) '
+        '(*(msg)->member##_get)(msg, ## args)\n'
+        '#define EVTAG_ADD(msg, member) (*(msg)->member##_add)(msg)\n'
+        '#define EVTAG_LEN(msg, member) ((msg)->member##_length)\n'
+        )
+
+    return pre
+     
+
+def HeaderPostamble(name):
+    guard = GuardName(name)
+    return '#endif  /* %s */' % guard
+
+def BodyPreamble(name):
+    global _NAME
+    global _VERSION
+    
+    header_file = '.'.join(name.split('.')[:-1]) + '.gen.h'
+
+    pre = ( '/*\n'
+            ' * Automatically generated from %s\n'
+            ' * by %s/%s.  DO NOT EDIT THIS FILE.\n'
+            ' */\n\n' ) % (name, _NAME, _VERSION)
+    pre += ( '#include <sys/types.h>\n'
+             '#include <sys/time.h>\n'
+             '#include <stdlib.h>\n'
+             '#include <string.h>\n'
+             '#include <assert.h>\n'
+             '#include <event.h>\n\n' )
+
+    for include in cppdirect:
+        pre += '%s\n' % include
+    
+    pre += '\n#include "%s"\n\n' % header_file
+
+    pre += 'void event_err(int eval, const char *fmt, ...);\n'
+    pre += 'void event_warn(const char *fmt, ...);\n'
+    pre += 'void event_errx(int eval, const char *fmt, ...);\n'
+    pre += 'void event_warnx(const char *fmt, ...);\n\n'
+
+    return pre
+
+def main(argv):
+    filename = argv[1]
+
+    if filename.split('.')[-1] != 'rpc':
+        ext = filename.split('.')[-1]
+        print >>sys.stderr, 'Unrecognized file extension: %s' % ext
+        sys.exit(1)
+
+    print >>sys.stderr, 'Reading \"%s\"' % filename
+
+    fp = open(filename, 'r')
+    entities = Parse(fp)
+    fp.close()
+
+    header_file = '.'.join(filename.split('.')[:-1]) + '.gen.h'
+    impl_file = '.'.join(filename.split('.')[:-1]) + '.gen.c'
+
+    print >>sys.stderr, '... creating "%s"' % header_file
+    header_fp = open(header_file, 'w')
+    print >>header_fp, HeaderPreamble(filename)
+
+    # Create forward declarations: allows other structs to reference
+    # each other
+    for entry in entities:
+        entry.PrintForwardDeclaration(header_fp)
+    print >>header_fp, ''
+
+    for entry in entities:
+        entry.PrintTags(header_fp)
+        entry.PrintDeclaration(header_fp)
+    print >>header_fp, HeaderPostamble(filename)
+    header_fp.close()
+
+    print >>sys.stderr, '... creating "%s"' % impl_file
+    impl_fp = open(impl_file, 'w')
+    print >>impl_fp, BodyPreamble(filename)
+    for entry in entities:
+        entry.PrintCode(impl_fp)
+    impl_fp.close()
+
+if __name__ == '__main__':
+    main(sys.argv)


Property changes on: trunk/varnish-cache/contrib/libevent/event_rpcgen.py
___________________________________________________________________
Name: svn:executable
   + *
Name: svn:mime-type
   + text/script

Added: trunk/varnish-cache/contrib/libevent/event_tagging.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/event_tagging.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/event_tagging.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2003, 2004 Niels Provos <provos at citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/types.h>
+#include <sys/param.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/tree.h>
+#include <sys/queue.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+#include "event.h"
+
+int decode_int(u_int32_t *pnumber, struct evbuffer *evbuf);
+
+static struct evbuffer *_buf;
+
+void
+evtag_init()
+{
+	if ((_buf = evbuffer_new()) == NULL)
+		err(1, "%s: malloc", __func__);
+}
+
+/* 
+ * We encode integer's by nibbles; the first nibble contains the number
+ * of significant nibbles - 1;  this allows us to encode up to 64-bit
+ * integers.  This function is byte-order independent.
+ */
+
+void
+encode_int(struct evbuffer *evbuf, u_int32_t number)
+{
+	int off = 1, nibbles = 0;
+	u_int8_t data[5];
+
+	memset(data, 0, sizeof(data));
+	while (number) {
+		if (off & 0x1)
+			data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f);
+		else
+			data[off/2] = (data[off/2] & 0x0f) |
+			    ((number & 0x0f) << 4);
+		number >>= 4;
+		off++;
+	}
+
+	if (off > 2)
+		nibbles = off - 2;
+
+	/* Off - 1 is the number of encoded nibbles */
+	data[0] = (data[0] & 0x0f) | ((nibbles & 0x0f) << 4);
+
+	evbuffer_add(evbuf, data, (off + 1) / 2);
+}
+
+/*
+ * Marshal a data type, the general format is as follows:
+ *
+ * tag number: one byte; length: var bytes; payload: var bytes
+ */
+
+void
+evtag_marshal(struct evbuffer *evbuf, u_int8_t tag,
+    const void *data, u_int16_t len)
+{
+	evbuffer_add(evbuf, &tag, sizeof(tag));
+	encode_int(evbuf, len);
+	evbuffer_add(evbuf, (void *)data, len);
+}
+
+/* Marshaling for integers */
+void
+evtag_marshal_int(struct evbuffer *evbuf, u_int8_t tag, u_int32_t integer)
+{
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+	encode_int(_buf, integer);
+
+	evbuffer_add(evbuf, &tag, sizeof(tag));
+	encode_int(evbuf, EVBUFFER_LENGTH(_buf));
+	evbuffer_add_buffer(evbuf, _buf);
+}
+
+void
+evtag_marshal_string(struct evbuffer *buf, u_int8_t tag, const char *string)
+{
+	evtag_marshal(buf, tag, string, strlen(string));
+}
+
+void
+evtag_marshal_timeval(struct evbuffer *evbuf, u_int8_t tag, struct timeval *tv)
+{
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+	encode_int(_buf, tv->tv_sec);
+	encode_int(_buf, tv->tv_usec);
+
+	evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf),
+	    EVBUFFER_LENGTH(_buf));
+}
+
+static int __inline
+decode_int_internal(u_int32_t *pnumber, struct evbuffer *evbuf, int dodrain)
+{
+	u_int32_t number = 0;
+	u_int8_t *data = EVBUFFER_DATA(evbuf);
+	int len = EVBUFFER_LENGTH(evbuf);
+	int nibbles = 0, off;
+
+	if (!len)
+		return (-1);
+
+	nibbles = ((data[0] & 0xf0) >> 4) + 1;
+	if (nibbles > 8 || (nibbles >> 1) > len - 1)
+		return (-1);
+
+	off = nibbles;
+	while (off > 0) {
+		number <<= 4;
+		if (off & 0x1)
+			number |= data[off >> 1] & 0x0f;
+		else
+			number |= (data[off >> 1] & 0xf0) >> 4;
+		off--;
+	}
+
+	len = (nibbles >> 1) + 1;
+	if (dodrain)
+		evbuffer_drain(evbuf, len);
+
+	*pnumber = number;
+
+	return (len);
+}
+
+int
+decode_int(u_int32_t *pnumber, struct evbuffer *evbuf)
+{
+	return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
+}
+
+int
+evtag_peek(struct evbuffer *evbuf, u_int8_t *ptag)
+{
+	if (EVBUFFER_LENGTH(evbuf) < 2)
+		return (-1);
+	*ptag = EVBUFFER_DATA(evbuf)[0];
+
+	return (0);
+}
+
+int
+evtag_peek_length(struct evbuffer *evbuf, u_int32_t *plength)
+{
+	struct evbuffer tmp;
+	int res;
+
+	if (EVBUFFER_LENGTH(evbuf) < 2)
+		return (-1);
+
+	tmp = *evbuf;
+	tmp.buffer += 1;
+	tmp.off -= 1;
+
+	res = decode_int_internal(plength, &tmp, 0);
+	if (res == -1)
+		return (-1);
+
+	*plength += res + 1;
+
+	return (0);
+}
+
+int
+evtag_payload_length(struct evbuffer *evbuf, u_int32_t *plength)
+{
+	struct evbuffer tmp;
+	int res;
+
+	if (EVBUFFER_LENGTH(evbuf) < 2)
+		return (-1);
+
+	tmp = *evbuf;
+	tmp.buffer += 1;
+	tmp.off -= 1;
+
+	res = decode_int_internal(plength, &tmp, 0);
+	if (res == -1)
+		return (-1);
+
+	return (0);
+}
+
+int
+evtag_consume(struct evbuffer *evbuf)
+{
+	u_int32_t len;
+	evbuffer_drain(evbuf, 1);
+	if (decode_int(&len, evbuf) == -1)
+		return (-1);
+	evbuffer_drain(evbuf, len);
+
+	return (0);
+}
+
+/* Reads the data type from an event buffer */
+
+int
+evtag_unmarshal(struct evbuffer *src, u_int8_t *ptag, struct evbuffer *dst)
+{
+	u_int8_t tag;
+	u_int16_t len;
+	u_int32_t integer;
+
+	if (evbuffer_remove(src, &tag, sizeof(tag)) != sizeof(tag))
+		return (-1);
+	if (decode_int(&integer, src) == -1)
+		return (-1);
+	len = integer;
+
+	if (EVBUFFER_LENGTH(src) < len)
+		return (-1);
+
+	if (evbuffer_add(dst, EVBUFFER_DATA(src), len) == -1)
+		return (-1);
+
+	evbuffer_drain(src, len);
+
+	*ptag = tag;
+	return (len);
+}
+
+/* Marshaling for integers */
+
+int
+evtag_unmarshal_int(struct evbuffer *evbuf, u_int8_t need_tag,
+    u_int32_t *pinteger)
+{
+	u_int8_t tag;
+	u_int16_t len;
+	u_int32_t integer;
+
+	if (evbuffer_remove(evbuf, &tag, sizeof(tag)) != sizeof(tag) ||
+	    tag != need_tag)
+		return (-1);
+	if (decode_int(&integer, evbuf) == -1)
+		return (-1);
+	len = integer;
+
+	if (EVBUFFER_LENGTH(evbuf) < len)
+		return (-1);
+	
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+	if (evbuffer_add(_buf, EVBUFFER_DATA(evbuf), len) == -1)
+		return (-1);
+
+	evbuffer_drain(evbuf, len);
+
+	return (decode_int(pinteger, _buf));
+}
+
+/* Unmarshal a fixed length tag */
+
+int
+evtag_unmarshal_fixed(struct evbuffer *src, u_int8_t need_tag, void *data,
+    size_t len)
+{
+	u_int8_t tag;
+
+	/* Initialize this event buffer so that we can read into it */
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+	/* Now unmarshal a tag and check that it matches the tag we want */
+	if (evtag_unmarshal(src, &tag, _buf) == -1 || tag != need_tag)
+		return (-1);
+
+	if (EVBUFFER_LENGTH(_buf) != len)
+		return (-1);
+
+	memcpy(data, EVBUFFER_DATA(_buf), len);
+	return (0);
+}
+
+int
+evtag_unmarshal_string(struct evbuffer *evbuf, u_int8_t need_tag,
+    char **pstring)
+{
+	u_int8_t tag;
+
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+
+	if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
+		return (-1);
+
+	*pstring = calloc(EVBUFFER_LENGTH(_buf) + 1, 1);
+	if (*pstring == NULL)
+		err(1, "%s: calloc", __func__);
+	evbuffer_remove(_buf, *pstring, EVBUFFER_LENGTH(_buf));
+
+	return (0);
+}
+
+int
+evtag_unmarshal_timeval(struct evbuffer *evbuf, u_int8_t need_tag,
+    struct timeval *ptv)
+{
+	u_int8_t tag;
+	u_int32_t integer;
+
+	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
+	if (evtag_unmarshal(evbuf, &tag, _buf) == -1 || tag != need_tag)
+		return (-1);
+
+	if (decode_int(&integer, _buf) == -1)
+		return (-1);
+	ptv->tv_sec = integer;
+	if (decode_int(&integer, _buf) == -1)
+		return (-1);
+	ptv->tv_usec = integer;
+
+	return (0);
+}

Added: trunk/varnish-cache/contrib/libevent/http.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/http.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/http.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,1492 @@
+/*
+ * Copyright (c) 2002-2006 Niels Provos <provos at citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#include <sys/param.h>
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/tree.h>
+#include <sys/wait.h>
+#include <sys/queue.h>
+
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <signal.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include <unistd.h>
+#include <getopt.h>
+#include <fcntl.h>
+
+#undef timeout_pending
+#undef timeout_initialized
+
+#include "event.h"
+#include "log.h"
+#include "http.h"
+
+extern int debug;
+
+static int make_socket_ai(int (*f)(int, const struct sockaddr *, socklen_t),
+    struct addrinfo *);
+static int make_socket(int (*)(int, const struct sockaddr *, socklen_t),
+    const char *, short);
+static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
+
+void evhttp_write(int, short, void *);
+
+static const char *
+html_replace(char ch)
+{
+	static char buf[2];
+	
+	switch (ch) {
+	case '<':
+		return "&lt;";
+	case '>':
+		return "&gt;";
+	case '"':
+		return "&quot;";
+	case '\'':
+		return "&#039;";
+	case '&':
+		return "&amp;";
+	default:
+		break;
+	}
+
+	/* Echo the character back */
+	buf[0] = ch;
+	buf[1] = '\0';
+	
+	return buf;
+}
+
+/*
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ */
+
+char *
+evhttp_htmlescape(const char *html)
+{
+	int i, new_size = 0;
+	char *escaped_html, *p;
+	
+	for (i = 0; i < strlen(html); ++i)
+		new_size += strlen(html_replace(html[i]));
+
+	p = escaped_html = malloc(new_size + 1);
+	if (escaped_html == NULL)
+		event_err(1, "%s: malloc(%d)", __func__, new_size + 1);
+	for (i = 0; i < strlen(html); ++i) {
+		const char *replaced = html_replace(html[i]);
+		/* this is length checked */
+		strcpy(p, replaced);
+		p += strlen(replaced);
+	}
+
+	*p = '\0';
+
+	return (escaped_html);
+}
+
+const char *
+evhttp_method(enum evhttp_cmd_type type)
+{
+	const char *method;
+
+	switch (type) {
+	case EVHTTP_REQ_GET:
+		method = "GET";
+		break;
+	case EVHTTP_REQ_POST:
+		method = "POST";
+		break;
+	case EVHTTP_REQ_HEAD:
+		method = "HEAD";
+		break;
+	default:
+		method = NULL;
+		break;
+	}
+
+	return (method);
+}
+
+void
+evhttp_form_response(struct evbuffer *buf, struct evhttp_request *req)
+{
+	/* Clean out the buffer */
+	evbuffer_drain(buf, buf->off);
+
+	/* Create the header fields */
+	evhttp_make_header(buf, req);
+
+	/* Append the response buffer */
+	evbuffer_add(buf,
+	    EVBUFFER_DATA(req->buffer), EVBUFFER_LENGTH(req->buffer));
+}
+
+void
+evhttp_write_buffer(struct evhttp_request *req, struct evbuffer *buffer,
+    void (*cb)(struct evhttp_request *, void *), void *arg)
+{
+	struct timeval tv;
+
+	event_debug(("%s: preparing to write buffer\n", __func__));
+
+	if (req->buffer != buffer) {
+		if (req->buffer != NULL)
+			evbuffer_free(req->buffer);
+		req->buffer = buffer;
+	}
+
+	/* Set call back */
+
+	req->cb = cb;
+	req->cb_arg = arg;
+
+	event_set(&req->ev, req->fd, EV_WRITE, evhttp_write, req);
+	timerclear(&tv);
+	tv.tv_sec = HTTP_WRITE_TIMEOUT;
+	event_add(&req->ev, &tv);
+}
+
+/*
+ * Create the headers need for an HTTP reply
+ */
+static void
+evhttp_make_header_request(struct evbuffer *buf, struct evhttp_request *req)
+{
+	static char line[1024];
+	const char *method;
+	
+	evhttp_remove_header(req->output_headers, "Accept-Encoding");
+	evhttp_remove_header(req->output_headers, "Proxy-Connection");
+	evhttp_remove_header(req->output_headers, "Connection");
+	evhttp_add_header(req->output_headers, "Connection", "close");
+	req->minor = 0;
+
+	/* Generate request line */
+	method = evhttp_method(req->type);
+	snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n",
+	    method, req->uri, req->major, req->minor);
+	evbuffer_add(buf, line, strlen(line));
+
+	/* Add the content length on a post request if missing */
+	if (req->type == EVHTTP_REQ_POST &&
+	    evhttp_find_header(req->output_headers, "Content-Length") == NULL){
+		char size[12];
+		snprintf(size, sizeof(size), "%d",
+		    EVBUFFER_LENGTH(req->buffer));
+		evhttp_add_header(req->output_headers, "Content-Length", size);
+	}
+}
+
+/*
+ * Create the headers needed for an HTTP reply
+ */
+static void
+evhttp_make_header_response(struct evbuffer *buf, struct evhttp_request *req)
+{
+	static char line[1024];
+	snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
+	    req->major, req->minor, req->response_code,
+	    req->response_code_line);
+	evbuffer_add(buf, line, strlen(line));
+
+	/* Potentially add headers */
+	if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
+		evhttp_add_header(req->output_headers,
+		    "Content-Type", "text/html; charset=ISO-8859-1");
+	}
+}
+
+void
+evhttp_make_header(struct evbuffer *buf, struct evhttp_request *req)
+{
+	static char line[1024];
+	struct evkeyval *header;
+
+	/*
+	 * Depending if this is a HTTP request or response, we might need to
+	 * add some new headers or remove existing headers.
+	 */
+	if (req->kind == EVHTTP_REQUEST) {
+		evhttp_make_header_request(buf, req);
+	} else {
+		evhttp_make_header_response(buf, req);
+	}
+
+	TAILQ_FOREACH(header, req->output_headers, next) {
+		snprintf(line, sizeof(line), "%s: %s\r\n",
+		    header->key, header->value);
+		evbuffer_add(buf, line, strlen(line));
+	}
+	evbuffer_add(buf, "\r\n", 2);
+
+	if (req->kind == EVHTTP_REQUEST) {
+		int len = EVBUFFER_LENGTH(req->buffer);
+
+		/* Add the POST data */
+		if (len > 0)
+			evbuffer_add(buf, EVBUFFER_DATA(req->buffer), len);
+	}
+}
+
+/* Separated host, port and file from URI */
+
+int
+evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile)
+{
+	static char host[1024];
+	static char file[1024];
+	char *p, *p2;
+	int len;
+	u_short port;
+
+	len = strlen(HTTP_PREFIX);
+	if (strncasecmp(url, HTTP_PREFIX, len))
+		return (-1);
+
+	url += len;
+
+	/* We might overrun */
+	if (strlcpy(host, url, sizeof (host)) >= sizeof(host))
+		return (-1);
+
+	p = strchr(host, '/');
+	if (p != NULL) {
+		*p = '\0';
+		p2 = p + 1;
+	} else
+		p2 = NULL;
+
+	if (pfile != NULL) {
+		/* Generate request file */
+		if (p2 == NULL)
+			p2 = "";
+		snprintf(file, sizeof(file), "/%s", p2);
+	}
+
+	p = strchr(host, ':');
+	if (p != NULL) {
+		*p = '\0';
+		port = atoi(p + 1);
+
+		if (port == 0)
+			return (-1);
+	} else
+		port = HTTP_DEFAULTPORT;
+
+	if (phost != NULL)
+		*phost = host;
+	if (pport != NULL)
+		*pport = port;
+	if (pfile != NULL)
+		*pfile = file;
+
+	return (0);
+}
+
+void
+evhttp_fail(struct evhttp_request *req)
+{
+	evhttp_request_free(req);
+}
+
+void
+evhttp_write(int fd, short what, void *arg)
+{
+	struct evhttp_request *req = arg;
+	struct timeval tv;
+	int n;
+
+	if (what == EV_TIMEOUT) {
+		evhttp_fail(req);
+		return;
+	}
+
+	n = evbuffer_write(req->buffer, fd);
+	if (n == -1) {
+		event_warn("%s: evbuffer_write", __func__);
+		evhttp_fail(req);
+		return;
+	}
+
+	if (n == 0) {
+		event_warnx("%s: write nothing\n", __func__);
+		evhttp_fail(req);
+		return;
+	}
+
+	if (EVBUFFER_LENGTH(req->buffer) != 0) {
+		timerclear(&tv);
+		tv.tv_sec = HTTP_WRITE_TIMEOUT;
+		event_add(&req->ev, &tv);
+		return;
+	}
+
+	/* Activate our call back */
+	(*req->cb)(req, req->cb_arg);
+}
+
+/*
+ * Reads data into a buffer structure until no more data
+ * can be read on the file descriptor or we have read all
+ * the data that we wanted to read.
+ * Execute callback when done.
+ */
+
+void
+evhttp_read(int fd, short what, void *arg)
+{
+	struct evhttp_request *req = arg;
+	struct timeval tv;
+	int n;
+
+	if (what == EV_TIMEOUT) {
+		evhttp_fail(req);
+		return;
+	}
+
+	n = evbuffer_read(req->buffer, fd, req->ntoread);
+	event_debug(("%s: got %d on %d\n", __func__, n, req->fd));
+
+	if (n == -1) {
+		event_warn("%s: evbuffer_read", __func__);
+		evhttp_fail(req);
+	}
+
+	/* Adjust the amount of data that we have left to read */
+	if (req->ntoread > 0)
+		req->ntoread -= n;
+
+	if (n == 0 || req->ntoread == 0) {
+		(*req->cb)(req, req->cb_arg);
+		return;
+	}
+
+	timerclear(&tv);
+	tv.tv_sec = HTTP_READ_TIMEOUT;
+	event_add(&req->ev, &tv);
+}
+
+void
+evhttp_write_requestcb(struct evhttp_request *req, void *arg)
+{
+	/* Restore the original callbacks */
+	req->cb = req->save_cb;
+	req->cb_arg = req->save_cbarg;
+
+	/* This is after writing the request to the server */
+
+	/* We are done writing our header and are now expecting the response */
+	req->kind = EVHTTP_RESPONSE;
+
+	evhttp_start_read(req);
+}
+
+/*
+ * Clean up a connection object
+ */
+
+void
+evhttp_connection_free(struct evhttp_connection *evcon)
+{
+	event_del(&evcon->ev);
+	
+	if (evcon->fd != -1)
+		close(evcon->fd);
+
+	if (evcon->address != NULL)
+		free(evcon->address);
+
+	free(evcon);
+}
+
+/*
+ * Call back for asynchronous connection attempt.
+ */
+
+void
+evhttp_connectioncb(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	int error;
+	socklen_t errsz = sizeof(error);
+		
+	if (what == EV_TIMEOUT) {
+		event_warnx("%s: connection timeout for \"%s:%d\" on %d\n",
+		    __func__, evcon->address, evcon->port, evcon->fd);
+		goto cleanup;
+	}
+
+	/* Check if the connection completed */
+	if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, &error,
+		       &errsz) == -1) {
+		event_warn("%s: getsockopt for \"%s:%d\" on %d",
+		    __func__, evcon->address, evcon->port, evcon->fd);
+		goto cleanup;
+	}
+
+	if (error) {
+		event_warnx("%s: connect failed for \"%s:%d\" on %d: %s\n",
+		    __func__, evcon->address, evcon->port, evcon->fd,
+		    strerror(error));
+		goto cleanup;
+	}
+
+	/* We are connected to the server now */
+	event_debug(("%s: connected to \"%s:%d\" on %d\n",
+			__func__, evcon->address, evcon->port, evcon->fd));
+
+	/* We are turning the connection object over to the user */
+	(*evcon->cb)(evcon, evcon->cb_arg);
+	return;
+
+ cleanup:
+	/* Signal error to the user */
+	(*evcon->cb)(NULL, evcon->cb_arg);
+
+	evhttp_connection_free(evcon);
+	return;
+}
+
+/*
+ * Check if we got a valid response code.
+ */
+
+int
+evhttp_valid_response_code(int code)
+{
+	if (code == 0)
+		return (0);
+
+	return (1);
+}
+
+/* Parses the status line of a web server */
+
+int
+evhttp_parse_response_line(struct evhttp_request *req, char *line)
+{
+	char *protocol;
+	char *number;
+	char *readable;
+
+	protocol = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	number = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	readable = line;
+
+	if (strcmp(protocol, "HTTP/1.0") == 0) {
+		req->major = 1;
+		req->minor = 0;
+	} else if (strcmp(protocol, "HTTP/1.1") == 0) {
+		req->major = 1;
+		req->minor = 1;
+	} else {
+		event_warnx("%s: bad protocol \"%s\" on %d\n",
+		    __func__, protocol, req->fd);
+		return (-1);
+	}
+
+	req->response_code = atoi(number);
+	if (!evhttp_valid_response_code(req->response_code)) {
+		event_warnx("%s: bad response code \"%s\" on %d\n",
+		    __func__, number, req->fd);
+		return (-1);
+	}
+
+	if ((req->response_code_line = strdup(readable)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+
+	return (0);
+}
+
+/* Parse the first line of a HTTP request */
+
+int
+evhttp_parse_request_line(struct evhttp_request *req, char *line)
+{
+	char *method;
+	char *uri;
+	char *version;
+
+	/* Parse the request line */
+	method = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	uri = strsep(&line, " ");
+	if (line == NULL)
+		return (-1);
+	version = strsep(&line, " ");
+	if (line != NULL)
+		return (-1);
+
+	/* First line */
+	if (strcmp(method, "GET") == 0) {
+		req->type = EVHTTP_REQ_GET;
+	} else if (strcmp(method, "POST") == 0) {
+		req->type = EVHTTP_REQ_POST;
+	} else if (strcmp(method, "HEAD") == 0) {
+		req->type = EVHTTP_REQ_HEAD;
+	} else {
+		event_warnx("%s: bad method %s on fd %d\n",
+		    __func__, method, req->fd);
+		return (-1);
+	}
+
+	if (strcmp(version, "HTTP/1.0") == 0) {
+		req->major = 1;
+		req->minor = 0;
+	} else if (strcmp(version, "HTTP/1.1") == 0) {
+		req->major = 1;
+		req->minor = 1;
+	} else {
+		event_warnx("%s: bad version %s on %d\n",
+		    __func__, version, req->fd);
+		return (-1);
+	}
+
+	if ((req->uri = strdup(uri)) == NULL) {
+		event_warn("%s: strdup", __func__);
+		return (-1);
+	}
+
+	return (0);
+}
+
+const char *
+evhttp_find_header(struct evkeyvalq *headers, const char *key)
+{
+	struct evkeyval *header;
+
+	TAILQ_FOREACH(header, headers, next) {
+		if (strcasecmp(header->key, key) == 0)
+			return (header->value);
+	}
+
+	return (NULL);
+}
+
+void
+evhttp_clear_headers(struct evkeyvalq *headers)
+{
+	struct evkeyval *header;
+
+	for (header = TAILQ_FIRST(headers);
+	    header != NULL;
+	    header = TAILQ_FIRST(headers)) {
+		TAILQ_REMOVE(headers, header, next);
+		free(header->key);
+		free(header->value);
+		free(header);
+	}
+}
+
+/*
+ * Returns 0,  if the header was successfully removed.
+ * Returns -1, if the header could not be found.
+ */
+
+int
+evhttp_remove_header(struct evkeyvalq *headers, const char *key)
+{
+	struct evkeyval *header;
+
+	TAILQ_FOREACH(header, headers, next) {
+		if (strcasecmp(header->key, key) == 0)
+			break;
+	}
+
+	if (header == NULL)
+		return (-1);
+
+	/* Free and remove the header that we found */
+	TAILQ_REMOVE(headers, header, next);
+	free(header->key);
+	free(header->value);
+	free(header);
+
+	return (0);
+}
+
+int
+evhttp_add_header(struct evkeyvalq *headers, const char *key, const char *value)
+{
+	struct evkeyval *header;
+
+	header = calloc(1, sizeof(struct evkeyval));
+	if (header == NULL) {
+		event_warn("%s: calloc", __func__);
+		return (-1);
+	}
+	if ((header->key = strdup(key)) == NULL) {
+		free(header);
+		event_warn("%s: strdup", __func__);
+		return (-1);
+	}
+	if ((header->value = strdup(value)) == NULL) {
+		free(header->key);
+		free(header);
+		event_warn("%s: strdup", __func__);
+		return (-1);
+	}
+
+	TAILQ_INSERT_TAIL(headers, header, next);
+
+	return (0);
+}
+
+/*
+ * Parses header lines from a request or a response into the specified
+ * request object given an event buffer.
+ *
+ * Returns
+ *   -1  on error
+ *    0  when we need to read more headers
+ *    1  when all headers have been read.
+ */
+
+int
+evhttp_parse_lines(struct evhttp_request *req, struct evbuffer* buffer)
+{
+	u_char *endp;
+	int done = 0;
+
+	struct evkeyvalq* headers = req->input_headers;
+	while ((endp = evbuffer_find(buffer, "\r\n", 2)) != NULL) {
+		char *skey, *svalue;
+
+		if (strncmp(EVBUFFER_DATA(buffer), "\r\n", 2) == 0) {
+			evbuffer_drain(buffer, 2);
+			/* Last header - Done */
+			done = 1;
+			break;
+		}
+
+		*endp = '\0';
+		endp += 2;
+
+		event_debug(("%s: Got: %s\n", __func__, EVBUFFER_DATA(buffer)));
+
+		/* Processing of header lines */
+		if (req->got_firstline == 0) {
+			switch (req->kind) {
+			case EVHTTP_REQUEST:
+				if (evhttp_parse_request_line(req, EVBUFFER_DATA(buffer)) == -1)
+					return (-1);
+				break;
+			case EVHTTP_RESPONSE:
+				if (evhttp_parse_response_line(req, EVBUFFER_DATA(buffer)) == -1)
+					return (-1);
+				break;
+			default:
+				return (-1);
+			}
+			req->got_firstline = 1;
+		} else {
+			/* Regular header */
+			svalue = EVBUFFER_DATA(buffer);
+			skey = strsep(&svalue, ":");
+			if (svalue == NULL)
+				return (-1);
+
+			svalue += strspn(svalue, " ");
+
+			if (evhttp_add_header(headers, skey, svalue) == -1)
+				return (-1);
+		}
+
+		/* Move the uncompleted headers forward */
+		evbuffer_drain(buffer, endp - EVBUFFER_DATA(buffer));
+	}
+
+	return (done);
+}
+
+void
+evhttp_get_body(struct evhttp_request *req)
+{
+	struct timeval tv;
+	const char *content_length;
+	const char *connection;
+	struct evkeyvalq *headers = req->input_headers;
+	
+	/* If this is a request without a body, then we are done */
+	if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) {
+		(*req->cb)(req, req->cb_arg);
+		return;
+	}
+
+	content_length = evhttp_find_header(headers, "Content-Length");
+	connection = evhttp_find_header(headers, "Connection");
+
+	if (content_length == NULL && connection == NULL)
+		req->ntoread = -1;
+	else if (content_length == NULL &&
+	    strcasecmp(connection, "Close") != 0) {
+		/* Bad combination, we don't know when it will end */
+		event_warnx("%s: we got no content length, but the server"
+		    " wants to keep the connection open: %s.\n",
+		    __func__, connection);
+		evhttp_fail(req);
+		return;
+	} else if (content_length == NULL)
+		req->ntoread = -1;
+	else
+		req->ntoread = atoi(content_length);
+
+	event_debug(("%s: bytes to read: %d (in buffer %d)\n",
+			__func__, req->ntoread, EVBUFFER_LENGTH(req->buffer)));
+	
+	if (req->ntoread > 0)
+		req->ntoread -= EVBUFFER_LENGTH(req->buffer);
+
+	if (req->ntoread == 0) {
+		(*req->cb)(req, req->cb_arg);
+		return;
+	}
+
+	event_set(&req->ev, req->fd, EV_READ, evhttp_read, req);
+	timerclear(&tv);
+	tv.tv_sec = HTTP_READ_TIMEOUT;
+	event_add(&req->ev, &tv);
+}
+
+void
+evhttp_read_header(int fd, short what, void *arg)
+{
+	struct timeval tv;
+	struct evhttp_request *req = arg;
+	int n, res;
+
+	if (what == EV_TIMEOUT) {
+		event_warnx("%s: timeout on %d\n", __func__, fd);
+		evhttp_request_free(req);
+		return;
+	}
+
+	n = evbuffer_read(req->buffer, fd, -1);
+	if (n == 0) {
+		event_warnx("%s: no more data on %d\n", __func__, fd);
+		evhttp_request_free(req);
+		return;
+	}
+	if (n == -1) {
+		event_warnx("%s: bad read on %d\n", __func__, fd);
+		evhttp_request_free(req);
+		return;
+	}
+
+	res = evhttp_parse_lines(req, req->buffer);
+	if (res == -1) {
+		/* Error while reading, terminate */
+		event_warnx("%s: bad header lines on %d\n", __func__, fd);
+		evhttp_request_free(req);
+		return;
+	} else if (res == 0) {
+		/* Need more header lines */
+		timerclear(&tv);
+		tv.tv_sec = HTTP_READ_TIMEOUT;
+		event_add(&req->ev, &tv);
+		return;
+	}
+
+	/* Done reading headers, do the real work */
+	switch (req->kind) {
+	case EVHTTP_REQUEST:
+		event_debug(("%s: checking for post data on %d\n",
+				__func__, req->fd));
+		evhttp_get_body(req);
+		break;
+
+	case EVHTTP_RESPONSE:
+		event_debug(("%s: starting to read body for \"%s\" on %d\n",
+				__func__, req->remote_host, req->fd));
+		evhttp_get_body(req);
+		break;
+
+	default:
+		event_warnx("%s: bad header on %d\n", __func__, fd);
+		evhttp_fail(req);
+		break;
+	}
+}
+
+/*
+ * Creates a TCP connection to the specified port and executes a callback
+ * when finished.  Failure or sucess is indicate by the passed connection
+ * object.
+ *
+ * Although this interface accepts a hostname, it is intended to take
+ * only numeric hostnames so that non-blocking DNS resolution can
+ * happen elsewhere.
+ */
+
+struct evhttp_connection *
+evhttp_connect(const char *address, unsigned short port,
+    void (*cb)(struct evhttp_connection *, void *), void *cb_arg)
+{
+	struct evhttp_connection *evcon = NULL;
+	struct timeval tv;
+	
+	event_debug(("Attempting connection to %s:%d\n", address, port));
+
+	if ((evcon = calloc(1, sizeof(struct evhttp_connection))) == NULL) {
+		event_warn("%s: calloc failed", __func__);
+		goto error;
+	}
+
+	evcon->fd = -1;
+	evcon->port = port;
+	if ((evcon->address = strdup(address)) == NULL) {
+		event_warn("%s: strdup failed", __func__);
+		goto error;
+	}
+	
+	/* Let the user name when something interesting happened */
+	evcon->cb = cb;
+	evcon->cb_arg = cb_arg;
+	
+	/* Do async connection to HTTP server */
+	if ((evcon->fd = make_socket(connect, address, port)) == -1) {
+		event_warn("%s: failed to connect to \"%s:%d\"",
+		    __func__, address, port);
+		goto error;
+	}
+
+	/* Set up a callback for successful connection setup */
+	event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon);
+	timerclear(&tv);
+	tv.tv_sec = HTTP_CONNECT_TIMEOUT;
+	event_add(&evcon->ev, &tv);
+
+	return (evcon);
+
+ error:
+	if (evcon != NULL)
+		evhttp_connection_free(evcon);
+	return (NULL);
+}
+
+/*
+ * Starts an HTTP request on the provided evhttp_connection object.
+ *
+ * In theory we might use this to queue requests on the connection
+ * object.
+ */
+
+int
+evhttp_make_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req,
+    enum evhttp_cmd_type type, const char *uri)
+{
+	struct evbuffer *evbuf = evbuffer_new();
+
+	if (evbuf == NULL)
+		return (-1);
+
+	/* We are making a request */
+	req->fd = evcon->fd;
+	req->kind = EVHTTP_REQUEST;
+	req->type = type;
+	if (req->uri != NULL)
+		free(req->uri);
+	if ((req->uri = strdup(uri)) == NULL)
+		goto error;
+
+	/* Set the protocol version if it is not supplied */
+	if (!req->major && !req->minor) {
+		req->major = 1;
+		req->minor = 1;
+	}
+	
+	/* Create the header from the store arguments */
+	evhttp_make_header(evbuf, req);
+
+	/* Schedule the write */
+	req->save_cb = req->cb;
+	req->save_cbarg = req->cb_arg;
+
+	/* evbuf is being freed when the request finishes */
+	evhttp_write_buffer(req, evbuf, evhttp_write_requestcb, NULL);
+	return (0);
+
+ error:
+	evbuffer_free(evbuf);
+	return (-1);
+}
+
+/*
+ * Reads data from file descriptor into request structure
+ * Request structure needs to be set up correctly.
+ */
+
+void
+evhttp_start_read(struct evhttp_request *req)
+{
+	struct timeval tv;
+
+	/* Set up an event to read the headers */
+	event_set(&req->ev, req->fd, EV_READ, evhttp_read_header, req);
+
+	timerclear(&tv);
+	tv.tv_sec = HTTP_READ_TIMEOUT;
+	event_add(&req->ev, &tv);
+}
+
+void
+evhttp_send_done(struct evhttp_request *req, void *arg)
+{
+	evhttp_request_free(req);
+}
+
+/*
+ * Returns an error page.
+ */
+
+void
+evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
+{
+	char *fmt = "<HTML><HEAD>\n"
+	    "<TITLE>%d %s</TITLE>\n"
+	    "</HEAD><BODY>\n"
+	    "<H1>Method Not Implemented</H1>\n"
+	    "Invalid method in request<P>\n"
+	    "</BODY></HTML>\n";
+
+	struct evbuffer *buf = evbuffer_new();
+
+	evhttp_response_code(req, error, reason);
+
+	evbuffer_add_printf(buf, fmt, error, reason);
+
+	evhttp_send_page(req, buf);
+
+	evbuffer_free(buf);
+}
+
+/* Requires that headers and response code are already set up */
+
+static __inline void
+evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
+{
+	struct evbuffer *buf = req->buffer;
+
+	evbuffer_drain(buf, -1);
+
+	/* Adds headers to the response */
+	evhttp_make_header(buf, req);
+
+	evbuffer_add_buffer(buf, databuf);
+
+	evhttp_write_buffer(req, buf, evhttp_send_done, NULL);
+}
+
+void
+evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
+    struct evbuffer *databuf)
+{
+	evhttp_response_code(req, code, reason);
+	
+	evhttp_send(req, databuf);
+}
+
+void
+evhttp_response_code(struct evhttp_request *req, int code, const char *reason)
+{
+	req->kind = EVHTTP_RESPONSE;
+	req->response_code = code;
+	if (req->response_code_line != NULL)
+		free(req->response_code_line);
+	req->response_code_line = strdup(reason);
+}
+
+void
+evhttp_send_page(struct evhttp_request *req, struct evbuffer *databuf)
+{
+	if (req->kind != EVHTTP_RESPONSE)
+		evhttp_response_code(req, 200, "OK");
+
+	evhttp_clear_headers(req->output_headers);
+	evhttp_add_header(req->output_headers, "Content-Type", "text/html");
+	evhttp_add_header(req->output_headers, "Connection", "close");
+
+	evhttp_send(req, databuf);
+}
+
+/* 
+ * Helper function to parse out arguments in a query.
+ * The arguments are separated by key and value.
+ */
+
+void
+evhttp_parse_query(const char *uri, struct evkeyvalq *headers)
+{
+	char *line;
+	char *argument;
+	char *p;
+
+	TAILQ_INIT(headers);
+
+	/* No arguments - we are done */
+	if (strchr(uri, '?') == NULL)
+		return;
+
+	if ((line = strdup(uri)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+
+
+	argument = line;
+
+	/* We already know that there has to be a ? */
+	strsep(&argument, "?");
+
+	p = argument;
+	while (p != NULL && *p != '\0') {
+		char *key, *value;
+		argument = strsep(&p, "&");
+
+		value = argument;
+		key = strsep(&value, "=");
+		if (value == NULL)
+			goto error;
+
+		event_warnx("Got: %s -> %s\n", key, value);
+		evhttp_add_header(headers, key, value);
+	}
+
+ error:
+	free(line);
+}
+
+void
+evhttp_handle_request(struct evhttp_request *req, void *arg)
+{
+	struct evhttp *http = arg;
+	struct evhttp_cb *cb;
+
+	/* Test for different URLs */
+	TAILQ_FOREACH(cb, &http->callbacks, next) {
+		int res;
+		char *p = strchr(req->uri, '?');
+		if (p == NULL)
+			res = strcmp(cb->what, req->uri) == 0;
+		else
+			res = strncmp(cb->what, req->uri,
+			    (size_t)(p - req->uri)) == 0;
+		if (res) {
+			(*cb->cb)(req, cb->cbarg);
+			return;
+		}
+	}
+
+	/* Generic call back */
+	if (http->gencb) {
+		(*http->gencb)(req, http->gencbarg);
+		return;
+	} else {
+		/* We need to send a 404 here */
+		char *fmt = "<html><head>"
+		    "<title>404 Not Found</title>"
+		    "</head><body>"
+		    "<h1>Not Found</h1>"
+		    "<p>The requested URL %s was not found on this server.</p>"
+		    "</body></html>\n";
+
+		char *escaped_html = evhttp_htmlescape(req->uri);
+		struct evbuffer *buf = evbuffer_new();
+
+		evhttp_response_code(req, HTTP_NOTFOUND, "Not Found");
+
+		evbuffer_add_printf(buf, fmt, escaped_html);
+
+		free(escaped_html);
+		
+		evhttp_send_page(req, buf);
+
+		evbuffer_free(buf);
+	}
+}
+
+static void
+accept_socket(int fd, short what, void *arg)
+{
+	struct evhttp *http = arg;
+	struct sockaddr_storage ss;
+	socklen_t addrlen = sizeof(ss);
+	int nfd;
+
+	if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) {
+		event_warn("%s: bad accept", __func__);
+		return;
+	}
+
+	evhttp_get_request(nfd, (struct sockaddr *)&ss, addrlen,
+	    evhttp_handle_request, http);
+}
+
+static int
+bind_socket(struct evhttp *http, const char *address, u_short port)
+{
+	struct event *ev = &http->bind_ev;
+	int fd;
+
+	if ((fd = make_socket(bind, address, port)) == -1)
+		return (-1);
+
+	if (listen(fd, 10) == -1) {
+		event_warn("%s: listen", __func__);
+		return (-1);
+	}
+
+	/* Schedule the socket for accepting */
+	event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
+	event_add(ev, NULL);
+
+	event_debug(("Bound to port %d - Awaiting connections ... ", port));
+
+	return (0);
+}
+
+/*
+ * Start a web server on the specified address and port.
+ */
+
+struct evhttp *
+evhttp_start(const char *address, u_short port)
+{
+	struct evhttp *http;
+
+	if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
+		event_warn("%s: calloc", __func__);
+		return (NULL);
+	}
+
+	TAILQ_INIT(&http->callbacks);
+
+	if (bind_socket(http, address, port) == -1) {
+		free(http);
+		return (NULL);
+	}
+
+	return (http);
+}
+
+void
+evhttp_free(struct evhttp* http)
+{
+	struct evhttp_cb *http_cb;
+	int fd = http->bind_ev.ev_fd;
+
+	/* Remove the accepting part */
+	event_del(&http->bind_ev);
+	close(fd);
+
+	while ((http_cb = TAILQ_FIRST(&http->callbacks)) != NULL) {
+		TAILQ_REMOVE(&http->callbacks, http_cb, next);
+		free(http_cb->what);
+		free(http_cb);
+	}
+	
+	free(http);
+}
+
+void
+evhttp_set_cb(struct evhttp *http, const char *uri,
+    void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+	struct evhttp_cb *http_cb;
+
+	if ((http_cb = calloc(1, sizeof(struct evhttp_cb))) == NULL)
+		event_err(1, "%s: calloc", __func__);
+
+	http_cb->what = strdup(uri);
+	http_cb->cb = cb;
+	http_cb->cbarg = cbarg;
+
+	TAILQ_INSERT_TAIL(&http->callbacks, http_cb, next);
+}
+
+void
+evhttp_set_gencb(struct evhttp *http,
+    void (*cb)(struct evhttp_request *, void *), void *cbarg)
+{
+	http->gencb = cb;
+	http->gencbarg = cbarg;
+}
+
+/*
+ * Request related functions
+ */
+
+struct evhttp_request *
+evhttp_request_new(void (*cb)(struct evhttp_request *, void *), void *arg)
+{
+	struct evhttp_request *req = NULL;
+
+	/* Allocate request structure */
+	if ((req = calloc(1, sizeof(struct evhttp_request))) == NULL) {
+		event_warn("%s: calloc", __func__);
+		goto error;
+	}
+
+	req->fd = -1;
+	req->kind = EVHTTP_RESPONSE;
+	req->input_headers = calloc(1, sizeof(struct evkeyvalq));
+	if (req->input_headers == NULL) {
+		event_warn("%s: calloc", __func__);
+		goto error;
+	}
+	TAILQ_INIT(req->input_headers);
+
+	req->output_headers = calloc(1, sizeof(struct evkeyvalq));
+	if (req->output_headers == NULL) {
+		event_warn("%s: calloc", __func__);
+		goto error;
+	}
+	TAILQ_INIT(req->output_headers);
+
+	req->buffer = evbuffer_new();
+
+	req->cb = cb;
+	req->cb_arg = arg;
+
+	return (req);
+
+ error:
+	if (req != NULL)
+		evhttp_request_free(req);
+	return (NULL);
+}
+
+void
+evhttp_request_free(struct evhttp_request *req)
+{
+	if (req->fd != -1)
+		close(req->fd);
+	if (req->remote_host != NULL)
+		free(req->remote_host);
+	if (req->uri != NULL)
+		free(req->uri);
+	if (req->response_code_line != NULL)
+		free(req->response_code_line);
+
+	if (event_initialized(&req->ev))
+		event_del(&req->ev);
+
+	evhttp_clear_headers(req->input_headers);
+	free(req->input_headers);
+
+	evhttp_clear_headers(req->output_headers);
+	free(req->output_headers);
+
+	if (req->buffer != NULL)
+		evbuffer_free(req->buffer);
+	free(req);
+}
+
+/*
+ * Allows for inspection of the request URI
+ */
+
+const char *
+evhttp_request_uri(struct evhttp_request *req) {
+	if (req->uri == NULL)
+		event_debug(("%s: request %p has no uri\n", req));
+	return (req->uri);
+}
+
+/*
+ * Takes a file descriptor to read a request from.
+ * The callback is executed once the whole request has been read.
+ */
+
+void
+evhttp_get_request(int fd, struct sockaddr *sa, socklen_t salen,
+    void (*cb)(struct evhttp_request *, void *), void *arg)
+{
+	struct evhttp_request *req;
+	char *hostname, *portname;
+
+	name_from_addr(sa, salen, &hostname, &portname);
+	event_debug(("%s: new request from %s:%s on %d\n",
+			__func__, hostname, portname, fd));
+
+	if ((req = evhttp_request_new(cb, arg)) == NULL)
+		return;
+
+	req->fd = fd;
+	req->kind = EVHTTP_REQUEST;
+	
+	if ((req->remote_host = strdup(hostname)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+	req->remote_port = atoi(portname);
+
+	evhttp_start_read(req);
+}
+
+
+/*
+ * Network helper functions that we do not want to export to the rest of
+ * the world.
+ */
+
+static struct addrinfo *
+addr_from_name(char *address)
+{
+        struct addrinfo ai, *aitop;
+	
+        memset(&ai, 0, sizeof (ai));
+        ai.ai_family = AF_INET;
+        ai.ai_socktype = SOCK_RAW;
+        ai.ai_flags = 0;
+        if (getaddrinfo(address, NULL, &ai, &aitop) != 0) {
+                event_warn("getaddrinfo");
+                return (NULL);
+        }
+
+	return (aitop);
+}
+
+static void
+name_from_addr(struct sockaddr *sa, socklen_t salen,
+    char **phost, char **pport)
+{
+	static char ntop[NI_MAXHOST];
+	static char strport[NI_MAXSERV];
+
+	if (getnameinfo(sa, salen,
+		ntop, sizeof(ntop), strport, sizeof(strport),
+		NI_NUMERICHOST|NI_NUMERICSERV) != 0)
+		event_err(1, "getnameinfo failed");
+
+	*phost = ntop;
+	*pport = strport;
+}
+
+/* Either connect or bind */
+
+static int
+make_socket_ai(int (*f)(int, const struct sockaddr *, socklen_t),
+    struct addrinfo *ai)
+{
+        struct linger linger;
+        int fd, on = 1;
+	int serrno;
+
+        /* Create listen socket */
+        fd = socket(AF_INET, SOCK_STREAM, 0);
+        if (fd == -1) {
+                event_warn("socket");
+                return (-1);
+        }
+
+        if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+                event_warn("fcntl(O_NONBLOCK)");
+                goto out;
+        }
+
+        if (fcntl(fd, F_SETFD, 1) == -1) {
+                event_warn("fcntl(F_SETFD)");
+                goto out;
+        }
+
+        setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
+        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on));
+        linger.l_onoff = 1;
+        linger.l_linger = 5;
+        setsockopt(fd, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger));
+
+        if ((f)(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
+		if (errno != EINPROGRESS) {
+			goto out;
+		}
+        }
+
+	return (fd);
+
+ out:
+	serrno = errno;
+	close(fd);
+	errno = serrno;
+	return (-1);
+}
+
+static int
+make_socket(int (*f)(int, const struct sockaddr *, socklen_t),
+    const char *address, short port)
+{
+        struct addrinfo ai, *aitop;
+        char strport[NI_MAXSERV];
+	int fd;
+	
+        memset(&ai, 0, sizeof (ai));
+        ai.ai_family = AF_INET;
+        ai.ai_socktype = SOCK_STREAM;
+        ai.ai_flags = f != connect ? AI_PASSIVE : 0;
+        snprintf(strport, sizeof (strport), "%d", port);
+        if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
+                event_warn("getaddrinfo");
+                return (-1);
+        }
+        
+	fd = make_socket_ai(f, aitop);
+
+	freeaddrinfo(aitop);
+
+	return (fd);
+}

Added: trunk/varnish-cache/contrib/libevent/http.h
===================================================================
--- trunk/varnish-cache/contrib/libevent/http.h	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/http.h	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2001 Niels Provos <provos at citi.umich.edu>
+ * All rights reserved.
+ *
+ * This header file contains definitions for dealing with HTTP requests
+ * that are internal to libevent.  As user of the library, you should not
+ * need to know about these.
+ */
+
+#ifndef _HTTP_H_
+#define _HTTP_H_
+
+#define HTTP_CONNECT_TIMEOUT	45
+#define HTTP_WRITE_TIMEOUT	50
+#define HTTP_READ_TIMEOUT	50
+
+#define HTTP_PREFIX		"http://"
+#define HTTP_DEFAULTPORT	80
+
+struct evbuffer;
+struct addrinfo;
+
+/* A stupid connection object - maybe make this a bufferevent later */
+
+struct evhttp_connection {
+	int fd;
+	struct event ev;
+
+	char *address;
+	u_short port;
+	
+	void (*cb)(struct evhttp_connection *, void *);
+	void *cb_arg;
+};
+
+enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
+
+struct evhttp_request {
+	struct evkeyvalq *input_headers;
+	struct evkeyvalq *output_headers;
+
+	char *remote_host;
+	u_short remote_port;
+
+	enum evhttp_request_kind kind;
+	enum evhttp_cmd_type type;
+
+	char *uri;			/* uri after HTTP request was parsed */
+
+	char major;			/* HTTP Major number */
+	char minor;			/* HTTP Minor number */
+	
+	int got_firstline;
+	int response_code;		/* HTTP Response code */
+	char *response_code_line;	/* Readable response */
+
+	int fd;
+
+	struct event ev;
+
+	struct evbuffer *buffer;
+	int ntoread;
+
+	/* Callback */
+	void (*cb)(struct evhttp_request *, void *);
+	void *cb_arg;
+
+	void (*save_cb)(struct evhttp_request *, void *);
+	void *save_cbarg;
+};
+
+struct evhttp_cb {
+	TAILQ_ENTRY(evhttp_cb) next;
+
+	char *what;
+
+	void (*cb)(struct evhttp_request *req, void *);
+	void *cbarg;
+};
+
+struct evhttp {
+	struct event bind_ev;
+
+	TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
+
+	void (*gencb)(struct evhttp_request *req, void *);
+	void *gencbarg;
+};
+
+void evhttp_get_request(int, struct sockaddr *, socklen_t,
+    void (*)(struct evhttp_request *, void *), void *);
+
+/*
+ * Starts a connection to the specified address and invokes the callback
+ * if everything is fine.
+ */
+struct evhttp_connection *evhttp_connect(
+	const char *address, unsigned short port,
+	void (*cb)(struct evhttp_connection *, void *), void *cb_arg);
+
+/* Frees an http connection */
+void evhttp_connection_free(struct evhttp_connection *evcon);
+
+int evhttp_make_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req,
+    enum evhttp_cmd_type type, const char *uri);
+
+int evhttp_hostportfile(char *, char **, u_short *, char **);
+
+int evhttp_parse_lines(struct evhttp_request *, struct evbuffer*);
+
+void evhttp_start_read(struct evhttp_request *);
+void evhttp_read_header(int, short, void *);
+void evhttp_make_header(struct evbuffer *, struct evhttp_request *);
+
+void evhttp_form_response(struct evbuffer *, struct evhttp_request *);
+void evhttp_write_buffer(struct evhttp_request *, struct evbuffer *,
+    void (*)(struct evhttp_request *, void *), void *);
+
+/* response sending HTML the data in the buffer */
+void evhttp_response_code(struct evhttp_request *, int, const char *);
+void evhttp_send_page(struct evhttp_request *, struct evbuffer *);
+void evhttp_fail(struct evhttp_request *);
+
+#endif /* _HTTP_H */

Modified: trunk/varnish-cache/contrib/libevent/kqueue.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/kqueue.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/kqueue.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -75,6 +75,7 @@
 int kq_recalc	(struct event_base *, void *, int);
 int kq_dispatch	(struct event_base *, void *, struct timeval *);
 int kq_insert	(struct kqop *, struct kevent *);
+void kq_dealloc (void *);
 
 const struct eventop kqops = {
 	"kqueue",
@@ -82,7 +83,8 @@
 	kq_add,
 	kq_del,
 	kq_recalc,
-	kq_dispatch
+	kq_dispatch,
+	kq_dealloc
 };
 
 void *
@@ -266,10 +268,8 @@
 		if (!which)
 			continue;
 
-		if (!(ev->ev_events & EV_PERSIST)) {
-			ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+		if (!(ev->ev_events & EV_PERSIST))
 			event_del(ev);
-		}
 
 		event_active(ev, which,
 		    ev->ev_events & EV_SIGNAL ? events[i].data : 1);
@@ -396,3 +396,18 @@
 
 	return (0);
 }
+
+void
+kq_dealloc(void *arg)
+{
+	struct kqop *kqop = arg;
+
+	if (kqop->changes)
+		free(kqop->changes);
+	if (kqop->events)
+		free(kqop->events);
+	if (kqop->kq)
+		close(kqop->kq);
+	memset(kqop, 0, sizeof(struct kqop));
+	free(kqop);
+}

Modified: trunk/varnish-cache/contrib/libevent/log.h
===================================================================
--- trunk/varnish-cache/contrib/libevent/log.h	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/log.h	2006-04-03 11:59:08 UTC (rev 98)
@@ -33,11 +33,11 @@
 void event_warnx(const char *fmt, ...);
 void event_msgx(const char *fmt, ...);
 void _event_debugx(const char *fmt, ...);
-#undef USE_DEBUG
+
 #ifdef USE_DEBUG
 #define event_debug(x) _event_debugx x
 #else
-#define event_debug(x)
+#define event_debug(x) do {;} while (0)
 #endif
 
 #endif

Modified: trunk/varnish-cache/contrib/libevent/poll.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/poll.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/poll.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -74,14 +74,16 @@
 int poll_del		(void *, struct event *);
 int poll_recalc		(struct event_base *, void *, int);
 int poll_dispatch	(struct event_base *, void *, struct timeval *);
+void poll_dealloc	(void *);
 
-struct eventop pollops = {
+const struct eventop pollops = {
 	"poll",
 	poll_init,
 	poll_add,
 	poll_del,
 	poll_recalc,
-	poll_dispatch
+	poll_dispatch,
+	poll_dealloc
 };
 
 void *
@@ -89,11 +91,11 @@
 {
 	struct pollop *pollop;
 
-	/* Disable kqueue when this environment variable is set */
+	/* Disable poll when this environment variable is set */
 	if (getenv("EVENT_NOPOLL"))
 		return (NULL);
 
-        if (!(pollop = calloc(1, sizeof(struct pollop))))
+	if (!(pollop = calloc(1, sizeof(struct pollop))))
 		return (NULL);
 
 	evsignal_init(&pollop->evsigmask);
@@ -182,7 +184,7 @@
 		return (0);
 
 	for (i = 0; i < nfds; i++) {
-                int what = pop->event_set[i].revents;
+		int what = pop->event_set[i].revents;
 		struct event *r_ev = NULL, *w_ev = NULL;
 		if (!what)
 			continue;
@@ -355,3 +357,21 @@
 	poll_check_ok(pop);
 	return (0);
 }
+
+void
+poll_dealloc(void *arg)
+{
+	struct pollop *pop = arg;
+
+	if (pop->event_set)
+		free(pop->event_set);
+	if (pop->event_r_back)
+		free(pop->event_r_back);
+	if (pop->event_w_back)
+		free(pop->event_w_back);
+	if (pop->idxplus1_by_fd)
+		free(pop->idxplus1_by_fd);
+
+	memset(pop, 0, sizeof(struct pollop));
+	free(pop);
+}

Modified: trunk/varnish-cache/contrib/libevent/rtsig.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/rtsig.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/rtsig.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -1,3 +1,152 @@
+/*
+ * Copyright (c) 2006 Mathew Mills <mathewmills at mac.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+/*
+ * Meta-level comments: You know that a kernel interface is wrong if
+ * supporting it requires three times more code than any of the other
+ * kernel interfaces supported in libevent.  Niels - 2006-02-22
+ */
+/**
+
+   "RTSIG" is a shorthand for using O_ASYNC to make descriptors send
+   signals when readable/writable and to use POSIX real-time signals
+   witch are queued unlike normal signals.  At first blush this may
+   seem like a alternative to epoll, but a number of problems arise
+   when attempting to build an eventloop entirely out of rtsig.
+   Still, we can use rtsig in combination with poll() to
+   provide an eventloop that allows for many thousands of sockets
+   without huge overheads implicit with using select() or poll()
+   alone.  epoll and kqueue are far superior to rtsig and should be
+   used where available, but rtsig has been in standard Linux kernels
+   for a long time and have a huge installation base.  epoll requires
+   special patches for 2.4 kernels and 2.6 kernels are not yet nearly
+   so ubiquitous.
+
+   rtsig problems:
+    - O_ASYNC mechanisms work only on sockets - not pipes or tty's
+
+    - O_ASYNC signals are edge-triggered, POLLIN on packet arriving
+   or socket close; POLLOUT when a socket transitions from
+   non-writable to writable.  Being edge-triggered means the
+   event-handler callbacks must transition the level ( reading
+   completely the socket buffer contents ) or it will be unable to
+   reliably receive notification again.
+
+   - rtsig implementations must be intimately involved in how a
+   process dispatches signals.
+
+   - delivering signals per-event can be expensive, CPU-wise, but
+     sigtimedwait() blocks on signals only and means non-sockets
+     cannot be serviced.
+
+   Theory of operation:
+    This libevent module uses rtsig to allow us to manage a set of
+    poll-event descriptors.  We can drop uninteresting fd's from the
+    pollset if the fd will send a signal when it becomes interesting
+    again.
+
+    poll() offers us level-triggering and, when we have verified the
+    level of a socket, we can trust the edge-trigger nature of the
+    ASYNC signal.
+
+    As an eventloop we must poll for external events but leverage
+    kernel functionality to sleep between events ( until the loop's
+    next scheduled timed event ).
+
+    If we are polling on any non-sockets then we simply have no choice
+    about blocking on the poll() call.  If we blocked on the
+    sigtimedwait() call as rtsig papers recommend we will not wake on
+    non-socket state transitions.  As part of libevent, this module
+    must support non-socket polling.
+
+    Many applications, however, do not need to poll on non-sockets and
+    so this module should be able to optimize this case by using
+    sigtimedwait().  For this reason this module can actually trigger
+    events in each of three different ways:
+      - poll() returning ready events from descriptors in the pollset
+
+      - real-time signals dequeued via sigtimedwait()
+
+      - real-time signals that call an installed signal handler which in
+    turn writes the contents of siginfo to one end of a socketpair
+    DGRAM socket.  The other end of the socket is always in the
+    pollset so poll will be guaranteed to return even if the signal is
+    received before entering poll().
+
+    non-socket descriptors force us to block on the poll() for the
+    duration of a dispatch.  In this case we unblock (w/ sigprocmask)
+    the managed signals just before polling.  Each managed signal is
+    handled by signal_handler() which send()'s the contents of siginfo
+    over the socketpair.  Otherwise, we call poll() with a timeout of
+    0ms so it checks the levels of the fd's in the pollset and returns
+    immediately.  Any fd that is a socket and has no active state is
+    removed from the pollset for the next pass -- we will rely on
+    getting a signal for events on these fd's.
+
+    The receiving end of the siginfo socketpair is in the pollset
+    (permanently) so if we are polling on non-sockets, the delivery of
+    signals immediately following sigprocmask( SIG_UNBLOCK...) will
+    result in a readable op->signal_recv_fd which ensures the poll()
+    will return immediately.  If the poll() call is blocking and a
+    signal arrives ( possibly a real-time signal from a socket not in
+    the pollset ) its handler will write the data to the socketpair
+    and interrupt the poll().
+
+    After every poll call we attempt a non-blocking recv from the
+    signal_recv_fd and continue to recv and dispatch the events until
+    recv indicates the socket buffer is empty.
+
+    One might raise concerns about receiving event activations from
+    both poll() and from the rtsig data in the signal_recv_fd.
+    Fortunately, libevent is already structured for event coalescing,
+    so this issue is mitigated ( though we do some work twice for the
+    same event making us less efficient ).  I suspect that the cost of
+    turning off the O_ASYNC flag on fd's in the pollset is more
+    expensive than handling some events twice.  Looking at the
+    kernel's source code for setting O_ASYNC, it looks like it takes a
+    global kernel lock...
+
+    After a poll and recv-loop for the signal_recv_fd, we finally do a
+    sigtimedwait().  sigtimedwait will only block if we haven't
+    blocked in poll() and we have not enqueued events from either the
+    poll or the recv-loop.  Because sigtimedwait blocks all signals
+    that are not in the set of signals to be dequeued, we need to
+    dequeue almost all signals and make sure we dispatch them
+    correctly.  We dequeue any signal that is not blocked as well as
+    all libevent-managed signals.  If we get a signal that is not
+    managed by libevent we lookup the sigaction for the specific
+    signal and call that function ourselves.
+
+    Finally, I should mention that getting a SIGIO signal indicates
+    that the rtsig buffer has overflowed and we have lost events.
+    This forces us to add _every_ descriptor to the pollset to recover.
+
+*/
+
+
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -20,152 +169,465 @@
 #include <string.h>
 #include <sys/poll.h>
 #include <sys/queue.h>
-#ifndef HAVE_WORKING_RTSIG
-#include <sys/stat.h>
-#endif
+#include <sys/tree.h>
 #include <unistd.h>
+#include <sys/socket.h>
 
-#define EVLIST_X_NORT	0x1000	/* Skip RT signals (internal) */
-
 #include "event.h"
+#include "event-internal.h"
 #include "log.h"
 extern struct event_list signalqueue;
 
+#include <linux/unistd.h>
+#ifndef __NR_gettid
+#define gettid() getpid()
+#else
+
+#if ((__GLIBC__ > 2) || ((__GLIBC__ == 2) && (__GLIBC_MINOR__ >= 3)))
+_syscall0(pid_t,gettid)
+#endif
+
+#endif
+
+#define EVLIST_NONSOCK   0x1000 /* event is for a non-socket file-descriptor */
+#define EVLIST_DONTDEL   0x2000 /* event should always be in the pollset */
+#define MAXBUFFERSIZE (1024 * 1024 * 2) /* max socketbuffer for signal-spair */
+#define INIT_MAX 16     /* init/min # of fd positions in our pollset */
+
+static int signal_send_fd[_NSIG]; /* the globalend of the signal socketpair */
+static int trouble[_NSIG]; /* 1 when signal-handler cant send to signal_send_fd */
+
+struct rtdata;
+TAILQ_HEAD(rtdata_list, rtdata);
+
 struct rtsigop {
-    sigset_t sigs;
-    struct pollfd *poll;
-    struct event **toev;
-    int cur, max, total;
-#ifndef HAVE_WORKING_RTSIG
-    int pollmode;
-#endif
+	sigset_t sigs;        /* signal mask for all _managed_ signals */
+	struct pollfd *poll;  /* poll structures */
+	struct rtdata **ptodat;  /* map poll_position to rtdata */
+	int cur;              /* cur # fd's in a poll set */
+	int max;              /* max # fd's in a poll set, start at 16 and grow as needed */
+	int total;            /* count of fd's we are watching now */
+	int signo;            /* the signo we use for ASYNC fd notifications */
+	int nonsock;          /* number of non-socket fd's we are watching */
+	int highestfd;        /* highest fd accomodated by fdtodat */
+	struct rtdata_list **fdtodat; /* map fd to rtdata ( and thus to event ) */
+	int signal_recv_fd;   /* recv side of the signal_send_fd */
+	int signal_send_fd;   /* recv side of the signal_send_fd */
+	struct event sigfdev; /* our own event structure for the signal fd */
 };
 
-#define INIT_MAX 16
+struct rtdata {
+	/* rtdata holds rtsig-private state on each event */
+	TAILQ_ENTRY (rtdata) next;
+	struct event *ev;
+	int poll_position;
+};
 
+void *rtsig_init(void);
+int rtsig_add(void *, struct event *);
+int rtsig_del(void *, struct event *);
+int rtsig_recalc(struct event_base *, void *, int);
+int rtsig_dispatch(struct event_base *, void *, struct timeval *);
+
+struct eventop rtsigops = {
+	"rtsig",
+	rtsig_init,
+	rtsig_add,
+	rtsig_del,
+	rtsig_recalc,
+	rtsig_dispatch
+};
+
+static void
+signal_handler(int sig, siginfo_t *info, void *ctx)
+{
+	/*
+	 * the signal handler for all libevent-managed signals only
+	 * used if we need to do a blocking poll() call due to
+	 * non-socket fd's in the pollset.
+	 */
+  
+	siginfo_t *i = info;
+	siginfo_t i_local;
+
+	if (trouble[sig - 1]) {
+		i_local.si_signo = SIGIO;
+		i_local.si_errno = 0;
+		i_local.si_code = 0;
+		i = &i_local;
+		trouble[sig - 1] = 0;
+	}
+
+	if (send(signal_send_fd[sig - 1], i, sizeof(*i),
+		MSG_DONTWAIT|MSG_NOSIGNAL) == -1)
+		trouble[sig - 1] = 1;
+}
+
+static void
+donothing(int fd, short event, void *arg)
+{
+	/*
+	 * callback for our signal_recv_fd event structure
+	 * we don't want to act on these events, we just want to wake the poll()
+	 */
+};
+
+static void
+signotset(sigset_t *set)
+{
+	int i, l;
+	l = sizeof(*set) / 4;
+	for (i = 0; i < l; i++) {
+		((unsigned *)set)[i] = ~((unsigned *)set)[i];
+	}
+}
+
+/*  The next three functions manage our private data about each event struct */
+
 static int
-poll_add(struct rtsigop *op, struct event *ev)
+grow_fdset(struct rtsigop *op, int newhigh)
 {
-    struct pollfd *pfd;
+	/*
+	 * grow the fd -> rtdata array because we have encountered a
+	 * new fd too high to fit in the existing array
+	 */
 
-    if (op->poll == NULL) return 0;
+	struct rtdata_list **p;
+	struct rtdata_list *datset;
+	int i,x;
+	int newcnt = (newhigh + 1) << 1;
 
-    if (op->cur == op->max) {
-        void *p;
+	if (newhigh <= op->highestfd)
+		return (0);
 
-        p = realloc(op->poll, sizeof(*op->poll) * (op->max << 1));
-        if (!p) {
-            errno = ENOMEM;
-            return -1;
-        }
-        op->poll = p;
-        p = realloc(op->toev, sizeof(*op->toev) * (op->max << 1));
-        if (!p) {
-            op->poll = realloc(op->poll, sizeof(*op->poll) * op->max);
-            errno = ENOMEM;
-            return -1;
-        }
-        op->toev = p;
-        op->max <<= 1;
-    }
+	p = op->fdtodat;
+	p = realloc(op->fdtodat, sizeof(struct rtdata_list *) * newcnt);
+	if (p == NULL)
+		return (-1);
+	op->fdtodat = p;
 
-    pfd = &op->poll[op->cur];
-    pfd->fd = ev->ev_fd;
-    pfd->events = 0;
-    if (ev->ev_events & EV_READ) pfd->events |= POLLIN;
-    if (ev->ev_events & EV_WRITE) pfd->events |= POLLOUT;
-    pfd->revents = 0;
+	datset = calloc(newcnt - (op->highestfd + 1),
+	    sizeof(struct rtdata_list));
+	if (datset == NULL)
+		return (-1);
 
-    op->toev[op->cur] = ev;
-    op->cur++;
+	for (i = op->highestfd + 1, x = 0; i < newcnt; i++, x++) {
+		op->fdtodat[i] = &(datset[x]);
+		TAILQ_INIT(op->fdtodat[i]);
+	}
 
-    return 0;
+	op->highestfd = newcnt - 1;
+	return (0);
 }
 
+static struct rtdata *
+ev2dat(struct rtsigop *op, struct event *ev, int create)
+{
+	/*
+	 * given an event struct, find the dat structure that
+	 * corresponds to it if create is non-zero and the rtdata
+	 * structure does not exist, create it return NULL if not
+	 * found
+	 */
+
+	int found = 0;
+	int fd = ev->ev_fd;
+	struct rtdata *ret = NULL;
+
+	if (op->highestfd < fd && create)
+		if (grow_fdset(op, fd) == -1)
+			return (NULL);
+  
+	TAILQ_FOREACH(ret, op->fdtodat[fd], next) {
+		if (ret->ev == ev) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		if (!create)
+			return (NULL);
+
+		ret = calloc(1, sizeof(struct rtdata));
+		if (ret == NULL)
+			return (NULL);
+		ret->ev = ev;
+		ret->poll_position = -1;
+		TAILQ_INSERT_TAIL(op->fdtodat[fd], ret, next);
+	}
+
+	return (ret);
+}
+
 static void
+dat_del(struct rtsigop *op, struct rtdata *dat)
+{
+	/*
+	 * delete our private notes about a given event struct
+	 * called from rtsig_del() only
+	 */
+	int fd;
+	if (dat == NULL)
+		return;
+	fd = dat->ev->ev_fd;
+
+	TAILQ_REMOVE(op->fdtodat[fd], dat, next);
+	memset(dat, 0, sizeof(*dat));
+	free(dat);
+}
+
+
+static void
+set_sigaction(int sig)
+{
+	/*
+	 * set the standard handler for any libevent-managed signal,
+	 * including the rtsig used for O_ASYNC notifications
+	 */
+	struct sigaction act;
+
+	act.sa_flags = SA_RESTART | SA_SIGINFO;
+	sigfillset(&(act.sa_mask));
+	act.sa_sigaction = &signal_handler;
+	sigaction(sig, &act, NULL);
+}
+
+static int
+find_rt_signal()
+{
+	/* find an unused rtsignal */
+	struct sigaction act;
+	int sig = SIGRTMIN;
+
+	while (sig <= SIGRTMAX) {
+		if (sigaction(sig, NULL, &act) != 0) {
+			if (errno == EINTR)
+				continue;
+		} else {
+			if (act.sa_flags & SA_SIGINFO) {
+				if (act.sa_sigaction == NULL)
+					return (sig);
+			} else {
+				if (act.sa_handler == SIG_DFL)
+					return (sig);
+			}
+		}
+		sig++;
+	}
+	return (0);
+}
+
+/*
+ * the next three functions manage our pollset and the memory management for 
+ * fd -> rtdata -> event -> poll_position maps
+ */
+
+static int
+poll_add(struct rtsigop *op, struct event *ev, struct rtdata *dat)
+{
+	struct pollfd *pfd;
+	int newmax = op->max << 1;
+	int pp;
+
+	if (op->poll == NULL)
+		return (0);
+
+	if (dat == NULL)
+		dat = ev2dat(op, ev, 0);
+
+	if (dat == NULL)
+		return (0);
+
+	pp = dat->poll_position;
+
+	if (pp != -1) {
+		pfd = &op->poll[pp];
+		if (ev->ev_events & EV_READ)
+			pfd->events |= POLLIN;
+    
+		if (ev->ev_events & EV_WRITE)
+			pfd->events |= POLLOUT;
+    
+		return (0);
+	}
+
+	if (op->cur == op->max) {
+		void *p = realloc(op->poll, sizeof(*op->poll) * newmax);
+		if (p == NULL) {
+			errno = ENOMEM;
+			return (-1);
+		}
+		op->poll = p;
+
+		p = realloc(op->ptodat, sizeof(*op->ptodat) * newmax);
+		if (p == NULL) {
+			/* shrink the pollset back down */
+			op->poll = realloc(op->poll,
+			    sizeof(*op->poll) * op->max);
+			errno = ENOMEM;
+			return (-1);
+		}
+		op->ptodat = p;
+		op->max = newmax;
+	}
+
+	pfd = &op->poll[op->cur];
+	pfd->fd = ev->ev_fd;
+	pfd->revents = 0;
+	pfd->events = 0;
+
+	if (ev->ev_events & EV_READ)
+		pfd->events |= POLLIN;
+  
+	if (ev->ev_events & EV_WRITE)
+		pfd->events |= POLLOUT;
+  
+	op->ptodat[op->cur] = dat;
+	dat->poll_position = op->cur;
+	op->cur++;
+
+	return (0);
+}
+
+static void
 poll_free(struct rtsigop *op, int n)
 {
-    if (op->poll == NULL) return;
+  if (op->poll == NULL)
+	  return;
 
-    op->cur--;
-    if (n < op->cur) {
-        memcpy(&op->poll[n], &op->poll[op->cur], sizeof(*op->poll));
-        op->toev[n] = op->toev[op->cur];
-    }
-    if (op->max > INIT_MAX && op->cur < op->max >> 1) {
-        op->max >>= 1;
-        op->poll = realloc(op->poll, sizeof(*op->poll) * op->max);
-        op->toev = realloc(op->toev, sizeof(*op->toev) * op->max);
-    }
+  op->cur--;
+
+  if (n < op->cur) {
+    memcpy(&op->poll[n], &op->poll[op->cur], sizeof(*op->poll));
+    op->ptodat[n] = op->ptodat[op->cur];
+    op->ptodat[n]->poll_position = n;
+  }
+
+
+  /* less then half the max in use causes us to shrink */
+  if (op->max > INIT_MAX && op->cur < op->max >> 1) {
+    op->max >>= 1;
+    op->poll = realloc(op->poll, sizeof(*op->poll) * op->max);
+    op->ptodat = realloc(op->ptodat, sizeof(*op->ptodat) * op->max);
+  }
 }
 
 static void
-poll_remove(struct rtsigop *op, struct event *ev)
+poll_remove(struct rtsigop *op, struct event *ev, struct rtdata *dat)
 {
-    int i;
+  int pp;
+  if (dat == NULL)
+    dat = ev2dat(op, ev, 0);
 
-    for (i = 0; i < op->cur; i++) {
-        if (op->toev[i] == ev) {
-            poll_free(op, i);
-            break;
-        }
-    }
+  if (dat == NULL) return;
+
+  pp = dat->poll_position;
+  if (pp != -1) {
+    poll_free(op, pp);
+    dat->poll_position = -1;
+  }
 }
 
 static void
 activate(struct event *ev, int flags)
 {
-    if (!(ev->ev_events & EV_PERSIST)) event_del(ev);
-    event_active(ev, flags, 1);
+	/* activate an event, possibly removing one-shot events */
+	if (!(ev->ev_events & EV_PERSIST))
+		event_del(ev);
+	event_active(ev, flags, 1);
 }
 
-void *rtsig_init(void);
-int rtsig_add(void *, struct event *);
-int rtsig_del(void *, struct event *);
-int rtsig_recalc(struct event_base *, void *, int);
-int rtsig_dispatch(struct event_base *, void *, struct timeval *);
+#define FD_CLOSEONEXEC(x) do { \
+        if (fcntl(x, F_SETFD, 1) == -1) \
+                event_warn("fcntl(%d, F_SETFD)", x); \
+} while (0)
 
-struct eventop rtsigops = {
-    "rtsig",
-    rtsig_init,
-    rtsig_add,
-    rtsig_del,
-    rtsig_recalc,
-    rtsig_dispatch
-};
-
 void *
 rtsig_init(void)
 {
 	struct rtsigop *op;
+	int sockets[2];
+	int optarg;
+	struct rtdata *dat;
+	int flags;
 
 	if (getenv("EVENT_NORTSIG"))
-		return (NULL);
+		goto err;
 
-	op = malloc(sizeof(*op));
-	if (op == NULL) return (NULL);
+	op = calloc(1, sizeof(*op));
+	if (op == NULL)
+		goto err;
 
-	memset(op, 0, sizeof(*op));
-
 	op->max = INIT_MAX;
 	op->poll = malloc(sizeof(*op->poll) * op->max);
-	if (op->poll == NULL) {
-		free(op);
-		return (NULL);
-	}
-	op->toev = malloc(sizeof(*op->toev) * op->max);
-	if (op->toev == NULL) {
-		free(op->poll);
-		free(op);
-		return (NULL);
-	}
+	if (op->poll == NULL) 
+		goto err_free_op;
 
+	op->signo = find_rt_signal();
+	if (op->signo == 0)
+		goto err_free_poll;
+  
+	op->nonsock = 0;
+
+	if (socketpair(PF_UNIX, SOCK_DGRAM, 0, sockets) != 0)
+		goto err_free_poll;
+
+	FD_CLOSEONEXEC(sockets[0]);
+	FD_CLOSEONEXEC(sockets[1]);
+
+	signal_send_fd[op->signo - 1] = sockets[0];
+	trouble[op->signo - 1] = 0;
+	op->signal_send_fd = sockets[0];
+	op->signal_recv_fd = sockets[1];
+	flags = fcntl(op->signal_recv_fd, F_GETFL);
+	fcntl(op->signal_recv_fd, F_SETFL, flags | O_NONBLOCK);
+
+	optarg = MAXBUFFERSIZE;
+	setsockopt(signal_send_fd[op->signo - 1],
+	    SOL_SOCKET, SO_SNDBUF, 
+	    &optarg, sizeof(optarg));
+  
+	optarg = MAXBUFFERSIZE;
+	setsockopt(op->signal_recv_fd,
+	    SOL_SOCKET, SO_RCVBUF,
+	    &optarg, sizeof(optarg));
+
+	op->highestfd = -1;
+	op->fdtodat = NULL;
+	if (grow_fdset(op, 1) == -1)
+		goto err_close_pair;
+
+	op->ptodat = malloc(sizeof(*op->ptodat) * op->max);
+	if (op->ptodat == NULL)
+		goto err_close_pair;
+
 	sigemptyset(&op->sigs);
 	sigaddset(&op->sigs, SIGIO);
-	sigaddset(&op->sigs, SIGRTMIN);
+	sigaddset(&op->sigs, op->signo);
 	sigprocmask(SIG_BLOCK, &op->sigs, NULL);
+	set_sigaction(SIGIO);
+	set_sigaction(op->signo);
 
+	event_set(&(op->sigfdev), op->signal_recv_fd, EV_READ|EV_PERSIST,
+	    donothing, NULL);
+	op->sigfdev.ev_flags |= EVLIST_DONTDEL;
+	dat = ev2dat(op, &(op->sigfdev), 1);
+	poll_add(op, &(op->sigfdev), dat);
+
 	return (op);
+
+ err_close_pair:
+	close(op->signal_recv_fd);
+	close(signal_send_fd[op->signo - 1]);
+
+ err_free_poll:
+	free(op->poll);
+ 
+ err_free_op:
+	free(op);
+ err:
+	return (NULL);
 }
 
 int
@@ -173,79 +635,102 @@
 {
 	struct rtsigop *op = (struct rtsigop *) arg;
 	int flags, i;
-#ifndef HAVE_WORKING_RTSIG
-	struct stat st;
-#endif
+	struct stat statbuf;
+	struct rtdata *dat;
 
 	if (ev->ev_events & EV_SIGNAL) {
+		int signo = EVENT_SIGNAL(ev);
+  
 		sigaddset(&op->sigs, EVENT_SIGNAL(ev));
-		return sigprocmask(SIG_BLOCK, &op->sigs, NULL);
+		if (sigprocmask(SIG_BLOCK, &op->sigs, NULL) == -1)
+			return (-1);
+    
+		set_sigaction(signo);
+    
+		signal_send_fd[signo - 1] = op->signal_send_fd;
+		trouble[signo - 1] = 0;
+
+		return (0);
 	}
 
-	if (!(ev->ev_events & (EV_READ | EV_WRITE))) return 0;
+	if (!(ev->ev_events & (EV_READ|EV_WRITE))) 
+		return (0);
 
-#ifndef HAVE_WORKING_RTSIG
-	if (fstat(ev->ev_fd, &st) == -1) return -1;
-	if (S_ISFIFO(st.st_mode)) {
-		ev->ev_flags |= EVLIST_X_NORT;
-		op->pollmode++;
-	}
-#endif
+	if (-1 == fstat(ev->ev_fd, &statbuf))
+		return (-1);
 
+	if (!S_ISSOCK(statbuf.st_mode))
+		ev->ev_flags |= EVLIST_NONSOCK;
+
 	flags = fcntl(ev->ev_fd, F_GETFL);
 	if (flags == -1)
 		return (-1);
 
 	if (!(flags & O_ASYNC)) {
-		if (fcntl(ev->ev_fd, F_SETSIG, SIGRTMIN) == -1
-		    || fcntl(ev->ev_fd, F_SETOWN, (int) getpid()) == -1)
+		if (fcntl(ev->ev_fd, F_SETSIG, op->signo) == -1 ||
+		    fcntl(ev->ev_fd, F_SETOWN, (int) gettid()) == -1)
 			return (-1);
-
-		if (fcntl(ev->ev_fd, F_SETFL, flags | O_ASYNC))
+    
+		/*
+		 * the overhead of always handling writeable edges
+		 * isn't going to be that bad...
+		 */
+		if (fcntl(ev->ev_fd, F_SETFL, flags | O_ASYNC|O_RDWR)) 
 			return (-1);
 	}
 
 #ifdef O_ONESIGFD
+	/*
+	 * F_SETAUXFL and O_ONESIGFD are defined in a non-standard
+	 * linux kernel patch to coalesce events for fds
+	 */
 	fcntl(ev->ev_fd, F_SETAUXFL, O_ONESIGFD);
 #endif
 
+	dat = ev2dat(op, ev, 1);
+	if (dat == NULL)
+		return (-1);
+
 	op->total++;
-	if (poll_add(op, ev) == -1)
-		goto err;
+	if (ev->ev_flags & EVLIST_NONSOCK)
+		op->nonsock++;
 
+	if (poll_add(op, ev, dat) == -1) {
+		/* must check the level of new fd's */
+		i = errno;
+		fcntl(ev->ev_fd, F_SETFL, flags);
+		errno = i;
+		return (-1);
+	}
+
 	return (0);
-
- err:
-	i = errno;
-	fcntl(ev->ev_fd, F_SETFL, flags);
-	errno = i;
-	return (-1);
 }
 
 int
 rtsig_del(void *arg, struct event *ev)
 {
+	struct rtdata *dat;
 	struct rtsigop *op = (struct rtsigop *) arg;
 
 	if (ev->ev_events & EV_SIGNAL) {
 		sigset_t sigs;
 
 		sigdelset(&op->sigs, EVENT_SIGNAL(ev));
-
+    
 		sigemptyset(&sigs);
 		sigaddset(&sigs, EVENT_SIGNAL(ev));
 		return (sigprocmask(SIG_UNBLOCK, &sigs, NULL));
 	}
 
-	if (!(ev->ev_events & (EV_READ | EV_WRITE)))
+	if (!(ev->ev_events & (EV_READ|EV_WRITE)))
 		return (0);
 
-#ifndef HAVE_WORKING_RTSIG
-	if (ev->ev_flags & EVLIST_X_NORT)
-		op->pollmode--;
-#endif
-	poll_remove(op, ev);
+	dat = ev2dat(op, ev, 0);
+	poll_remove(op, ev, dat);
+	dat_del(op, dat);
 	op->total--;
+	if (ev->ev_flags & EVLIST_NONSOCK)
+		op->nonsock--;
 
 	return (0);
 }
@@ -253,183 +738,248 @@
 int
 rtsig_recalc(struct event_base *base, void *arg, int max)
 {
-    return (0);
+	return (0);
 }
 
-int
-rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+/*
+ * the following do_X functions implement the different stages of a single
+ * eventloop pass: poll(), recv(sigsock), sigtimedwait()
+ *
+ * do_siginfo_dispatch() is a common factor to both do_sigwait() and
+ * do_signals_from_socket().
+ */
+
+static inline int
+do_poll(struct rtsigop *op, struct timespec *ts)
 {
-	struct rtsigop *op = (struct rtsigop *) arg;
-	struct timespec ts;
-	int res, i;
+	int res = 0;
+	int i = 0;
+  
+	if (op->cur > 1) {
+		/* non-empty poll set (modulo the signalfd) */
+		if (op->nonsock) {
+			int timeout = ts->tv_nsec / 1000000 + ts->tv_sec * 1000;
+			
+			sigprocmask(SIG_UNBLOCK, &(op->sigs), NULL);
 
-	if (op->poll == NULL)
-		goto retry_poll;
-#ifndef HAVE_WORKING_RTSIG
-	if (op->pollmode)
-		goto poll_all;
-#endif
+			res = poll(op->poll, op->cur, timeout);
+			
+			sigprocmask(SIG_BLOCK, &(op->sigs), NULL);
+			
+			ts->tv_sec = 0;
+			ts->tv_nsec = 0;
+		} else {
+			res = poll(op->poll, op->cur, 0);
+		}
 
-	if (op->cur) {
-		ts.tv_sec = ts.tv_nsec = 0;
-	} else {
-		ts.tv_sec = tv->tv_sec;
-		ts.tv_nsec = tv->tv_usec * 1000;
-	}
-
-	for (;;) {
-		siginfo_t info;
-		struct event *ev;
-		int signum;
-
-		signum = sigtimedwait(&op->sigs, &info, &ts);
-
-		if (signum == -1) {
-			if (errno == EAGAIN)
-				break;
+		if (res < 0) {
 			return (errno == EINTR ? 0 : -1);
+		} else if (res) {
+			ts->tv_sec = 0;
+			ts->tv_nsec = 0;
 		}
 
-		ts.tv_sec = ts.tv_nsec = 0;
+		i = 0;
+		while (i < op->cur) {
+			struct rtdata *dat = op->ptodat[i];
+			struct event *ev = dat->ev;
 
-		if (signum == SIGIO) {
-#ifndef HAVE_WORKING_RTSIG
-		poll_all:
-#endif
-			free(op->poll);
-			free(op->toev);
-		retry_poll:
-			op->cur = 0;
-			op->max = op->total;
-			op->poll = malloc(sizeof(*op->poll) * op->total);
-			if (op->poll == NULL)
-				return (-1);
-			op->toev = malloc(sizeof(*op->toev) * op->total);
-			if (op->toev == NULL) {
-				free(op->poll);
-				op->poll = NULL;
-				return (-1);
+			if (op->poll[i].revents) {
+				int flags = 0;
+	
+				if (op->poll[i].revents & (POLLIN | POLLERR))
+					flags |= EV_READ;
+	
+				if (op->poll[i].revents & POLLOUT)
+					flags |= EV_WRITE;
+	
+				if (!(ev->ev_events & EV_PERSIST)) {
+					poll_remove(op, ev, op->ptodat[i]);
+					event_del(ev);
+				} else {
+					i++;
+				}
+	
+				event_active(ev, flags, 1);
+			} else {
+				if (ev->ev_flags & (EVLIST_NONSOCK|EVLIST_DONTDEL)) {
+					i++;
+				} else {
+					poll_remove(op, ev, op->ptodat[i]);
+				}
 			}
+		}
+	}
+	return (res);
+}
 
-			TAILQ_FOREACH(ev, &base->eventqueue, ev_next)
-			    if (!(ev->ev_flags & EVLIST_X_NORT))
-				    poll_add(op, ev);
+static inline int
+do_siginfo_dispatch(struct event_base *base, struct rtsigop *op,
+    siginfo_t *info)
+{
+	int signum;
+	struct rtdata *dat, *next_dat;
+	struct event *ev, *next_ev;
 
-			break;
-		}
+	if (info == NULL)
+		return (-1);
 
-		if (signum == SIGRTMIN) {
-			int flags, i, sigok = 0;
+	signum = info->si_signo;
+	if (signum == op->signo) {
+		int flags, sigok = 0;
+		flags = 0;
 
-			if (info.si_band <= 0) { /* SI_SIGIO */
-				flags = EV_READ | EV_WRITE;
-			} else {
-				flags = 0;
-				if (info.si_band & POLLIN) flags |= EV_READ;
-				if (info.si_band & POLLOUT) flags |= EV_WRITE;
-				if (!flags) continue;
-			}
+		if (info->si_band & (POLLIN|POLLERR))
+			flags |= EV_READ;
+		if (info->si_band & POLLOUT)
+			flags |= EV_WRITE;
 
-			for (i = 0; flags && i < op->cur; i++) {
-				ev = op->toev[i];
+		if (!flags)
+			return (0);
 
-				if (ev->ev_fd == info.si_fd) {
-					flags &= ~ev->ev_events;
-					sigok = 1;
-				}
+		if (info->si_fd > op->highestfd)
+			return (-1);
+
+		dat = TAILQ_FIRST(op->fdtodat[info->si_fd]);
+		while (dat != TAILQ_END(op->fdtodat[info->si_fd])) {
+			next_dat = TAILQ_NEXT(dat, next);
+			if (flags & dat->ev->ev_events) {
+				ev = dat->ev;
+				poll_add(op, ev, dat);
+				activate(ev, flags & ev->ev_events);
+				sigok = 1;
 			}
-
-			for (ev = TAILQ_FIRST(&base->eventqueue);
-			    flags && ev != TAILQ_END(&base->eventqueue);
-			    ev = TAILQ_NEXT(ev, ev_next)) {
-				if (ev->ev_fd == info.si_fd) {
-					if (flags & ev->ev_events) {
-						i = poll_add(op, ev);
-						if (i == -1) return -1;
-						flags &= ~ev->ev_events;
-					}
-					sigok = 1;
+			dat = next_dat;
+		}
+	} else if (signum == SIGIO) {
+		TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+			if (ev->ev_events & (EV_READ|EV_WRITE))
+				poll_add(op, ev, NULL);
+		}
+		return (1); /* 1 means the caller should poll() again */
+    
+	} else if (sigismember(&op->sigs, signum)) {
+		/* managed signals are queued */
+		ev = TAILQ_FIRST(&signalqueue);
+		while (ev != TAILQ_END(&signalqueue)) {
+			next_ev = TAILQ_NEXT(ev, ev_signal_next);
+			if (EVENT_SIGNAL(ev) == signum)
+				activate(ev, EV_SIGNAL);
+			ev = next_ev;
+		}
+	} else {
+		/* dispatch unmanaged signals immediately */
+		struct sigaction sa;
+		if (sigaction(signum, NULL, &sa) == 0) {
+			if ((sa.sa_flags & SA_SIGINFO) && sa.sa_sigaction) {
+				(*sa.sa_sigaction)(signum, info, NULL);
+			} else if (sa.sa_handler) {
+				if ((int)sa.sa_handler != 1)
+					(*sa.sa_handler)(signum);
+			} else {
+				if (signum != SIGCHLD) {
+					/* non-blocked SIG_DFL */
+					kill(gettid(), signum);
 				}
 			}
-
-			if (!sigok) {
-				flags = fcntl(info.si_fd, F_GETFL);
-				if (flags == -1) return -1;
-				fcntl(info.si_fd, F_SETFL, flags & ~O_ASYNC);
-			}
-		} else {
-			TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
-				if (EVENT_SIGNAL(ev) == signum)
-					activate(ev, EV_SIGNAL);
-			}
 		}
 	}
 
-	if (!op->cur)
-		return (0);
+	return (0);
+}
 
-	res = poll(op->poll, op->cur, tv->tv_sec * 1000 + 
-				      (tv->tv_usec + 999) / 1000);
-	if (res < 0)
-		return (-1);
+/*
+ * return 1 if we should poll again
+ * return 0 if we are all set
+ * return -1 on error
+ */
+static inline int
+do_sigwait(struct event_base *base, struct rtsigop *op, struct timespec *ts,
+    sigset_t *sigs)
+{
+	for (;;) {
+		siginfo_t info;
+		int signum;
 
-	i = 0;
-#ifdef HAVE_WORKING_RTSIG
-	while (i < res) {
-#else
-	while (i < op->cur) {
-#endif
-		if (op->poll[i].revents) {
-			int flags = 0;
-			struct event *ev = op->toev[i];
+		signum = sigtimedwait(sigs, &info, ts);
 
-			if (op->poll[i].revents & POLLIN)
-				flags |= EV_READ;
-			if (op->poll[i].revents & POLLOUT)
-				flags |= EV_WRITE;
+		ts->tv_sec = 0;
+		ts->tv_nsec = 0;
 
-			if (!(ev->ev_events & EV_PERSIST)) {
-				event_del(ev);
-				res--;
-			} else {
-				i++;
-			}
-			event_active(ev, flags, 1);
-		} else {
-#ifndef HAVE_WORKING_RTSIG
-			if (op->toev[i]->ev_flags & EVLIST_X_NORT) {
-				i++;
-				res++;
-				continue;
-			}
-#endif
-			for (;;) {
-				op->cur--;
-				if (i == op->cur)
-					break;
-				if (op->poll[op->cur].revents) {
-					memcpy(&op->poll[i], &op->poll[op->cur], sizeof(*op->poll));
-					op->toev[i] = op->toev[op->cur];
-					break;
-				}
-			}
+		if (signum == -1) {
+			if (errno == EAGAIN || errno == EINTR)
+				return (0);
+      			return (-1);
+		} else if (1 == do_siginfo_dispatch(base, op, &info)) {
+			return (1);
 		}
 	}
-#ifdef HAVE_WORKING_RTSIG
-	op->cur = res;
-#endif
 
-	if (!op->cur) {
-		op->max = INIT_MAX;
-		free(op->poll);
-		free(op->toev);
-		/* We just freed it, we shouldn't have a problem getting it back. */
-		op->poll = malloc(sizeof(*op->poll) * op->max);
-		op->toev = malloc(sizeof(*op->toev) * op->max);
+	/* NOTREACHED */
+}
 
-		if (op->poll == NULL || op->toev == NULL)
-			event_err(1, "%s: malloc");
+static inline int
+do_signals_from_socket(struct event_base *base, struct rtsigop *op,
+    struct timespec *ts)
+{
+	int fd = op->signal_recv_fd;
+	siginfo_t info;
+	int res;
+
+	for (;;) {
+		res = recv(fd, &info, sizeof(info), MSG_NOSIGNAL);
+		if (res == -1) {
+			if (errno == EAGAIN)
+				return (0);
+			if (errno == EINTR)
+				continue;
+			return (-1);
+		} else {
+			ts->tv_sec = 0;
+			ts->tv_nsec = 0;
+			if (1 == do_siginfo_dispatch(base, op, &info))
+				return (1);
+		}
 	}
+	/* NOTREACHED */
+}
 
+int
+rtsig_dispatch(struct event_base *base, void *arg, struct timeval *tv)
+{
+	struct rtsigop *op = (struct rtsigop *) arg;
+	struct timespec ts;
+	int res;
+	sigset_t sigs;
+
+	ts.tv_sec = tv->tv_sec;
+	ts.tv_nsec = tv->tv_usec * 1000;
+
+ poll_for_level:
+	res = do_poll(op, &ts); /* ts can be modified in do_XXX() */
+
+	res = do_signals_from_socket(base, op, &ts);
+	if (res == 1)
+		goto poll_for_level;
+	else if (res == -1)
+		return (-1);
+
+	/*
+	 * the mask = managed_signals | unblocked-signals
+	 * MM - if this is not blocking do we need to cast the net this wide?
+	 */
+	sigemptyset(&sigs);
+	sigprocmask(SIG_BLOCK, &sigs, &sigs);
+	signotset(&sigs);
+	sigorset(&sigs, &sigs, &op->sigs);
+
+	res = do_sigwait(base, op, &ts, &sigs);
+
+	if (res == 1)
+		goto poll_for_level;
+	else if (res == -1)
+		return (-1);
+
 	return (0);
 }
+

Modified: trunk/varnish-cache/contrib/libevent/select.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/select.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/select.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -76,6 +76,7 @@
 int select_del		(void *, struct event *);
 int select_recalc	(struct event_base *, void *, int);
 int select_dispatch	(struct event_base *, void *, struct timeval *);
+void select_dealloc     (void *);
 
 const struct eventop selectops = {
 	"select",
@@ -83,7 +84,8 @@
 	select_add,
 	select_del,
 	select_recalc,
-	select_dispatch
+	select_dispatch,
+	select_dealloc
 };
 
 static int select_resize(struct selectop *sop, int fdsz);
@@ -93,7 +95,7 @@
 {
 	struct selectop *sop;
 
-	/* Disable kqueue when this environment variable is set */
+	/* Disable select when this environment variable is set */
 	if (getenv("EVENT_NOSELECT"))
 		return (NULL);
 
@@ -131,7 +133,7 @@
 
 }
 #else
-#define check_selectop(sop)
+#define check_selectop(sop) do {;} while (0)
 #endif
 
 /*
@@ -350,3 +352,25 @@
 	check_selectop(sop);
 	return (0);
 }
+
+void
+select_dealloc(void *arg)
+{
+	struct selectop *sop = arg;
+
+	if (sop->event_readset_in)
+		free(sop->event_readset_in);
+	if (sop->event_writeset_in)
+		free(sop->event_writeset_in);
+	if (sop->event_readset_out)
+		free(sop->event_readset_out);
+	if (sop->event_writeset_out)
+		free(sop->event_writeset_out);
+	if (sop->event_r_by_fd)
+		free(sop->event_r_by_fd);
+	if (sop->event_w_by_fd)
+		free(sop->event_w_by_fd);
+
+	memset(sop, 0, sizeof(struct selectop));
+	free(sop);
+}

Modified: trunk/varnish-cache/contrib/libevent/signal.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/signal.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/signal.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -26,7 +26,9 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
+#ifdef HAVE_CONFIG_H
 #include "config.h"
+#endif
 
 #include <sys/types.h>
 #ifdef HAVE_SYS_TIME_H
@@ -52,7 +54,7 @@
 
 extern struct event_list signalqueue;
 
-static short evsigcaught[NSIG];
+static sig_atomic_t evsigcaught[NSIG];
 static int needrecalc;
 volatile sig_atomic_t evsignal_caught = 0;
 
@@ -61,11 +63,12 @@
 static int ev_signal_added;
 
 /* Callback for when the signal handler write a byte to our signaling socket */
-static void evsignal_cb(int fd, short what, void *arg)
+static void
+evsignal_cb(int fd, short what, void *arg)
 {
 	static char signals[100];
 	struct event *ev = arg;
-	int n;
+	ssize_t n;
 
 	n = read(fd, signals, sizeof(signals));
 	if (n == -1)
@@ -98,6 +101,8 @@
 	FD_CLOSEONEXEC(ev_signal_pair[0]);
 	FD_CLOSEONEXEC(ev_signal_pair[1]);
 
+	fcntl(ev_signal_pair[0], F_SETFL, O_NONBLOCK);
+
 	event_set(&ev_signal, ev_signal_pair[1], EV_READ,
 	    evsignal_cb, &ev_signal);
 	ev_signal.ev_flags |= EVLIST_INTERNAL;
@@ -107,12 +112,12 @@
 evsignal_add(sigset_t *evsigmask, struct event *ev)
 {
 	int evsignal;
-	
+
 	if (ev->ev_events & (EV_READ|EV_WRITE))
 		event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
 	evsignal = EVENT_SIGNAL(ev);
 	sigaddset(evsigmask, evsignal);
-	
+
 	return (0);
 }
 
@@ -135,11 +140,14 @@
 static void
 evsignal_handler(int sig)
 {
+	int save_errno = errno;
+
 	evsigcaught[sig]++;
 	evsignal_caught = 1;
 
 	/* Wake up our notification mechanism */
 	write(ev_signal_pair[0], "a", 1);
+	errno = save_errno;
 }
 
 int
@@ -147,7 +155,7 @@
 {
 	struct sigaction sa;
 	struct event *ev;
-	
+
 	if (!ev_signal_added) {
 		ev_signal_added = 1;
 		event_add(&ev_signal, NULL);
@@ -159,13 +167,13 @@
 
 	if (sigprocmask(SIG_BLOCK, evsigmask, NULL) == -1)
 		return (-1);
-	
+
 	/* Reinstall our signal handler. */
 	memset(&sa, 0, sizeof(sa));
 	sa.sa_handler = evsignal_handler;
 	sa.sa_mask = *evsigmask;
 	sa.sa_flags |= SA_RESTART;
-	
+
 	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
 		if (sigaction(EVENT_SIGNAL(ev), &sa, NULL) == -1)
 			return (-1);
@@ -187,7 +195,7 @@
 evsignal_process(void)
 {
 	struct event *ev;
-	short ncalls;
+	sig_atomic_t ncalls;
 
 	TAILQ_FOREACH(ev, &signalqueue, ev_signal_next) {
 		ncalls = evsigcaught[EVENT_SIGNAL(ev)];

Added: trunk/varnish-cache/contrib/libevent/strlcpy.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/strlcpy.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/strlcpy.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,74 @@
+/*	$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $	*/
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller at courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``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 AUTHOR 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.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include <sys/types.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz.  At most siz-1 characters
+ * will be copied.  Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t
+strlcpy(dst, src, siz)
+	char *dst;
+	const char *src;
+	size_t siz;
+{
+	register char *d = dst;
+	register const char *s = src;
+	register size_t n = siz;
+
+	/* Copy as many bytes as will fit */
+	if (n != 0 && --n != 0) {
+		do {
+			if ((*d++ = *s++) == 0)
+				break;
+		} while (--n != 0);
+	}
+
+	/* Not enough room in dst, add NUL and traverse rest of src */
+	if (n == 0) {
+		if (siz != 0)
+			*d = '\0';		/* NUL-terminate dst */
+		while (*s++)
+			;
+	}
+
+	return(s - src - 1);	/* count does not include NUL */
+}

Modified: trunk/varnish-cache/contrib/libevent/test/Makefile.am
===================================================================
--- trunk/varnish-cache/contrib/libevent/test/Makefile.am	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/test/Makefile.am	2006-04-03 11:59:08 UTC (rev 98)
@@ -4,20 +4,28 @@
 CPPFPLAGS = -I.. 
 CFLAGS = -I../compat @CFLAGS@
 
+EXTRA_DIST = regress.rpc
+
 noinst_PROGRAMS = test-init test-eof test-weof test-time regress bench
 
-test_init_sources = test-init.c
-test_eof_sources = test-eof.c
-test_weof_sources = test-weof.c
-test_time_sources = test-time.c
-regress_sources = regress.c
-bench_sources = bench.c
+BUILT_SOURCES = regress.gen.c regress.gen.h
+test_init_SOURCES = test-init.c
+test_eof_SOURCES = test-eof.c
+test_weof_SOURCES = test-weof.c
+test_time_SOURCES = test-time.c
+regress_SOURCES = regress.c regress.h regress_http.c \
+	regress.gen.c regress.gen.h
+bench_SOURCES = bench.c
 
+regress.gen.c regress.gen.h: regress.rpc
+	../event_rpcgen.py regress.rpc
+
 DISTCLEANFILES = *~
+CLEANFILES = regress.gen.h regress.gen.c
 
 test: test-init test-eof test-weof test-time regress
 
 verify: test
 	@./test.sh
 
-bench test-init test-eof test-weof test-time regress: ../libevent.la
+bench test-init test-eof test-weof test-time: ../libevent.la

Modified: trunk/varnish-cache/contrib/libevent/test/regress.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/test/regress.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/test/regress.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -39,21 +39,28 @@
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #endif
+#include <sys/queue.h>
 #ifndef WIN32
 #include <sys/socket.h>
 #include <sys/signal.h>
 #include <unistd.h>
 #endif
+#include <netdb.h>
 #include <fcntl.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 
-#include <event.h>
+#include "event.h"
+#include "log.h"
+#include "http.h"
 
-static int pair[2];
-static int test_ok;
+#include "regress.h"
+#include "regress.gen.h"
+
+int pair[2];
+int test_ok;
 static int called;
 static char wbuf[4096];
 static char rbuf[4096];
@@ -276,7 +283,7 @@
 }
 
 void
-test1(void)
+test_simpleread(void)
 {
 	struct event ev;
 
@@ -295,7 +302,7 @@
 }
 
 void
-test2(void)
+test_simplewrite(void)
 {
 	struct event ev;
 
@@ -311,7 +318,7 @@
 }
 
 void
-test3(void)
+test_multiple(void)
 {
 	struct event ev, ev2;
 	int i;
@@ -340,7 +347,7 @@
 }
 
 void
-test4(void)
+test_persistent(void)
 {
 	struct event ev, ev2;
 	int i;
@@ -369,7 +376,7 @@
 }
 
 void
-test5(void)
+test_combined(void)
 {
 	struct both r1, r2, w1, w2;
 
@@ -404,7 +411,7 @@
 }
 
 void
-test6(void)
+test_simpletimeout(void)
 {
 	struct timeval tv;
 	struct event ev;
@@ -424,7 +431,7 @@
 
 #ifndef WIN32
 void
-test7(void)
+test_simplesignal(void)
 {
 	struct event ev;
 	struct itimerval itv;
@@ -447,7 +454,7 @@
 #endif
 
 void
-test8(void)
+test_loopexit(void)
 {
 	struct timeval tv, tv_start, tv_end;
 	struct event ev;
@@ -477,6 +484,21 @@
 }
 
 void
+test_evbuffer(void) {
+	setup_test("Evbuffer: ");
+
+	struct evbuffer *evb = evbuffer_new();
+
+	evbuffer_add_printf(evb, "%s/%d", "hello", 1);
+
+	if (EVBUFFER_LENGTH(evb) == 7 &&
+	    strcmp(EVBUFFER_DATA(evb), "hello/1") == 0)
+	    test_ok = 1;
+	
+	cleanup_test();
+}
+
+void
 readcb(struct bufferevent *bev, void *arg)
 {
 	if (EVBUFFER_LENGTH(bev->input) == 8333) {
@@ -499,7 +521,7 @@
 }
 
 void
-test9(void)
+test_bufferevent(void)
 {
 	struct bufferevent *bev1, *bev2;
 	char buffer[8333];
@@ -637,7 +659,211 @@
    cleanup_test();
 }
 
+int decode_int(u_int32_t *pnumber, struct evbuffer *evbuf);
 
+void
+read_once_cb(int fd, short event, void *arg)
+{
+	char buf[256];
+	int len;
+
+	len = read(fd, buf, sizeof(buf));
+
+	if (called) {
+		test_ok = 0;
+	} else if (len) {
+		/* Assumes global pair[0] can be used for writing */
+		write(pair[0], TEST1, strlen(TEST1)+1);
+		test_ok = 1;
+	}
+
+	called++;
+}
+
+void
+test_want_only_once(void)
+{
+	struct event ev;
+	struct timeval tv;
+
+	/* Very simple read test */
+	setup_test("Want read only once: ");
+	
+	write(pair[0], TEST1, strlen(TEST1)+1);
+
+	/* Setup the loop termination */
+	timerclear(&tv);
+	tv.tv_sec = 1;
+	event_loopexit(&tv);
+	
+	event_set(&ev, pair[1], EV_READ, read_once_cb, &ev);
+	if (event_add(&ev, NULL) == -1)
+		exit(1);
+	event_dispatch();
+
+	cleanup_test();
+}
+
+#define TEST_MAX_INT	6
+
+void
+evtag_int_test(void)
+{
+	struct evbuffer *tmp = evbuffer_new();
+	u_int32_t integers[TEST_MAX_INT] = {
+		0xaf0, 0x1000, 0x1, 0xdeadbeef, 0x00, 0xbef000
+	};
+	u_int32_t integer;
+	int i;
+
+	for (i = 0; i < TEST_MAX_INT; i++) {
+		int oldlen, newlen;
+		oldlen = EVBUFFER_LENGTH(tmp);
+		encode_int(tmp, integers[i]);
+		newlen = EVBUFFER_LENGTH(tmp);
+		fprintf(stdout, "\t\tencoded 0x%08x with %d bytes\n",
+		    integers[i], newlen - oldlen);
+	}
+
+	for (i = 0; i < TEST_MAX_INT; i++) {
+		if (decode_int(&integer, tmp) == -1) {
+			fprintf(stderr, "decode %d failed", i);
+			exit(1);
+		}
+		if (integer != integers[i]) {
+			fprintf(stderr, "got %x, wanted %x",
+			    integer, integers[i]);
+			exit(1);
+		}
+	}
+
+	if (EVBUFFER_LENGTH(tmp) != 0) {
+		fprintf(stderr, "trailing data");
+		exit(1);
+	}
+	evbuffer_free(tmp);
+
+	fprintf(stdout, "\t%s: OK\n", __func__);
+}
+
+void
+evtag_fuzz()
+{
+	u_char buffer[4096];
+	struct evbuffer *tmp = evbuffer_new();
+	struct timeval tv;
+	int i, j;
+
+	int not_failed = 0;
+	for (j = 0; j < 100; j++) {
+		for (i = 0; i < sizeof(buffer); i++)
+			buffer[i] = rand();
+		evbuffer_drain(tmp, -1);
+		evbuffer_add(tmp, buffer, sizeof(buffer));
+
+		if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1)
+			not_failed++;
+	}
+
+	/* The majority of decodes should fail */
+	if (not_failed >= 10) {
+		fprintf(stderr, "evtag_unmarshal should have failed");
+		exit(1);
+	}
+
+	/* Now insert some corruption into the tag length field */
+	evbuffer_drain(tmp, -1);
+	timerclear(&tv);
+	tv.tv_sec = 1;
+	evtag_marshal_timeval(tmp, 0, &tv);
+	evbuffer_add(tmp, buffer, sizeof(buffer));
+
+	EVBUFFER_DATA(tmp)[1] = 0xff;
+	if (evtag_unmarshal_timeval(tmp, 0, &tv) != -1) {
+		fprintf(stderr, "evtag_unmarshal_timeval should have failed");
+		exit(1);
+	}
+
+	evbuffer_free(tmp);
+
+	fprintf(stdout, "\t%s: OK\n", __func__);
+}
+
+void
+evtag_test(void)
+{
+	fprintf(stdout, "Testing Tagging:\n");
+
+	evtag_init();
+	evtag_int_test();
+	evtag_fuzz();
+
+	fprintf(stdout, "OK\n");
+}
+
+void
+rpc_test(void)
+{
+	struct msg *msg, *msg2;
+	struct kill *kill;
+	struct run *run;
+	struct evbuffer *tmp = evbuffer_new();
+	int i;
+
+	fprintf(stdout, "Testing RPC: ");
+
+	msg = msg_new();
+	EVTAG_ASSIGN(msg, from_name, "niels");
+	EVTAG_ASSIGN(msg, to_name, "phoenix");
+
+	if (EVTAG_GET(msg, kill, &kill) == -1) {
+		fprintf(stderr, "Failed to set kill message.\n");
+		exit(1);
+	}
+
+	EVTAG_ASSIGN(kill, weapon, "feather");
+	EVTAG_ASSIGN(kill, action, "tickle");
+
+	for (i = 0; i < 3; ++i) {
+		run = EVTAG_ADD(msg, run);
+		if (run == NULL) {
+			fprintf(stderr, "Failed to add run message.\n");
+			exit(1);
+		}
+		EVTAG_ASSIGN(run, how, "very fast");
+	}
+
+	if (msg_complete(msg) == -1) {
+		fprintf(stderr, "Failed to make complete message.\n");
+		exit(1);
+	}
+
+	evtag_marshal_msg(tmp, 0, msg);
+
+	msg2 = msg_new();
+	if (evtag_unmarshal_msg(tmp, 0, msg2) == -1) {
+		fprintf(stderr, "Failed to unmarshal message.\n");
+		exit(1);
+	}
+
+	if (!EVTAG_HAS(msg2, from_name) ||
+	    !EVTAG_HAS(msg2, to_name) ||
+	    !EVTAG_HAS(msg2, kill)) {
+		fprintf(stderr, "Missing data structures.\n");
+		exit(1);
+	}
+
+	if (EVTAG_LEN(msg2, run) != 3) {
+		fprintf(stderr, "Wrong number of run messages.\n");
+		exit(1);
+	}
+
+	msg_free(msg);
+	msg_free(msg2);
+
+	fprintf(stdout, "OK\n");
+}
+
 int
 main (int argc, char **argv)
 {
@@ -656,23 +882,27 @@
 	/* Initalize the event library */
 	event_base = event_init();
 
-	test1();
+	http_suite();
+	
+	test_simpleread();
 
-	test2();
+	test_simplewrite();
 
-	test3();
+	test_multiple();
 
-	test4();
+	test_persistent();
 
-	test5();
+	test_combined();
 
-	test6();
+	test_simpletimeout();
 #ifndef WIN32
-	test7();
+	test_simplesignal();
 #endif
-	test8();
+	test_loopexit();
 
-	test9();
+	test_evbuffer();
+	
+	test_bufferevent();
 
 	test_priorities(1);
 	test_priorities(2);
@@ -680,6 +910,12 @@
 
 	test_multiple_events_for_same_fd();
 
+	test_want_only_once();
+	
+	evtag_test();
+
+	rpc_test();
+
 	return (0);
 }
 

Added: trunk/varnish-cache/contrib/libevent/test/regress.h
===================================================================
--- trunk/varnish-cache/contrib/libevent/test/regress.h	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/test/regress.h	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos at citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+#ifndef _REGRESS_H_
+#define _REGRESS_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void http_suite(void);
+void http_basic_test(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _REGRESS_H_ */

Added: trunk/varnish-cache/contrib/libevent/test/regress.rpc
===================================================================
--- trunk/varnish-cache/contrib/libevent/test/regress.rpc	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/test/regress.rpc	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,17 @@
+/* tests data packing and unpacking */
+
+struct msg {
+	string from_name = 1;
+	string to_name = 2;
+	optional struct[kill] kill = 3;
+	array struct[run] run = 4;
+}
+
+struct kill {
+	string weapon = 1;
+	string action = 2;
+}
+
+struct run {
+	string how = 1;
+}

Added: trunk/varnish-cache/contrib/libevent/test/regress_http.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/test/regress_http.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/test/regress_http.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2003-2006 Niels Provos <provos at citi.umich.edu>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#include <sys/signal.h>
+#include <unistd.h>
+#endif
+#include <netdb.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "event.h"
+#include "log.h"
+#include "http.h"
+
+extern int pair[];
+extern int test_ok;
+
+static struct evhttp *http;
+
+void http_basic_cb(struct evhttp_request *req, void *arg);
+void http_post_cb(struct evhttp_request *req, void *arg);
+
+struct evhttp *
+http_setup(short *pport)
+{
+	int i;
+	struct evhttp *myhttp;
+	short port = -1;
+
+	/* Try a few different ports */
+	for (i = 0; i < 50; ++i) {
+		myhttp = evhttp_start("127.0.0.1", 8080 + i);
+		if (myhttp != NULL) {
+			port = 8080 + i;
+			break;
+		}
+	}
+
+	if (port == -1)
+		event_errx(1, "Could not start web server");
+
+	/* Register a callback for certain types of requests */
+	evhttp_set_cb(myhttp, "/test", http_basic_cb, NULL);
+	evhttp_set_cb(myhttp, "/postit", http_post_cb, NULL);
+
+	*pport = port;
+	return (myhttp);
+}
+
+int
+http_connect(const char *address, u_short port)
+{
+	/* Stupid code for connecting */
+	struct addrinfo ai, *aitop;
+	char strport[NI_MAXSERV];
+	int fd;
+	
+	memset(&ai, 0, sizeof (ai));
+	ai.ai_family = AF_INET;
+	ai.ai_socktype = SOCK_STREAM;
+	snprintf(strport, sizeof (strport), "%d", port);
+	if (getaddrinfo(address, strport, &ai, &aitop) != 0) {
+		event_warn("getaddrinfo");
+		return (-1);
+	}
+        
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+	if (fd == -1)
+		event_err(1, "socket failed");
+
+	if (connect(fd, aitop->ai_addr, aitop->ai_addrlen) == -1)
+		event_err(1, "connect failed");
+
+	freeaddrinfo(aitop);
+
+	return (fd);
+}
+
+void
+http_readcb(struct bufferevent *bev, void *arg)
+{
+	const char *what = "This is funny";
+
+ 	event_debug(("%s: %s\n", __func__, EVBUFFER_DATA(bev->input)));
+	
+	if (evbuffer_find(bev->input, what, strlen(what)) != NULL) {
+		struct evhttp_request *req = evhttp_request_new(NULL, NULL);
+		req->kind = EVHTTP_RESPONSE;
+		int done = evhttp_parse_lines(req, bev->input);
+
+		if (done == 1 &&
+		    evhttp_find_header(req->input_headers,
+			"Content-Type") != NULL)
+			test_ok++;
+		evhttp_request_free(req);
+		bufferevent_disable(bev, EV_READ);
+		event_loopexit(NULL);
+	}
+}
+
+void
+http_writecb(struct bufferevent *bev, void *arg)
+{
+	if (EVBUFFER_LENGTH(bev->output) == 0) {
+		/* enable reading of the reply */
+		bufferevent_enable(bev, EV_READ);
+		test_ok++;
+	}
+}
+
+void
+http_errorcb(struct bufferevent *bev, short what, void *arg)
+{
+	test_ok = -2;
+	event_loopexit(NULL);
+}
+
+void
+http_basic_cb(struct evhttp_request *req, void *arg)
+{
+	event_debug((stderr, "%s: called\n", __func__));
+
+	struct evbuffer *evb = evbuffer_new();
+	evbuffer_add_printf(evb, "This is funny");
+
+	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+	evbuffer_free(evb);
+}
+
+void
+http_basic_test(void)
+{
+	struct bufferevent *bev;
+	int fd;
+	char *http_request;
+	short port = -1;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing Basic HTTP Server: ");
+
+	http = http_setup(&port);
+	
+	fd = http_connect("127.0.0.1", port);
+
+	/* Stupid thing to send a request */
+	bev = bufferevent_new(fd, http_readcb, http_writecb,
+	    http_errorcb, NULL);
+
+	http_request =
+	    "GET /test HTTP/1.1\r\n"
+	    "Host: somehost \r\n"
+	    "\r\n";
+
+	bufferevent_write(bev, http_request, strlen(http_request));
+	
+	event_dispatch();
+
+	bufferevent_free(bev);
+	close(fd);
+
+	evhttp_free(http);
+	
+	if (test_ok != 2) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+void http_connectcb(struct evhttp_connection *evcon, void *arg);
+
+void
+http_connection_test(void)
+{
+	short port = -1;
+	struct evhttp_connection *evcon = NULL;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing Basic HTTP Connection: ");
+
+	http = http_setup(&port);
+
+	evcon = evhttp_connect("127.0.0.1", port, http_connectcb, NULL);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	evhttp_connection_free(evcon);
+	evhttp_free(http);
+	
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+void http_request_done(struct evhttp_request *, void *);
+
+void
+http_connectcb(struct evhttp_connection *evcon, void *arg)
+{
+	struct evhttp_request *req = NULL;
+
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit (1);
+	}
+
+	/*
+	 * At this point, we want to schedule a request to the HTTP
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(http_request_done, NULL);
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+	
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_GET, "/test") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+}
+
+void
+http_request_done(struct evhttp_request *req, void *arg)
+{
+	const char *what = "This is funny";
+
+	if (req->response_code != HTTP_OK) {
+	
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->buffer) != strlen(what)) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+	
+	if (memcmp(EVBUFFER_DATA(req->buffer), what, strlen(what)) != 0) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+/*
+ * HTTP POST test.
+ */
+
+void http_connect_forpostcb(struct evhttp_connection *evcon, void *arg);
+
+void
+http_post_test(void)
+{
+	short port = -1;
+	struct evhttp_connection *evcon = NULL;
+
+	test_ok = 0;
+	fprintf(stdout, "Testing HTTP POST Request: ");
+
+	http = http_setup(&port);
+
+	evcon = evhttp_connect("127.0.0.1", port, http_connect_forpostcb, NULL);
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	event_dispatch();
+
+	evhttp_connection_free(evcon);
+	evhttp_free(http);
+	
+	if (test_ok != 1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	
+	fprintf(stdout, "OK\n");
+}
+
+void http_postrequest_done(struct evhttp_request *, void *);
+
+#define POST_DATA "Okay.  Not really printf"
+
+void
+http_connect_forpostcb(struct evhttp_connection *evcon, void *arg)
+{
+	struct evhttp_request *req = NULL;
+
+	if (evcon == NULL) {
+		fprintf(stdout, "FAILED\n");
+		exit (1);
+	}
+
+	/*
+	 * At this point, we want to schedule an HTTP POST request
+	 * server using our make request method.
+	 */
+
+	req = evhttp_request_new(http_postrequest_done, NULL);
+
+	/* Add the information that we care about */
+	evhttp_add_header(req->output_headers, "Host", "somehost");
+	evbuffer_add_printf(req->buffer, POST_DATA);
+	
+	if (evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/postit") == -1) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+}
+
+void
+http_post_cb(struct evhttp_request *req, void *arg)
+{
+	event_debug((stderr, "%s: called\n", __func__));
+
+	/* Yes, we are expecting a post request */
+	if (req->type != EVHTTP_REQ_POST) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->buffer) != strlen(POST_DATA)) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+
+	if (strcmp(EVBUFFER_DATA(req->buffer), POST_DATA)) {
+		fprintf(stdout, "FAILED\n");
+		exit(1);
+	}
+	
+	struct evbuffer *evb = evbuffer_new();
+	evbuffer_add_printf(evb, "This is funny");
+
+	evhttp_send_reply(req, HTTP_OK, "Everything is fine", evb);
+
+	evbuffer_free(evb);
+}
+
+void
+http_postrequest_done(struct evhttp_request *req, void *arg)
+{
+	const char *what = "This is funny";
+
+	if (req->response_code != HTTP_OK) {
+	
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (evhttp_find_header(req->input_headers, "Content-Type") == NULL) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	if (EVBUFFER_LENGTH(req->buffer) != strlen(what)) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+	
+	if (memcmp(EVBUFFER_DATA(req->buffer), what, strlen(what)) != 0) {
+		fprintf(stderr, "FAILED\n");
+		exit(1);
+	}
+
+	test_ok = 1;
+	event_loopexit(NULL);
+}
+
+
+void
+http_suite(void)
+{
+	http_basic_test();
+	http_connection_test();
+	http_post_test();
+}

Modified: trunk/varnish-cache/contrib/libevent/test/test-weof.c
===================================================================
--- trunk/varnish-cache/contrib/libevent/test/test-weof.c	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/test/test-weof.c	2006-04-03 11:59:08 UTC (rev 98)
@@ -47,7 +47,7 @@
 {
 	struct event ev;
 
-	if (signal(SIGPIPE, SIG_IGN) == SIG_IGN)
+	if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
 		return (1);
 
 	if (socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1)

Modified: trunk/varnish-cache/contrib/libevent/test/test.sh
===================================================================
--- trunk/varnish-cache/contrib/libevent/test/test.sh	2006-04-03 11:05:53 UTC (rev 97)
+++ trunk/varnish-cache/contrib/libevent/test/test.sh	2006-04-03 11:59:08 UTC (rev 98)
@@ -1,17 +1,19 @@
 #!/bin/sh
 
 setup () {
-	 export EVENT_NOKQUEUE=yes
-	 export EVENT_NODEVPOLL=yes
-	 export EVENT_NOPOLL=yes
-	 export EVENT_NOSELECT=yes
-	 export EVENT_NOEPOLL=yes
-	 export EVENT_NORTSIG=yes
+	 EVENT_NOKQUEUE=yes; export EVENT_NOKQUEUE
+	 EVENT_NODEVPOLL=yes; export EVENT_NODEVPOLL
+	 EVENT_NOPOLL=yes; export EVENT_NOPOLL
+	 EVENT_NOSELECT=yes; export EVENT_NOSELECT
+	 EVENT_NOEPOLL=yes; export EVENT_NOEPOLL
+	 EVENT_NORTSIG=yes; export EVENT_NORTSIG
 }
 
 test () {
-	if ! ./test-init 2>/dev/null ;
+	if ./test-init 2>/dev/null ;
 	then
+	        true
+	else
 		echo Skipping test
 		return
 	fi	
@@ -51,31 +53,37 @@
 # Need to do this by hand?
 setup
 unset EVENT_NOKQUEUE
+export EVENT_NOKQUEUE
 echo "KQUEUE"
 test
 
 setup
 unset EVENT_NODEVPOLL
+export EVENT_NODEVPOLL
 echo "DEVPOLL"
 test
 
 setup
 unset EVENT_NOPOLL
+export EVENT_NOPOLL
 echo "POLL"
 test
 
 setup
 unset EVENT_NOSELECT
+export EVENT_NOSELECT
 echo "SELECT"
 test
 
 setup
 unset EVENT_NORTSIG
+export EVENT_NORTSIG
 echo "RTSIG"
 test
 
 setup
 unset EVENT_NOEPOLL
+export EVENT_NOEPOLL
 echo "EPOLL"
 test
 




More information about the varnish-commit mailing list