Index: lib/libevent/Makefile
===================================================================
RCS file: /home/dcvs/src/lib/libevent/Makefile,v
retrieving revision 1.2
diff -u -r1.2 Makefile
--- lib/libevent/Makefile	31 Jan 2008 08:25:12 -0000	1.2
+++ lib/libevent/Makefile	30 Jun 2008 23:55:05 -0000
@@ -4,9 +4,9 @@
 .PATH:	${SRCDIR}
 
 LIB=	event
-SRCS=	buffer.c evbuffer.c evdns.c event-internal.h event.c
+SRCS=	buffer.c evbuffer.c evdns.c event-internal.h event.c evrpc.c evutil.c http.c
 SRCS+=	event_tagging.c kqueue.c log.c log.h poll.c select.c signal.c
-INCS=	event.h evdns.h
+INCS=	event.h evdns.h event-config.h evutil.h
 
 CFLAGS=	-I${.CURDIR} -I. -I${SRCDIR} -DHAVE_CONFIG_H
 
Index: lib/libevent/config.h
===================================================================
RCS file: /home/dcvs/src/lib/libevent/config.h,v
retrieving revision 1.1
diff -u -r1.1 config.h
--- lib/libevent/config.h	30 Jan 2008 12:57:50 -0000	1.1
+++ lib/libevent/config.h	30 Jun 2008 19:57:37 -0000
@@ -1,86 +1,5 @@
-/* $DragonFly: src/lib/libevent/config.h,v 1.1 2008/01/30 12:57:50 hasso Exp $ */
-
 /* config.h.  Generated from config.h.in by configure.  */
 /* config.h.in.  Generated from configure.in by autoheader.  */
-/* Define if kqueue works correctly with pipes */
-#define HAVE_WORKING_KQUEUE 1
-
-/* Define to `unsigned long long' if <sys/types.h> doesn't define.  */
-/* #undef u_int64_t */
-
-/* Define to `unsigned int' if <sys/types.h> doesn't define.  */
-/* #undef u_int32_t */
-
-/* Define to `unsigned short' if <sys/types.h> doesn't define.  */
-/* #undef u_int16_t */
-
-/* Define to `unsigned char' if <sys/types.h> doesn't define.  */
-/* #undef u_int8_t */
-
-/* Define if timeradd is defined in <sys/time.h> */
-#define HAVE_TIMERADD 1
-#ifndef HAVE_TIMERADD
-/* #undef timersub */
-#define timeradd(tvp, uvp, vvp)						\
-	do {								\
-		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;		\
-		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
-		if ((vvp)->tv_usec >= 1000000) {			\
-			(vvp)->tv_sec++;				\
-			(vvp)->tv_usec -= 1000000;			\
-		}							\
-	} while (0)
-#define	timersub(tvp, uvp, vvp)						\
-	do {								\
-		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
-		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
-		if ((vvp)->tv_usec < 0) {				\
-			(vvp)->tv_sec--;				\
-			(vvp)->tv_usec += 1000000;			\
-		}							\
-	} while (0)
-#endif /* !HAVE_TIMERADD */
-
-#define HAVE_TIMERCLEAR 1
-#ifndef HAVE_TIMERCLEAR
-#define	timerclear(tvp)	(tvp)->tv_sec = (tvp)->tv_usec = 0
-#endif
-
-#define HAVE_TIMERCMP 1
-#ifndef HAVE_TIMERCMP
-/* #undef timercmp */
-#define	timercmp(tvp, uvp, cmp)						\
-	(((tvp)->tv_sec == (uvp)->tv_sec) ?				\
-	 ((tvp)->tv_usec cmp (uvp)->tv_usec) :				\
-	 ((tvp)->tv_sec cmp (uvp)->tv_sec))
-#endif
-
-#define HAVE_TIMERISSET 1
-#ifndef HAVE_TIMERISSET
-/* #undef timerisset */
-#define	timerisset(tvp)	((tvp)->tv_sec || (tvp)->tv_usec)
-#endif
-
-/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
-#define HAVE_TAILQFOREACH 1
-#ifndef HAVE_TAILQFOREACH
-#define	TAILQ_FIRST(head)		((head)->tqh_first)
-#define	TAILQ_END(head)			NULL
-#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
-#define TAILQ_FOREACH(var, head, field)					\
-	for((var) = TAILQ_FIRST(head);					\
-	    (var) != TAILQ_END(head);					\
-	    (var) = TAILQ_NEXT(var, field))
-#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
-	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
-	(elm)->field.tqe_next = (listelm);				\
-	*(listelm)->field.tqe_prev = (elm);				\
-	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
-} while (0)
-#endif /* TAILQ_FOREACH */
-
-/* Define to __FUNCTION__ or __file__ if your compiler doesn't have __func__ */
-/* #undef __func__ */
 
 /* Define if clock_gettime is available in libc */
 #define DNS_USE_CPU_CLOCK_FOR_ID 1
@@ -160,21 +79,21 @@
 /* Define to 1 if you have the <port.h> header file. */
 /* #undef HAVE_PORT_H */
 
-/* Define if your system supports POSIX realtime signals */
-/* #undef HAVE_RTSIG */
-
 /* Define to 1 if you have the `select' function. */
 #define HAVE_SELECT 1
 
 /* Define if F_SETFD is defined in <fcntl.h> */
 #define HAVE_SETFD 1
 
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
 /* Define to 1 if you have the <signal.h> header file. */
 #define HAVE_SIGNAL_H 1
 
-/* Define to 1 if you have the `sigtimedwait' function. */
-/* #undef HAVE_SIGTIMEDWAIT */
-
 /* Define to 1 if you have the <stdarg.h> header file. */
 #define HAVE_STDARG_H 1
 
@@ -199,6 +118,9 @@
 /* Define to 1 if you have the `strtok_r' function. */
 #define HAVE_STRTOK_R 1
 
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
 /* Define to 1 if the system has the type `struct in6_addr'. */
 #define HAVE_STRUCT_IN6_ADDR 1
 
@@ -214,12 +136,18 @@
 /* Define to 1 if you have the <sys/ioctl.h> header file. */
 #define HAVE_SYS_IOCTL_H 1
 
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
 /* Define to 1 if you have the <sys/queue.h> header file. */
 #define HAVE_SYS_QUEUE_H 1
 
 /* Define to 1 if you have the <sys/select.h> header file. */
 #define HAVE_SYS_SELECT_H 1
 
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #define HAVE_SYS_STAT_H 1
 
@@ -244,6 +172,18 @@
 /* Define if timerisset is defined in <sys/time.h> */
 #define HAVE_TIMERISSET 1
 
+/* Define to 1 if the system has the type `uint16_t'. */
+#define HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define HAVE_UINT8_T 1
+
 /* Define to 1 if you have the <unistd.h> header file. */
 #define HAVE_UNISTD_H 1
 
@@ -253,9 +193,6 @@
 /* Define if kqueue works correctly with pipes */
 #define HAVE_WORKING_KQUEUE 1
 
-/* Define if realtime signals work on pipes */
-/* #undef HAVE_WORKING_RTSIG */
-
 /* Name of package */
 #define PACKAGE "libevent"
 
@@ -274,6 +211,18 @@
 /* Define to the version of this package. */
 #define PACKAGE_VERSION ""
 
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
 /* Define to 1 if you have the ANSI C header files. */
 #define STDC_HEADERS 1
 
@@ -281,7 +230,7 @@
 #define TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define VERSION "1.3e"
+#define VERSION "1.4.5-stable"
 
 /* Define to appropriate substitue if compiler doesnt have __func__ */
 /* #undef __func__ */
@@ -303,15 +252,3 @@
 
 /* Define to unsigned int if you dont have it */
 /* #undef socklen_t */
-
-/* Define to `unsigned short' if <sys/types.h> does not define. */
-/* #undef uint16_t */
-
-/* Define to `unsigned int' if <sys/types.h> does not define. */
-/* #undef uint32_t */
-
-/* Define to `unsigned long long' if <sys/types.h> does not define. */
-/* #undef uint64_t */
-
-/* Define to `unsigned char' if <sys/types.h> does not define. */
-/* #undef uint8_t */
Index: contrib/libevent/README.DELETED
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/README.DELETED,v
retrieving revision 1.1
diff -u -r1.1 README.DELETED
--- contrib/libevent/README.DELETED	30 Jan 2008 12:52:45 -0000	1.1
+++ contrib/libevent/README.DELETED	30 Jun 2008 21:10:27 -0000
@@ -1,3 +1,4 @@
+autogen.sh
 ChangeLog
 Makefile.am
 Makefile.in
@@ -16,15 +17,13 @@
 epoll.c
 epoll_sub.c
 event_rpcgen.py
-evhttp.h
 evport.c
-http-internal.h
-http.c
 install-sh
 ltmain.sh
 missing
 rtsig.c
 sample/
-strlcpy-internal.h
 strlcpy.c
 test/
+stamp-*
+mkinstalldirs
Index: contrib/libevent/buffer.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/buffer.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 buffer.c
--- contrib/libevent/buffer.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/buffer.c	12 Nov 2007 02:37:32 -0000
@@ -29,6 +29,11 @@
 #include "config.h"
 #endif
 
+#ifdef WIN32
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
 #ifdef HAVE_VASPRINTF
 /* If we have vasprintf, we need to define this before we include stdio.h. */
 #define _GNU_SOURCE
@@ -57,6 +62,7 @@
 #endif
 
 #include "event.h"
+#include "config.h"
 
 struct evbuffer *
 evbuffer_new(void)
@@ -351,12 +357,14 @@
 	u_char *p;
 	size_t oldoff = buf->off;
 	int n = EVBUFFER_MAX_READ;
-#ifdef WIN32
-	DWORD dwBytesRead;
-#endif
 
-#ifdef FIONREAD
+#if defined(FIONREAD)
+#ifdef WIN32
+	long lng = n;
+	if (ioctlsocket(fd, FIONREAD, &lng) == -1 || (n=lng) == 0) {
+#else
 	if (ioctl(fd, FIONREAD, &n) == -1 || n == 0) {
+#endif
 		n = EVBUFFER_MAX_READ;
 	} else if (n > EVBUFFER_MAX_READ && n > howmuch) {
 		/*
@@ -384,18 +392,13 @@
 
 #ifndef WIN32
 	n = read(fd, p, howmuch);
+#else
+	n = recv(fd, p, howmuch, 0);
+#endif
 	if (n == -1)
 		return (-1);
 	if (n == 0)
 		return (0);
-#else
-	n = ReadFile((HANDLE)fd, p, howmuch, &dwBytesRead, NULL);
-	if (n == 0)
-		return (-1);
-	if (dwBytesRead == 0)
-		return (0);
-	n = dwBytesRead;
-#endif
 
 	buf->off += n;
 
@@ -410,24 +413,16 @@
 evbuffer_write(struct evbuffer *buffer, int fd)
 {
 	int n;
-#ifdef WIN32
-	DWORD dwBytesWritten;
-#endif
 
 #ifndef WIN32
 	n = write(fd, buffer->buffer, buffer->off);
+#else
+	n = send(fd, buffer->buffer, buffer->off, 0);
+#endif
 	if (n == -1)
 		return (-1);
 	if (n == 0)
 		return (0);
-#else
-	n = WriteFile((HANDLE)fd, buffer->buffer, buffer->off, &dwBytesWritten, NULL);
-	if (n == 0)
-		return (-1);
-	if (dwBytesWritten == 0)
-		return (0);
-	n = dwBytesWritten;
-#endif
 	evbuffer_drain(buffer, n);
 
 	return (n);
Index: contrib/libevent/evbuffer.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evbuffer.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evbuffer.c
--- contrib/libevent/evbuffer.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/evbuffer.c	28 Apr 2008 02:17:27 -0000
@@ -43,11 +43,15 @@
 #include <stdarg.h>
 #endif
 
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include "evutil.h"
 #include "event.h"
 
 /* prototypes */
 
-void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t);
 void bufferevent_read_pressure_cb(struct evbuffer *, size_t, size_t, void *);
 
 static int
@@ -56,7 +60,7 @@
 	struct timeval tv, *ptv = NULL;
 
 	if (timeout) {
-		timerclear(&tv);
+		evutil_timerclear(&tv);
 		tv.tv_sec = timeout;
 		ptv = &tv;
 	}
@@ -103,8 +107,17 @@
 	 * 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;
+	if (bufev->wm_read.high != 0) {
+		howmuch = bufev->wm_read.high - EVBUFFER_LENGTH(bufev->input);
+		/* we might have lowered the watermark, stop reading */
+		if (howmuch <= 0) {
+			struct evbuffer *buf = bufev->input;
+			event_del(&bufev->ev_read);
+			evbuffer_setcb(buf,
+			    bufferevent_read_pressure_cb, bufev);
+			return;
+		}
+	}
 
 	res = evbuffer_read(bufev->input, fd, howmuch);
 	if (res == -1) {
@@ -126,13 +139,12 @@
 	len = EVBUFFER_LENGTH(bufev->input);
 	if (bufev->wm_read.low != 0 && len < bufev->wm_read.low)
 		return;
-	if (bufev->wm_read.high != 0 && len > bufev->wm_read.high) {
+	if (bufev->wm_read.high != 0 && len >= bufev->wm_read.high) {
 		struct evbuffer *buf = bufev->input;
 		event_del(&bufev->ev_read);
 
-		/* Now schedule a callback for us */
+		/* Now schedule a callback for us when the buffer changes */
 		evbuffer_setcb(buf, bufferevent_read_pressure_cb, bufev);
-		return;
 	}
 
 	/* Invoke the user callback - must always be called last */
@@ -241,11 +253,7 @@
 	event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
 	event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
 
-	bufev->readcb = readcb;
-	bufev->writecb = writecb;
-	bufev->errorcb = errorcb;
-
-	bufev->cbarg = cbarg;
+	bufferevent_setcb(bufev, readcb, writecb, errorcb, cbarg);
 
 	/*
 	 * Set to EV_WRITE so that using bufferevent_write is going to
@@ -257,6 +265,33 @@
 	return (bufev);
 }
 
+void
+bufferevent_setcb(struct bufferevent *bufev,
+    evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg)
+{
+	bufev->readcb = readcb;
+	bufev->writecb = writecb;
+	bufev->errorcb = errorcb;
+
+	bufev->cbarg = cbarg;
+}
+
+void
+bufferevent_setfd(struct bufferevent *bufev, int fd)
+{
+	event_del(&bufev->ev_read);
+	event_del(&bufev->ev_write);
+
+	event_set(&bufev->ev_read, fd, EV_READ, bufferevent_readcb, bufev);
+	event_set(&bufev->ev_write, fd, EV_WRITE, bufferevent_writecb, bufev);
+	if (bufev->ev_base != NULL) {
+		event_base_set(bufev->ev_base, &bufev->ev_read);
+		event_base_set(bufev->ev_base, &bufev->ev_write);
+	}
+
+	/* might have to manually trigger event registration */
+}
+
 int
 bufferevent_priority_set(struct bufferevent *bufev, int priority)
 {
@@ -288,7 +323,7 @@
  */
 
 int
-bufferevent_write(struct bufferevent *bufev, void *data, size_t size)
+bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
 {
 	int res;
 
@@ -404,6 +439,8 @@
 {
 	int res;
 
+	bufev->ev_base = base;
+
 	res = event_base_set(base, &bufev->ev_read);
 	if (res == -1)
 		return (res);
Index: contrib/libevent/evdns.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evdns.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evdns.c
--- contrib/libevent/evdns.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/evdns.c	14 May 2008 04:07:41 -0000
@@ -39,20 +39,20 @@
 #include "config.h"
 #endif
 
-#ifdef WIN32
-#include "misc.h"
+#ifdef DNS_USE_FTIME_FOR_ID
+#include <sys/timeb.h>
 #endif
 
-/* #define NDEBUG */
-
 #ifndef DNS_USE_CPU_CLOCK_FOR_ID
 #ifndef DNS_USE_GETTIMEOFDAY_FOR_ID
 #ifndef DNS_USE_OPENSSL_FOR_ID
+#ifndef DNS_USE_FTIME_FOR_ID
 #error Must configure at least one id generation method.
 #error Please see the documentation.
 #endif
 #endif
 #endif
+#endif
 
 /* #define _POSIX_C_SOURCE 200507 */
 #define _GNU_SOURCE
@@ -78,7 +78,9 @@
 
 #include <string.h>
 #include <fcntl.h>
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
 #ifdef HAVE_STDINT_H
 #include <stdint.h>
 #endif
@@ -86,7 +88,9 @@
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <limits.h>
 #include <sys/stat.h>
 #include <ctype.h>
@@ -94,11 +98,13 @@
 #include <stdarg.h>
 
 #include "evdns.h"
+#include "evutil.h"
 #include "log.h"
 #ifdef WIN32
-#include <windows.h>
 #include <winsock2.h>
+#include <windows.h>
 #include <iphlpapi.h>
+#include <io.h>
 #else
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -109,10 +115,6 @@
 #include <netinet/in6.h>
 #endif
 
-#ifdef WIN32
-typedef int socklen_t;
-#endif
-
 #define EVDNS_LOG_DEBUG 0
 #define EVDNS_LOG_WARN 1
 
@@ -120,26 +122,32 @@
 #define HOST_NAME_MAX 255
 #endif
 
-#ifndef NDEBUG
 #include <stdio.h>
-#endif
 
 #undef MIN
 #define MIN(a,b) ((a)<(b)?(a):(b))
 
 #ifdef __USE_ISOC99B
 /* libevent doesn't work without this */
-typedef uint8_t u_char;
+typedef ev_uint8_t u_char;
 typedef unsigned int uint;
 #endif
 #include <event.h>
 
-#define u64 uint64_t
-#define u32 uint32_t
-#define u16 uint16_t
-#define u8  uint8_t
+#define u64 ev_uint64_t
+#define u32 ev_uint32_t
+#define u16 ev_uint16_t
+#define u8  ev_uint8_t
+
+#ifdef WIN32
+#define snprintf _snprintf
+#define open _open
+#define read _read
+#define close _close
+#define strdup _strdup
+#endif
 
-#define MAX_ADDRS 4  /* maximum number of addresses from a single packet */
+#define MAX_ADDRS 32  /* maximum number of addresses from a single packet */
 /* which we bother recording */
 
 #define TYPE_A         EVDNS_TYPE_A
@@ -319,7 +327,7 @@
 static void evdns_requests_pump_waiting_queue(void);
 static u16 transaction_id_pick(void);
 static struct request *request_new(int type, const char *name, int flags, evdns_callback_type callback, void *ptr);
-static void request_submit(struct request *req);
+static void request_submit(struct request *const req);
 
 static int server_request_free(struct server_request *req);
 static void server_request_free_answers(struct server_request *req);
@@ -352,7 +360,7 @@
 static int
 inet_aton(const char *c, struct in_addr *addr)
 {
-	uint32_t r;
+	ev_uint32_t r;
 	if (strcmp(c, "255.255.255.255") == 0) {
 		addr->s_addr = 0xffffffffu;
 	} else {
@@ -363,17 +371,15 @@
 	}
 	return 1;
 }
-#define CLOSE_SOCKET(x) closesocket(x)
 #else
 #define last_error(sock) (errno)
 #define error_is_eagain(err) ((err) == EAGAIN)
-#define CLOSE_SOCKET(x) close(x)
 #endif
+#define CLOSE_SOCKET(s) EVUTIL_CLOSESOCKET(s)
 
 #define ISSPACE(c) isspace((int)(unsigned char)(c))
 #define ISDIGIT(c) isdigit((int)(unsigned char)(c))
 
-#ifndef NDEBUG
 static const char *
 debug_ntoa(u32 address)
 {
@@ -386,7 +392,6 @@
   		      (int)(u8)((a    )&0xff));
 	return buf;
 }
-#endif
 
 static evdns_debug_log_fn_type evdns_log_fn = NULL;
 
@@ -852,7 +857,7 @@
 		 */
 		SKIP_NAME;
 		j += 4;
-		if (j >= length) goto err;
+		if (j > length) goto err;
 	}
 
 	/* now we have the answer section which looks like
@@ -953,8 +958,7 @@
 	GET16(additional);
 
 	if (flags & 0x8000) return -1; /* Must not be an answer. */
-	if (flags & 0x7800) return -1; /* only standard queries are supported */
-	flags &= 0x0300; /* Only TC and RD get preserved. */
+	flags &= 0x0110; /* Only RD and CD get preserved. */
 
 	server_req = malloc(sizeof(struct server_request));
 	if (server_req == NULL) return -1;
@@ -983,7 +987,7 @@
 		if (!q)
 			goto err;
 		q->type = type;
-		q->class = class;
+		q->dns_question_class = class;
 		memcpy(q->name, tmp_name, namelen+1);
 		server_req->base.questions[server_req->base.nquestions++] = q;
 	}
@@ -992,6 +996,13 @@
 
 	server_req->port = port;
 	port->refcnt++;
+
+	/* Only standard queries are supported. */
+	if (flags & 0x7800) {
+		evdns_server_request_respond(&(server_req->base), DNS_ERR_NOTIMPL);
+		return -1;
+	}
+
 	port->user_callback(&(server_req->base), port->user_data);
 
 	return 0;
@@ -1012,41 +1023,65 @@
 #undef GET8
 }
 
-/* Try to choose a strong transaction id which isn't already in flight */
 static u16
-transaction_id_pick(void) {
-	for (;;) {
-		const struct request *req = req_head, *started_at;
+default_transaction_id_fn(void)
+{
+	u16 trans_id;
 #ifdef DNS_USE_CPU_CLOCK_FOR_ID
-		struct timespec ts;
-		u16 trans_id;
+	struct timespec ts;
 #ifdef CLOCK_MONOTONIC
-		if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
+	if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
 #else
-		if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
+	if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
 #endif
-			event_err(1, "clock_gettime");
-                trans_id = ts.tv_nsec & 0xffff;
+	event_err(1, "clock_gettime");
+	trans_id = ts.tv_nsec & 0xffff;
+#endif
+
+#ifdef DNS_USE_FTIME_FOR_ID
+	struct _timeb tb;
+	_ftime(&tb);
+	trans_id = tb.millitm & 0xffff;
 #endif
 
 #ifdef DNS_USE_GETTIMEOFDAY_FOR_ID
-		struct timeval tv;
-		u16 trans_id;
-		gettimeofday(&tv, NULL);
-                trans_id = tv.tv_usec & 0xffff;
+	struct timeval tv;
+	evutil_gettimeofday(&tv, NULL);
+	trans_id = tv.tv_usec & 0xffff;
 #endif
 
 #ifdef DNS_USE_OPENSSL_FOR_ID
-		u16 trans_id;
-		if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
-			/* in the case that the RAND call fails we back */
-			/* down to using gettimeofday. */
-			struct timeval tv;
-			gettimeofday(&tv, NULL);
-			trans_id = tv.tv_usec & 0xffff; */
-			abort();
-		}
+	if (RAND_pseudo_bytes((u8 *) &trans_id, 2) == -1) {
+		/* in the case that the RAND call fails we back */
+		/* down to using gettimeofday. */
+		/*
+		  struct timeval tv;
+		  evutil_gettimeofday(&tv, NULL);
+		  trans_id = tv.tv_usec & 0xffff;
+		*/
+		abort();
+	}
 #endif
+	return trans_id;
+}
+
+static ev_uint16_t (*trans_id_function)(void) = default_transaction_id_fn;
+
+void
+evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void))
+{
+	if (fn)
+		trans_id_function = fn;
+	else
+		trans_id_function = default_transaction_id_fn;
+}
+
+/* Try to choose a strong transaction id which isn't already in flight */
+static u16
+transaction_id_pick(void) {
+	for (;;) {
+		const struct request *req = req_head, *started_at;
+		u16 trans_id = trans_id_function();
 
 		if (trans_id == 0xffff) continue;
 		/* now check to see if that id is already inflight */
@@ -1472,7 +1507,7 @@
 		return -1;
 	}
 	item->type = type;
-	item->class = class;
+	item->dns_question_class = class;
 	item->ttl = ttl;
 	item->is_name = is_name != 0;
 	item->datalen = 0;
@@ -1587,7 +1622,7 @@
 			return (int) j;
 		}
 		APPEND16(req->base.questions[i]->type);
-		APPEND16(req->base.questions[i]->class);
+		APPEND16(req->base.questions[i]->dns_question_class);
 	}
 
 	/* Add answer, authority, and additional sections. */
@@ -1606,7 +1641,7 @@
 			j = r;
 
 			APPEND16(item->type);
-			APPEND16(item->class);
+			APPEND16(item->dns_question_class);
 			APPEND32(item->ttl);
 			if (item->is_name) {
 				off_t len_idx = j, name_start;
@@ -1616,7 +1651,7 @@
 				if (r < 0)
 					goto overflow;
 				j = r;
-				_t = htons( (j-name_start) );
+				_t = htons( (short) (j-name_start) );
 				memcpy(buf+len_idx, &_t, 2);
 			} else {
 				APPEND16(item->datalen);
@@ -1663,8 +1698,8 @@
 	r = sendto(port->socket, req->response, req->response_len, 0,
 			   (struct sockaddr*) &req->addr, req->addrlen);
 	if (r<0) {
-		int err = last_error(port->socket);
-		if (! error_is_eagain(err))
+		int sock_err = last_error(port->socket);
+		if (! error_is_eagain(sock_err))
 			return -1;
 
 		if (port->pending_replies) {
@@ -1981,7 +2016,8 @@
 	while (1) {
 		struct nameserver *next = server->next;
 		(void) event_del(&server->event);
-		(void) evtimer_del(&server->timeout_event);
+		if (evtimer_initialized(&server->timeout_event))
+			(void) evtimer_del(&server->timeout_event);
 		if (server->socket >= 0)
 			CLOSE_SOCKET(server->socket);
 		free(server);
@@ -2050,14 +2086,7 @@
 
 	ns->socket = socket(PF_INET, SOCK_DGRAM, 0);
 	if (ns->socket < 0) { err = 1; goto out1; }
-#ifdef WIN32
-        {
-		u_long nonblocking = 1;
-		ioctlsocket(ns->socket, FIONBIO, &nonblocking);
-	}
-#else
-        fcntl(ns->socket, F_SETFL, O_NONBLOCK);
-#endif
+        evutil_make_socket_nonblocking(ns->socket);
 	sin.sin_addr.s_addr = address;
 	sin.sin_port = htons(port);
 	sin.sin_family = AF_INET;
@@ -2267,7 +2296,8 @@
 }
 
 int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) {
-	char buf[64];
+	/* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
+	char buf[73];
 	char *cp;
 	struct request *req;
 	int i;
@@ -2280,8 +2310,8 @@
 		*cp++ = "0123456789abcdef"[byte >> 4];
 		*cp++ = '.';
 	}
-	assert(cp + strlen(".ip6.arpa") < buf+sizeof(buf));
-	memcpy(cp, ".ip6.arpa", strlen(".ip6.arpa")+1);
+	assert(cp + strlen("ip6.arpa") < buf+sizeof(buf));
+	memcpy(cp, "ip6.arpa", strlen("ip6.arpa")+1);
 	log(EVDNS_LOG_DEBUG, "Resolve requested for %s (reverse)", buf);
 	req = request_new(TYPE_PTR, buf, flags, callback, ptr);
 	if (!req) return 1;
@@ -2495,7 +2525,7 @@
 			/* this name without a postfix */
 			if (string_num_dots(req->search_origname) < req->search_state->ndots) {
 				/* yep, we need to try it raw */
-				struct request *const newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
+				newreq = request_new(req->request_type, req->search_origname, req->search_flags, req->user_callback, req->user_pointer);
 				log(EVDNS_LOG_DEBUG, "Search: trying raw query %s", req->search_origname);
 				if (newreq) {
 					request_submit(newreq);
@@ -2917,7 +2947,7 @@
 #undef TRY
 }
 
-int
+static int
 evdns_config_windows_nameservers(void)
 {
 	if (load_nameservers_with_getnetworkparams() == 0)
@@ -2931,7 +2961,7 @@
 {
 	int res = 0;
 #ifdef WIN32
-	evdns_config_windows_nameservers();
+	res = evdns_config_windows_nameservers();
 #else
 	res = evdns_resolv_conf_parse(DNS_OPTIONS_ALL, "/etc/resolv.conf");
 #endif
@@ -3029,20 +3059,20 @@
 	for (i = 0; i < req->nquestions; ++i) {
 		u32 ans = htonl(0xc0a80b0bUL);
 		if (req->questions[i]->type == EVDNS_TYPE_A &&
-			req->questions[i]->class == EVDNS_CLASS_INET) {
+			req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
 			printf(" -- replying for %s (A)\n", req->questions[i]->name);
 			r = evdns_server_request_add_a_reply(req, req->questions[i]->name,
 										  1, &ans, 10);
 			if (r<0)
 				printf("eeep, didn't work.\n");
 		} else if (req->questions[i]->type == EVDNS_TYPE_PTR &&
-				   req->questions[i]->class == EVDNS_CLASS_INET) {
+				   req->questions[i]->dns_question_class == EVDNS_CLASS_INET) {
 			printf(" -- replying for %s (PTR)\n", req->questions[i]->name);
 			r = evdns_server_request_add_ptr_reply(req, NULL, req->questions[i]->name,
 											"foo.bar.example.com", 10);
 		} else {
 			printf(" -- skipping %s [%d %d]\n", req->questions[i]->name,
-				   req->questions[i]->type, req->questions[i]->class);
+				   req->questions[i]->type, req->questions[i]->dns_question_class);
 		}
 	}
 
@@ -3085,7 +3115,7 @@
 		int sock;
 		struct sockaddr_in my_addr;
 		sock = socket(PF_INET, SOCK_DGRAM, 0);
-		fcntl(sock, F_SETFL, O_NONBLOCK);
+                evutil_make_socket_nonblocking(sock);
 		my_addr.sin_family = AF_INET;
 		my_addr.sin_port = htons(10053);
 		my_addr.sin_addr.s_addr = INADDR_ANY;
Index: contrib/libevent/evdns.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evdns.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evdns.h
--- contrib/libevent/evdns.h	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/evdns.h	12 Nov 2007 02:37:32 -0000
@@ -47,7 +47,8 @@
  * the source verbatim in their source distributions)
  */
 
-/*
+/** @file evdns.h
+ *
  * Welcome, gentle reader
  *
  * Async DNS lookups are really a whole lot harder than they should be,
@@ -136,85 +137,6 @@
  *  Query: www.abc
  *  Order: www.abc., www.abc.myhome.net
  *
- * API reference:
- *
- * int evdns_nameserver_add(unsigned long int address)
- *   Add a nameserver. The address should be an IP address in
- *   network byte order. The type of address is chosen so that
- *   it matches in_addr.s_addr.
- *   Returns non-zero on error.
- *
- * int evdns_nameserver_ip_add(const char *ip_as_string)
- *   This wraps the above function by parsing a string as an IP
- *   address and adds it as a nameserver.
- *   Returns non-zero on error
- *
- * int evdns_resolve(const char *name, int flags,
- *		      evdns_callback_type callback,
- *		      void *ptr)
- *   Resolve a name. The name parameter should be a DNS name.
- *   The flags parameter should be 0, or DNS_QUERY_NO_SEARCH
- *   which disables searching for this query. (see defn of
- *   searching above).
- *
- *   The callback argument is a function which is called when
- *   this query completes and ptr is an argument which is passed
- *   to that callback function.
- *
- *   Returns non-zero on error
- *
- * void evdns_search_clear()
- *   Clears the list of search domains
- *
- * void evdns_search_add(const char *domain)
- *   Add a domain to the list of search domains
- *
- * void evdns_search_ndots_set(int ndots)
- *   Set the number of dots which, when found in a name, causes
- *   the first query to be without any search domain.
- *
- * int evdns_count_nameservers(void)
- *   Return the number of configured nameservers (not necessarily the
- *   number of running nameservers).  This is useful for double-checking
- *   whether our calls to the various nameserver configuration functions
- *   have been successful.
- *
- * int evdns_clear_nameservers_and_suspend(void)
- *   Remove all currently configured nameservers, and suspend all pending
- *   resolves.  Resolves will not necessarily be re-attempted until
- *   evdns_resume() is called.
- *
- * int evdns_resume(void)
- *   Re-attempt resolves left in limbo after an earlier call to
- *   evdns_clear_nameservers_and_suspend().
- *
- * int evdns_config_windows_nameservers(void)
- *   Attempt to configure a set of nameservers based on platform settings on
- *   a win32 host.  Preferentially tries to use GetNetworkParams; if that fails,
- *   looks in the registry.  Returns 0 on success, nonzero on failure.
- *
- * int evdns_resolv_conf_parse(int flags, const char *filename)
- *   Parse a resolv.conf like file from the given filename.
- *
- *   See the man page for resolv.conf for the format of this file.
- *   The flags argument determines what information is parsed from
- *   this file:
- *     DNS_OPTION_SEARCH - domain, search and ndots options
- *     DNS_OPTION_NAMESERVERS - nameserver lines
- *     DNS_OPTION_MISC - timeout and attempts options
- *     DNS_OPTIONS_ALL - all of the above
- *   The following directives are not parsed from the file:
- *     sortlist, rotate, no-check-names, inet6, debug
- *
- *   Returns non-zero on error:
- *    0 no errors
- *    1 failed to open file
- *    2 failed to stat file
- *    3 file too large
- *    4 out of memory
- *    5 short read from file
- *    6 no nameservers in file
- *
  * Internals:
  *
  * Requests are kept in two queues. The first is the inflight queue. In
@@ -242,27 +164,30 @@
 extern "C" {
 #endif
 
-/* Error codes 0-5 are as described in RFC 1035. */
+/* For integer types. */
+#include <evutil.h>
+
+/** Error codes 0-5 are as described in RFC 1035. */
 #define DNS_ERR_NONE 0
-/* The name server was unable to interpret the query */
+/** The name server was unable to interpret the query */
 #define DNS_ERR_FORMAT 1
-/* The name server was unable to process this query due to a problem with the
+/** The name server was unable to process this query due to a problem with the
  * name server */
 #define DNS_ERR_SERVERFAILED 2
-/* The domain name does not exist */
+/** The domain name does not exist */
 #define DNS_ERR_NOTEXIST 3
-/* The name server does not support the requested kind of query */
+/** The name server does not support the requested kind of query */
 #define DNS_ERR_NOTIMPL 4
-/* The name server refuses to reform the specified operation for policy
+/** The name server refuses to reform the specified operation for policy
  * reasons */
 #define DNS_ERR_REFUSED 5
-/* The reply was truncated or ill-formated */
+/** The reply was truncated or ill-formated */
 #define DNS_ERR_TRUNCATED 65
-/* An unknown error occurred */
+/** An unknown error occurred */
 #define DNS_ERR_UNKNOWN 66
-/* Communication with the server timed out */
+/** Communication with the server timed out */
 #define DNS_ERR_TIMEOUT 67
-/* The request was canceled because the DNS subsystem was shut down. */
+/** The request was canceled because the DNS subsystem was shut down. */
 #define DNS_ERR_SHUTDOWN 68
 
 #define DNS_IPv4_A 1
@@ -276,7 +201,7 @@
 #define DNS_OPTION_MISC 4
 #define DNS_OPTIONS_ALL 7
 
-/* 
+/**
  * The callback that contains the results from a lookup.
  * - type is either DNS_IPv4_A or DNS_PTR or DNS_IPv6_AAAA
  * - count contains the number of addresses of form type
@@ -285,37 +210,261 @@
  */
 typedef void (*evdns_callback_type) (int result, char type, int count, int ttl, void *addresses, void *arg);
 
+/**
+  Initialize the asynchronous DNS library.
+
+  This function initializes support for non-blocking name resolution by
+  calling evdns_resolv_conf_parse() on UNIX and
+  evdns_config_windows_nameservers() on Windows.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_shutdown()
+ */
 int evdns_init(void);
+
+
+/**
+  Shut down the asynchronous DNS resolver and terminate all active requests.
+
+  If the 'fail_requests' option is enabled, all active requests will return
+  an empty result with the error flag set to DNS_ERR_SHUTDOWN. Otherwise,
+  the requests will be silently discarded.
+
+  @param fail_requests if zero, active requests will be aborted; if non-zero,
+		active requests will return DNS_ERR_SHUTDOWN.
+  @see evdns_init()
+ */
 void evdns_shutdown(int fail_requests);
+
+
+/**
+  Convert a DNS error code to a string.
+
+  @param err the DNS error code
+  @return a string containing an explanation of the error code
+*/
 const char *evdns_err_to_string(int err);
+
+
+/**
+  Add a nameserver.
+
+  The address should be an IPv4 address in network byte order.
+  The type of address is chosen so that it matches in_addr.s_addr.
+
+  @param address an IP address in network byte order
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_nameserver_ip_add()
+ */
 int evdns_nameserver_add(unsigned long int address);
+
+
+/**
+  Get the number of configured nameservers.
+
+  This returns the number of configured nameservers (not necessarily the
+  number of running nameservers).  This is useful for double-checking
+  whether our calls to the various nameserver configuration functions
+  have been successful.
+
+  @return the number of configured nameservers
+  @see evdns_nameserver_add()
+ */
 int evdns_count_nameservers(void);
+
+
+/**
+  Remove all configured nameservers, and suspend all pending resolves.
+
+  Resolves will not necessarily be re-attempted until evdns_resume() is called.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resume()
+ */
 int evdns_clear_nameservers_and_suspend(void);
+
+
+/**
+  Resume normal operation and continue any suspended resolve requests.
+
+  Re-attempt resolves left in limbo after an earlier call to
+  evdns_clear_nameservers_and_suspend().
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_clear_nameservers_and_suspend()
+ */
 int evdns_resume(void);
+
+
+/**
+  Add a nameserver.
+
+  This wraps the evdns_nameserver_add() function by parsing a string as an IP
+  address and adds it as a nameserver.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_nameserver_add()
+ */
 int evdns_nameserver_ip_add(const char *ip_as_string);
+
+
+/**
+  Lookup an A record for a given name.
+
+  @param name a DNS hostname
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_ipv6(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
 int evdns_resolve_ipv4(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+  Lookup an AAAA record for a given name.
+
+  @param name a DNS hostname
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_ipv4(), evdns_resolve_reverse(), evdns_resolve_reverse_ipv6()
+ */
 int evdns_resolve_ipv6(const char *name, int flags, evdns_callback_type callback, void *ptr);
+
 struct in_addr;
 struct in6_addr;
+
+/**
+  Lookup a PTR record for a given IP address.
+
+  @param in an IPv4 address
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_reverse_ipv6()
+ */
 int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+  Lookup a PTR record for a given IPv6 address.
+
+  @param in an IPv6 address
+  @param flags either 0, or DNS_QUERY_NO_SEARCH to disable searching for this query.
+  @param callback a callback function to invoke when the request is completed
+  @param ptr an argument to pass to the callback function
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolve_reverse_ipv6()
+ */
 int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr);
+
+
+/**
+  Set the value of a configuration option.
+
+  The currently available configuration options are:
+
+    ndots, timeout, max-timeouts, max-inflight, and attempts
+
+  @param option the name of the configuration option to be modified
+  @param val the value to be set
+  @param flags either 0 | DNS_OPTION_SEARCH | DNS_OPTION_MISC
+  @return 0 if successful, or -1 if an error occurred
+ */
 int evdns_set_option(const char *option, const char *val, int flags);
-int evdns_resolv_conf_parse(int flags, const char *);
+
+
+/**
+  Parse a resolv.conf file.
+
+  The 'flags' parameter determines what information is parsed from the
+  resolv.conf file. See the man page for resolv.conf for the format of this
+  file.
+
+  The following directives are not parsed from the file: sortlist, rotate,
+  no-check-names, inet6, debug.
+
+  If this function encounters an error, the possible return values are: 1 =
+  failed to open file, 2 = failed to stat file, 3 = file too large, 4 = out of
+  memory, 5 = short read from file, 6 = no nameservers listed in the file
+
+  @param flags any of DNS_OPTION_NAMESERVERS|DNS_OPTION_SEARCH|DNS_OPTION_MISC|
+         DNS_OPTIONS_ALL
+  @param filename the path to the resolv.conf file
+  @return 0 if successful, or various positive error codes if an error
+          occurred (see above)
+  @see resolv.conf(3), evdns_config_windows_nameservers()
+ */
+int evdns_resolv_conf_parse(int flags, const char *const filename);
+
+
+/**
+  Obtain nameserver information using the Windows API.
+
+  Attempt to configure a set of nameservers based on platform settings on
+  a win32 host.  Preferentially tries to use GetNetworkParams; if that fails,
+  looks in the registry.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see evdns_resolv_conf_parse()
+ */
 #ifdef MS_WINDOWS
 int evdns_config_windows_nameservers(void);
 #endif
+
+
+/**
+  Clear the list of search domains.
+ */
 void evdns_search_clear(void);
+
+
+/**
+  Add a domain to the list of search domains
+
+  @param domain the domain to be added to the search list
+ */
 void evdns_search_add(const char *domain);
+
+
+/**
+  Set the 'ndots' parameter for searches.
+
+  Sets the number of dots which, when found in a name, causes
+  the first query to be without any search domain.
+
+  @param ndots the new ndots parameter
+ */
 void evdns_search_ndots_set(const int ndots);
 
+/**
+  A callback that is invoked when a log message is generated
+
+  @param is_warning indicates if the log message is a 'warning'
+  @param msg the content of the log message
+ */
 typedef void (*evdns_debug_log_fn_type)(int is_warning, const char *msg);
+
+
+/**
+  Set the callback function to handle log messages.
+
+  @param fn the callback to be invoked when a log message is generated
+ */
 void evdns_set_log_fn(evdns_debug_log_fn_type fn);
 
-#define DNS_NO_SEARCH 1
+/**
+   Set a callback that will be invoked to generate transaction IDs.  By
+   default, we pick transaction IDs based on the current clock time.
 
-#ifdef __cplusplus
-}
-#endif
+   @param fn the new callback, or NULL to use the default.
+ */
+void evdns_set_transaction_id_fn(ev_uint16_t (*fn)(void));
+
+#define DNS_NO_SEARCH 1
 
 /*
  * Structures and functions used to implement a DNS server.
@@ -328,7 +477,15 @@
 };
 struct evdns_server_question {
 	int type;
+#ifdef __cplusplus
+	int dns_question_class;
+#else
+	/* You should refer to this field as "dns_question_class".  The
+	 * name "class" works in C for backward compatibility, and will be
+	 * removed in a future version. (1.5 or later). */
 	int class;
+#define dns_question_class class
+#endif
 	char name[1];
 };
 typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
@@ -353,7 +510,7 @@
 struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
 void evdns_close_server_port(struct evdns_server_port *port);
 
-int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data);
+int evdns_server_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int dns_class, int ttl, int datalen, int is_name, const char *data);
 int evdns_server_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
 int evdns_server_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
 int evdns_server_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *inaddr_name, const char *hostname, int ttl);
@@ -364,4 +521,8 @@
 struct sockaddr;
 int evdns_server_request_get_requesting_addr(struct evdns_server_request *_req, struct sockaddr *sa, int addr_len);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif  /* !EVENTDNS_H */
Index: contrib/libevent/event-config.h
===================================================================
RCS file: contrib/libevent/event-config.h
diff -N contrib/libevent/event-config.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/event-config.h	25 Jun 2008 21:40:51 -0000
@@ -0,0 +1,262 @@
+/* event-config.h
+ * Generated by autoconf; post-processed by libevent.
+ * Do not edit this file.
+ * Do not rely on macros in this file existing in later versions.
+ */
+#ifndef _EVENT_CONFIG_H_
+#define _EVENT_CONFIG_H_
+/* config.h.  Generated from config.h.in by configure.  */
+/* config.h.in.  Generated from configure.in by autoheader.  */
+
+/* Define if clock_gettime is available in libc */
+/* #undef _EVENT_DNS_USE_CPU_CLOCK_FOR_ID */
+
+/* Define is no secure id variant is available */
+#define _EVENT_DNS_USE_GETTIMEOFDAY_FOR_ID 1
+
+/* Define to 1 if you have the `clock_gettime' function. */
+/* #undef _EVENT_HAVE_CLOCK_GETTIME */
+
+/* Define if /dev/poll is available */
+/* #undef _EVENT_HAVE_DEVPOLL */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define _EVENT_HAVE_DLFCN_H 1
+
+/* Define if your system supports the epoll system calls */
+/* #undef _EVENT_HAVE_EPOLL */
+
+/* Define to 1 if you have the `epoll_ctl' function. */
+/* #undef _EVENT_HAVE_EPOLL_CTL */
+
+/* Define if your system supports event ports */
+/* #undef _EVENT_HAVE_EVENT_PORTS */
+
+/* Define to 1 if you have the `fcntl' function. */
+#define _EVENT_HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define _EVENT_HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the `getaddrinfo' function. */
+#define _EVENT_HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `getnameinfo' function. */
+#define _EVENT_HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define _EVENT_HAVE_GETTIMEOFDAY 1
+
+/* Define to 1 if you have the `inet_ntop' function. */
+#define _EVENT_HAVE_INET_NTOP 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define _EVENT_HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `kqueue' function. */
+#define _EVENT_HAVE_KQUEUE 1
+
+/* Define to 1 if you have the `nsl' library (-lnsl). */
+/* #undef _EVENT_HAVE_LIBNSL */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+#define _EVENT_HAVE_LIBRESOLV 1
+
+/* Define to 1 if you have the `rt' library (-lrt). */
+/* #undef _EVENT_HAVE_LIBRT */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef _EVENT_HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define _EVENT_HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netinet/in6.h> header file. */
+/* #undef _EVENT_HAVE_NETINET_IN6_H */
+
+/* Define to 1 if you have the `poll' function. */
+#define _EVENT_HAVE_POLL 1
+
+/* Define to 1 if you have the <poll.h> header file. */
+#define _EVENT_HAVE_POLL_H 1
+
+/* Define to 1 if you have the `port_create' function. */
+/* #undef _EVENT_HAVE_PORT_CREATE */
+
+/* Define to 1 if you have the <port.h> header file. */
+/* #undef _EVENT_HAVE_PORT_H */
+
+/* Define to 1 if you have the `select' function. */
+#define _EVENT_HAVE_SELECT 1
+
+/* Define if F_SETFD is defined in <fcntl.h> */
+#define _EVENT_HAVE_SETFD 1
+
+/* Define to 1 if you have the `sigaction' function. */
+#define _EVENT_HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `signal' function. */
+#define _EVENT_HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define _EVENT_HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define _EVENT_HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define _EVENT_HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define _EVENT_HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define _EVENT_HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define _EVENT_HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define _EVENT_HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strsep' function. */
+#define _EVENT_HAVE_STRSEP 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define _EVENT_HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define _EVENT_HAVE_STRTOLL 1
+
+/* Define to 1 if the system has the type `struct in6_addr'. */
+#define _EVENT_HAVE_STRUCT_IN6_ADDR 1
+
+/* Define to 1 if you have the <sys/devpoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_DEVPOLL_H */
+
+/* Define to 1 if you have the <sys/epoll.h> header file. */
+/* #undef _EVENT_HAVE_SYS_EPOLL_H */
+
+/* Define to 1 if you have the <sys/event.h> header file. */
+#define _EVENT_HAVE_SYS_EVENT_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define _EVENT_HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define _EVENT_HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/queue.h> header file. */
+#define _EVENT_HAVE_SYS_QUEUE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define _EVENT_HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define _EVENT_HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define _EVENT_HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define _EVENT_HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define _EVENT_HAVE_SYS_TYPES_H 1
+
+/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
+#define _EVENT_HAVE_TAILQFOREACH 1
+
+/* Define if timeradd is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERADD 1
+
+/* Define if timerclear is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCLEAR 1
+
+/* Define if timercmp is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERCMP 1
+
+/* Define if timerisset is defined in <sys/time.h> */
+#define _EVENT_HAVE_TIMERISSET 1
+
+/* Define to 1 if the system has the type `uint16_t'. */
+#define _EVENT_HAVE_UINT16_T 1
+
+/* Define to 1 if the system has the type `uint32_t'. */
+#define _EVENT_HAVE_UINT32_T 1
+
+/* Define to 1 if the system has the type `uint64_t'. */
+#define _EVENT_HAVE_UINT64_T 1
+
+/* Define to 1 if the system has the type `uint8_t'. */
+#define _EVENT_HAVE_UINT8_T 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define _EVENT_HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `vasprintf' function. */
+#define _EVENT_HAVE_VASPRINTF 1
+
+/* Define if kqueue works correctly with pipes */
+#define _EVENT_HAVE_WORKING_KQUEUE 1
+
+/* Name of package */
+#define _EVENT_PACKAGE "libevent"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define _EVENT_PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define _EVENT_PACKAGE_NAME ""
+
+/* Define to the full name and version of this package. */
+#define _EVENT_PACKAGE_STRING ""
+
+/* Define to the one symbol short name of this package. */
+#define _EVENT_PACKAGE_TARNAME ""
+
+/* Define to the version of this package. */
+#define _EVENT_PACKAGE_VERSION ""
+
+/* The size of `int', as computed by sizeof. */
+#define _EVENT_SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG 4
+
+/* The size of `long long', as computed by sizeof. */
+#define _EVENT_SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define _EVENT_SIZEOF_SHORT 2
+
+/* Define to 1 if you have the ANSI C header files. */
+#define _EVENT_STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define _EVENT_TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define _EVENT_VERSION "1.4.5-stable"
+
+/* Define to appropriate substitue if compiler doesnt have __func__ */
+/* #undef _EVENT___func__ */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef _EVENT_const */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+   calls it, or to nothing if 'inline' is not supported under any name.  */
+#ifndef _EVENT___cplusplus
+/* #undef _EVENT_inline */
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+/* #undef _EVENT_pid_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef _EVENT_size_t */
+
+/* Define to unsigned int if you dont have it */
+/* #undef _EVENT_socklen_t */
+#endif
Index: contrib/libevent/event-internal.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event-internal.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event-internal.h
--- contrib/libevent/event-internal.h	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/event-internal.h	4 May 2008 00:48:34 -0000
@@ -31,8 +31,21 @@
 extern "C" {
 #endif
 
+#include "config.h"
+#include "min_heap.h"
 #include "evsignal.h"
 
+struct eventop {
+	const char *name;
+	void *(*init)(struct event_base *);
+	int (*add)(void *, struct event *);
+	int (*del)(void *, struct event *);
+	int (*dispatch)(struct event_base *, void *, struct timeval *);
+	void (*dealloc)(struct event_base *, void *);
+	/* set if we need to reinitialize the event base */
+	int need_reinit;
+};
+
 struct event_base {
 	const struct eventop *evsel;
 	void *evbase;
@@ -40,6 +53,7 @@
 	int event_count_active;	/* counts number of active events */
 
 	int event_gotterm;		/* Set to terminate loop */
+	int event_break;		/* Set to terminate loop immediately */
 
 	/* active event management */
 	struct event_list **activequeues;
@@ -51,9 +65,32 @@
 	struct event_list eventqueue;
 	struct timeval event_tv;
 
-	RB_HEAD(event_tree, event) timetree;
+	struct min_heap timeheap;
+
+	struct timeval tv_cache;
 };
 
+/* Internal use only: Functions that might be missing from <sys/queue.h> */
+#ifndef HAVE_TAILQFOREACH
+#define	TAILQ_FIRST(head)		((head)->tqh_first)
+#define	TAILQ_END(head)			NULL
+#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
+#define TAILQ_FOREACH(var, head, field)					\
+	for((var) = TAILQ_FIRST(head);					\
+	    (var) != TAILQ_END(head);					\
+	    (var) = TAILQ_NEXT(var, field))
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	(elm)->field.tqe_next = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
+} while (0)
+#endif /* TAILQ_FOREACH */
+
+int _evsignal_set_handler(struct event_base *base, int evsignal,
+			  void (*fn)(int));
+int _evsignal_restore_handler(struct event_base *base, int evsignal);
+
 #ifdef __cplusplus
 }
 #endif
Index: contrib/libevent/event.3
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event.3,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event.3
--- contrib/libevent/event.3	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/event.3	14 Dec 2007 19:08:14 -0000
@@ -34,10 +34,12 @@
 .Nm event_dispatch ,
 .Nm event_loop ,
 .Nm event_loopexit ,
+.Nm event_loopbreak ,
 .Nm event_set ,
 .Nm event_base_dispatch ,
 .Nm event_base_loop ,
 .Nm event_base_loopexit ,
+.Nm event_base_loopbreak ,
 .Nm event_base_set ,
 .Nm event_base_free ,
 .Nm event_add ,
@@ -78,7 +80,8 @@
 .Nm evbuffer_read ,
 .Nm evbuffer_find ,
 .Nm evbuffer_readline ,
-.Nm evhttp_start ,
+.Nm evhttp_new ,
+.Nm evhttp_bind_socket ,
 .Nm evhttp_free
 .Nd execute a function when a specific event occurs
 .Sh SYNOPSIS
@@ -92,6 +95,8 @@
 .Fn "event_loop" "int flags"
 .Ft int
 .Fn "event_loopexit" "struct timeval *tv"
+.Ft int
+.Fn "event_loopbreak" "void"
 .Ft void
 .Fn "event_set" "struct event *ev" "int fd" "short event" "void (*fn)(int, short, void *)" "void *arg"
 .Ft int
@@ -101,6 +106,8 @@
 .Ft int
 .Fn "event_base_loopexit" "struct event_base *base" "struct timeval *tv"
 .Ft int
+.Fn "event_base_loopbreak" "struct event_base *base"
+.Ft int
 .Fn "event_base_set" "struct event_base *base" "struct event *"
 .Ft void
 .Fn "event_base_free" "struct event_base *base"
@@ -181,9 +188,11 @@
 .Ft "char *"
 .Fn "evbuffer_readline" "struct evbuffer *buf"
 .Ft "struct evhttp *"
-.Fn "evhttp_start" "const char *address" "u_short port"
+.Fn "evhttp_new" "struct event_base *base"
+.Ft int
+.Fn "evhttp_bind_socket" "struct evhttp *http" "const char *address" "u_short port"
 .Ft "void"
-.Fn "evhttp_free" "struct evhttp* http"
+.Fn "evhttp_free" "struct evhttp *http"
 .Ft int
 .Fa (*event_sigcb)(void) ;
 .Ft volatile sig_atomic_t
@@ -205,51 +214,6 @@
 This function only returns on error, and should replace the event core
 of the application program.
 .Pp
-In order to avoid races in signal handlers, the
-.Nm event
-API provides two variables:
-.Va event_sigcb
-and
-.Va event_gotsig .
-A signal handler
-sets
-.Va event_gotsig
-to indicate that a signal has been received.
-The application sets
-.Va event_sigcb
-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
-.Nm event
-library, causing
-.Fn event_dispatch
-to terminate with
-.Va errno
-set to
-.Er EINTR .
-.Pp
-The
-.Nm event_loop
-function provides an interface for single pass execution of pending
-events.
-The flags
-.Va EVLOOP_ONCE
-and
-.Va EVLOOP_NONBLOCK
-are recognized.
-The
-.Nm event_loopexit
-function allows the loop to be terminated after some amount of time
-has passed.
-The parameter indicates the time after which the loop should terminate.
-.Pp
-It is the responsibility of the caller to provide these functions with
-pre-allocated event structures.
-.Pp
 The function
 .Fn event_set
 prepares the event structure
@@ -288,6 +252,11 @@
 .Va EV_READ ,
 or
 .Va EV_WRITE .
+Additionally, an event which has registered interest in more than one of the
+preceeding events, via bitwise-OR to
+.Fn event_set ,
+can provide its callback function with a bitwise-OR of more than one triggered
+event.
 The additional flag
 .Va EV_PERSIST
 makes an
@@ -353,6 +322,59 @@
 If the event has already executed or has never been added
 the call will have no effect.
 .Pp
+The functions
+.Fn evtimer_set ,
+.Fn evtimer_add ,
+.Fn evtimer_del ,
+.Fn evtimer_initialized ,
+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
+.Va EV_TIMEOUT .
+.Pp
+The functions
+.Fn signal_set ,
+.Fn signal_add ,
+.Fn signal_del ,
+.Fn signal_initialized ,
+and
+.Fn signal_pending
+are abbreviations.
+The event type will be a persistent
+.Va EV_SIGNAL .
+That means
+.Fn signal_set
+adds
+.Va EV_PERSIST .
+.Pp
+In order to avoid races in signal handlers, the
+.Nm event
+API provides two variables:
+.Va event_sigcb
+and
+.Va event_gotsig .
+A signal handler
+sets
+.Va event_gotsig
+to indicate that a signal has been received.
+The application sets
+.Va event_sigcb
+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
+.Nm event
+library, causing
+.Fn event_dispatch
+to terminate with
+.Va errno
+set to
+.Er EINTR .
+.Pp
 The function
 .Fn event_once
 is similar to
@@ -385,45 +407,38 @@
 .Fn event_initialized
 macro can be used to check if an event has been initialized.
 .Pp
-The functions
-.Fn evtimer_set ,
-.Fn evtimer_add ,
-.Fn evtimer_del ,
-.Fn evtimer_initialized ,
+The
+.Nm event_loop
+function provides an interface for single pass execution of pending
+events.
+The flags
+.Va EVLOOP_ONCE
 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
-.Va EV_TIMEOUT .
+.Va EVLOOP_NONBLOCK
+are recognized.
+The
+.Nm event_loopexit
+function exits from the event loop. The next
+.Fn event_loop
+iteration after the
+given timer expires will complete normally (handling all queued events) then
+exit without blocking for events again. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
+The
+.Nm event_loopbreak
+function exits from the event loop immediately.
+.Fn event_loop
+will abort after the next event is completed;
+.Fn event_loopbreak
+is typically invoked from this event's callback. This behavior is analogous
+to the "break;" statement. Subsequent invocations of
+.Fn event_loop
+will proceed normally.
 .Pp
-The functions
-.Fn signal_set ,
-.Fn signal_add ,
-.Fn signal_del ,
-.Fn signal_initialized ,
-and
-.Fn signal_pending
-are abbreviations.
-The event type will be a persistent
-.Va EV_SIGNAL .
-That means
-.Fn signal_set
-adds
-.Va EV_PERSIST .
+It is the responsibility of the caller to provide these functions with
+pre-allocated event structures.
 .Pp
-It is possible to disable support for
-.Va epoll , kqueue , devpoll , poll
-or
-.Va select
-by setting the environment variable
-.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
-or
-.Va EVENT_NOSELECT ,
-respectively.
-By setting the environment variable
-.Va EVENT_SHOW_METHOD ,
-.Nm libevent
-displays the kernel notification method that it uses.
 .Sh EVENT PRIORITIES
 By default
 .Nm libevent
@@ -539,7 +554,10 @@
 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 .
+.Fn evhttp_new .
+It can be bound to any port and address with the
+.Fn evhttp_bind_socket
+function.
 When the HTTP server is no longer used, it can be freed via
 .Fn evhttp_free .
 .Pp
@@ -556,6 +574,20 @@
 check
 .Va event.h
 for the public interfaces.
+.Sh ADDITIONAL NOTES
+It is possible to disable support for
+.Va epoll , kqueue , devpoll , poll
+or
+.Va select
+by setting the environment variable
+.Va EVENT_NOEPOLL , EVENT_NOKQUEUE , EVENT_NODEVPOLL , EVENT_NOPOLL
+or
+.Va EVENT_NOSELECT ,
+respectively.
+By setting the environment variable
+.Va EVENT_SHOW_METHOD ,
+.Nm libevent
+displays the kernel notification method that it uses.
 .Sh RETURN VALUES
 Upon successful completion
 .Fn event_add
Index: contrib/libevent/event.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event.c
--- contrib/libevent/event.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/event.c	29 May 2008 06:43:46 -0000
@@ -32,10 +32,8 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #undef WIN32_LEAN_AND_MEAN
-#include "misc.h"
 #endif
 #include <sys/types.h>
-#include <sys/tree.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #else 
@@ -55,6 +53,7 @@
 
 #include "event.h"
 #include "event-internal.h"
+#include "evutil.h"
 #include "log.h"
 
 #ifdef HAVE_EVENT_PORTS
@@ -66,9 +65,6 @@
 #ifdef HAVE_POLL
 extern const struct eventop pollops;
 #endif
-#ifdef HAVE_RTSIG
-extern const struct eventop rtsigops;
-#endif
 #ifdef HAVE_EPOLL
 extern const struct eventop epollops;
 #endif
@@ -96,9 +92,6 @@
 #ifdef HAVE_DEVPOLL
 	&devpollops,
 #endif
-#ifdef HAVE_RTSIG
-	&rtsigops,
-#endif
 #ifdef HAVE_POLL
 	&pollops,
 #endif
@@ -131,20 +124,6 @@
 static void	timeout_process(struct event_base *);
 static void	timeout_correct(struct event_base *, struct timeval *);
 
-static int
-compare(struct event *a, struct event *b)
-{
-	if (timercmp(&a->ev_timeout, &b->ev_timeout, <))
-		return (-1);
-	else if (timercmp(&a->ev_timeout, &b->ev_timeout, >))
-		return (1);
-	if (a < b)
-		return (-1);
-	else if (a > b)
-		return (1);
-	return (0);
-}
-
 static void
 detect_monotonic(void)
 {
@@ -157,12 +136,17 @@
 }
 
 static int
-gettime(struct timeval *tp)
+gettime(struct event_base *base, struct timeval *tp)
 {
-#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
-	struct timespec	ts;
+	if (base->tv_cache.tv_sec) {
+		*tp = base->tv_cache;
+		return (0);
+	}
 
+#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
 	if (use_monotonic) {
+		struct timespec	ts;
+
 		if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
 			return (-1);
 
@@ -172,30 +156,36 @@
 	}
 #endif
 
-	return (gettimeofday(tp, NULL));
+	return (evutil_gettimeofday(tp, NULL));
 }
 
-RB_PROTOTYPE(event_tree, event, ev_timeout_node, compare);
+struct event_base *
+event_init(void)
+{
+	struct event_base *base = event_base_new();
 
-RB_GENERATE(event_tree, event, ev_timeout_node, compare);
+	if (base != NULL)
+		current_base = base;
 
+	return (base);
+}
 
-void *
-event_init(void)
+struct event_base *
+event_base_new(void)
 {
 	int i;
 	struct event_base *base;
 
 	if ((base = calloc(1, sizeof(struct event_base))) == NULL)
-		event_err(1, "%s: calloc");
+		event_err(1, "%s: calloc", __func__);
 
 	event_sigcb = NULL;
 	event_gotsig = 0;
 
 	detect_monotonic();
-	gettime(&base->event_tv);
+	gettime(base, &base->event_tv);
 	
-	RB_INIT(&base->timetree);
+	min_heap_ctor(&base->timeheap);
 	TAILQ_INIT(&base->eventqueue);
 	TAILQ_INIT(&base->sig.signalqueue);
 	base->sig.ev_signal_pair[0] = -1;
@@ -218,27 +208,48 @@
 	/* allocate a single active event queue */
 	event_base_priority_init(base, 1);
 
-	current_base = base;
 	return (base);
 }
 
 void
 event_base_free(struct event_base *base)
 {
-	int i;
+	int i, n_deleted=0;
+	struct event *ev;
 
 	if (base == NULL && current_base)
 		base = current_base;
-        if (base == current_base)
+	if (base == current_base)
 		current_base = NULL;
 
+	/* XXX(niels) - check for internal events first */
 	assert(base);
+	/* Delete all non-internal events. */
+	for (ev = TAILQ_FIRST(&base->eventqueue); ev; ) {
+		struct event *next = TAILQ_NEXT(ev, ev_next);
+		if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+			event_del(ev);
+			++n_deleted;
+		}
+		ev = next;
+	}
+	while ((ev = min_heap_top(&base->timeheap)) != NULL) {
+		event_del(ev);
+		++n_deleted;
+	}
+
+	if (n_deleted)
+		event_debug(("%s: %d events were still set in base",
+					 __func__, n_deleted));
+
 	if (base->evsel->dealloc != NULL)
 		base->evsel->dealloc(base, base->evbase);
-	for (i=0; i < base->nactivequeues; ++i)
+
+	for (i = 0; i < base->nactivequeues; ++i)
 		assert(TAILQ_EMPTY(base->activequeues[i]));
 
-	assert(RB_EMPTY(&base->timetree));
+	assert(min_heap_empty(&base->timeheap));
+	min_heap_dtor(&base->timeheap);
 
 	for (i = 0; i < base->nactivequeues; ++i)
 		free(base->activequeues[i]);
@@ -249,6 +260,34 @@
 	free(base);
 }
 
+/* reinitialized the event base after a fork */
+int
+event_reinit(struct event_base *base)
+{
+	const struct eventop *evsel = base->evsel;
+	void *evbase = base->evbase;
+	int res = 0;
+	struct event *ev;
+
+	/* check if this event mechanism requires reinit */
+	if (!evsel->need_reinit)
+		return (0);
+
+	if (base->evsel->dealloc != NULL)
+		base->evsel->dealloc(base, base->evbase);
+	evbase = base->evbase = evsel->init(base);
+	if (base->evbase == NULL)
+		event_errx(1, "%s: could not reinitialize event mechanism",
+		    __func__);
+
+	TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
+		if (evsel->add(evbase, ev) == -1)
+			res = -1;
+	}
+
+	return (res);
+}
+
 int
 event_priority_init(int npriorities)
 {
@@ -307,9 +346,6 @@
 	int i;
 	short ncalls;
 
-	if (!base->event_count_active)
-		return;
-
 	for (i = 0; i < base->nactivequeues; ++i) {
 		if (TAILQ_FIRST(base->activequeues[i]) != NULL) {
 			activeq = base->activequeues[i];
@@ -320,7 +356,10 @@
 	assert(activeq != NULL);
 
 	for (ev = TAILQ_FIRST(activeq); ev; ev = TAILQ_FIRST(activeq)) {
-		event_queue_remove(base, ev, EVLIST_ACTIVE);
+		if (ev->ev_events & EV_PERSIST)
+			event_queue_remove(base, ev, EVLIST_ACTIVE);
+		else
+			event_del(ev);
 		
 		/* Allows deletes to work */
 		ncalls = ev->ev_ncalls;
@@ -329,7 +368,7 @@
 			ncalls--;
 			ev->ev_ncalls = ncalls;
 			(*ev->ev_callback)((int)ev->ev_fd, ev->ev_res, ev->ev_arg);
-			if (event_gotsig)
+			if (event_gotsig || base->event_break)
 				return;
 		}
 	}
@@ -351,6 +390,13 @@
   return (event_base_loop(event_base, 0));
 }
 
+const char *
+event_base_get_method(struct event_base *base)
+{
+	assert(base);
+	return (base->evsel->name);
+}
+
 static void
 event_loopexit_cb(int fd, short what, void *arg)
 {
@@ -360,20 +406,39 @@
 
 /* not thread safe */
 int
-event_loopexit(struct timeval *tv)
+event_loopexit(const struct timeval *tv)
 {
 	return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
 		    current_base, tv));
 }
 
 int
-event_base_loopexit(struct event_base *event_base, struct timeval *tv)
+event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
 {
 	return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
 		    event_base, tv));
 }
 
 /* not thread safe */
+int
+event_loopbreak(void)
+{
+	return (event_base_loopbreak(current_base));
+}
+
+int
+event_base_loopbreak(struct event_base *event_base)
+{
+	if (event_base == NULL)
+		return (-1);
+
+	event_base->event_break = 1;
+	return (0);
+}
+
+
+
+/* not thread safe */
 
 int
 event_loop(int flags)
@@ -390,22 +455,21 @@
 	struct timeval *tv_p;
 	int res, done;
 
-#ifndef WIN32
 	if(!TAILQ_EMPTY(&base->sig.signalqueue))
 		evsignal_base = base;
-#endif
 	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;
 			break;
 		}
 
+		if (base->event_break) {
+			base->event_break = 0;
+			break;
+		}
+
 		/* You cannot use this interface for multi-threaded apps */
 		while (event_gotsig) {
 			event_gotsig = 0;
@@ -428,7 +492,7 @@
 			 * if we have active events, we just poll new events
 			 * without waiting.
 			 */
-			timerclear(&tv);
+			evutil_timerclear(&tv);
 		}
 		
 		/* If we have no events, we just exit */
@@ -437,11 +501,17 @@
 			return (1);
 		}
 
-		res = evsel->dispatch(base, evbase, tv_p);
+		/* update last old time */
+		gettime(base, &base->event_tv);
+
+		/* clear time cache */
+		base->tv_cache.tv_sec = 0;
 
+		res = evsel->dispatch(base, evbase, tv_p);
 
 		if (res == -1)
 			return (-1);
+		gettime(base, &base->tv_cache);
 
 		timeout_process(base);
 
@@ -480,7 +550,7 @@
 /* not threadsafe, event scheduled once. */
 int
 event_once(int fd, short events,
-    void (*callback)(int, short, void *), void *arg, struct timeval *tv)
+    void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
 {
 	return event_base_once(current_base, fd, events, callback, arg, tv);
 }
@@ -488,7 +558,7 @@
 /* Schedules an event once */
 int
 event_base_once(struct event_base *base, int fd, short events,
-    void (*callback)(int, short, void *), void *arg, struct timeval *tv)
+    void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
 {
 	struct event_once *eonce;
 	struct timeval etv;
@@ -506,7 +576,7 @@
 
 	if (events == EV_TIMEOUT) {
 		if (tv == NULL) {
-			timerclear(&etv);
+			evutil_timerclear(&etv);
 			tv = &etv;
 		}
 
@@ -548,6 +618,8 @@
 	ev->ev_ncalls = 0;
 	ev->ev_pncalls = NULL;
 
+	min_heap_elem_init(ev);
+
 	/* by default, we put new events into the middle priority */
 	if(current_base)
 		ev->ev_pri = current_base->nactivequeues/2;
@@ -607,18 +679,18 @@
 
 	/* See if there is a timeout that we should report */
 	if (tv != NULL && (flags & event & EV_TIMEOUT)) {
-		gettime(&now);
-		timersub(&ev->ev_timeout, &now, &res);
+		gettime(ev->ev_base, &now);
+		evutil_timersub(&ev->ev_timeout, &now, &res);
 		/* correctly remap to real time */
-		gettimeofday(&now, NULL);
-		timeradd(&now, &res, tv);
+		evutil_gettimeofday(&now, NULL);
+		evutil_timeradd(&now, &res, tv);
 	}
 
 	return (flags & event);
 }
 
 int
-event_add(struct event *ev, struct timeval *tv)
+event_add(struct event *ev, const struct timeval *tv)
 {
 	struct event_base *base = ev->ev_base;
 	const struct eventop *evsel = base->evsel;
@@ -639,6 +711,9 @@
 
 		if (ev->ev_flags & EVLIST_TIMEOUT)
 			event_queue_remove(base, ev, EVLIST_TIMEOUT);
+		else if (min_heap_reserve(&base->timeheap,
+			1 + min_heap_size(&base->timeheap)) == -1)
+		    return (-1);  /* ENOMEM == errno */
 
 		/* Check if it is active due to a timeout.  Rescheduling
 		 * this timeout before the callback can be executed
@@ -656,8 +731,8 @@
 			event_queue_remove(base, ev, EVLIST_ACTIVE);
 		}
 
-		gettime(&now);
-		timeradd(&now, tv, &ev->ev_timeout);
+		gettime(base, &now);
+		evutil_timeradd(&now, tv, &ev->ev_timeout);
 
 		event_debug((
 			 "event_add: timeout in %d seconds, call %p",
@@ -668,14 +743,18 @@
 
 	if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
 	    !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
-		event_queue_insert(base, ev, EVLIST_INSERTED);
+		int res = evsel->add(evbase, ev);
+		if (res != -1)
+			event_queue_insert(base, ev, EVLIST_INSERTED);
 
-		return (evsel->add(evbase, ev));
+		return (res);
 	} else if ((ev->ev_events & EV_SIGNAL) &&
 	    !(ev->ev_flags & EVLIST_SIGNAL)) {
-		event_queue_insert(base, ev, EVLIST_SIGNAL);
+		int res = evsel->add(evbase, ev);
+		if (res != -1)
+			event_queue_insert(base, ev, EVLIST_SIGNAL);
 
-		return (evsel->add(evbase, ev));
+		return (res);
 	}
 
 	return (0);
@@ -746,21 +825,21 @@
 	struct event *ev;
 	struct timeval *tv = *tv_p;
 
-	if ((ev = RB_MIN(event_tree, &base->timetree)) == NULL) {
+	if ((ev = min_heap_top(&base->timeheap)) == NULL) {
 		/* if no time-based events are active wait for I/O */
 		*tv_p = NULL;
 		return (0);
 	}
 
-	if (gettime(&now) == -1)
+	if (gettime(base, &now) == -1)
 		return (-1);
 
-	if (timercmp(&ev->ev_timeout, &now, <=)) {
-		timerclear(tv);
+	if (evutil_timercmp(&ev->ev_timeout, &now, <=)) {
+		evutil_timerclear(tv);
 		return (0);
 	}
 
-	timersub(&ev->ev_timeout, &now, tv);
+	evutil_timersub(&ev->ev_timeout, &now, tv);
 
 	assert(tv->tv_sec >= 0);
 	assert(tv->tv_usec >= 0);
@@ -778,45 +857,50 @@
 static void
 timeout_correct(struct event_base *base, struct timeval *tv)
 {
-	struct event *ev;
+	struct event **pev;
+	unsigned int size;
 	struct timeval off;
 
 	if (use_monotonic)
 		return;
 
 	/* Check if time is running backwards */
-	gettime(tv);
-	if (timercmp(tv, &base->event_tv, >=)) {
+	gettime(base, tv);
+	if (evutil_timercmp(tv, &base->event_tv, >=)) {
 		base->event_tv = *tv;
 		return;
 	}
 
 	event_debug(("%s: time is running backwards, corrected",
 		    __func__));
-	timersub(&base->event_tv, tv, &off);
+	evutil_timersub(&base->event_tv, tv, &off);
 
 	/*
 	 * We can modify the key element of the node without destroying
 	 * the key, beause we apply it to all in the right order.
 	 */
-	RB_FOREACH(ev, event_tree, &base->timetree)
-		timersub(&ev->ev_timeout, &off, &ev->ev_timeout);
+	pev = base->timeheap.p;
+	size = base->timeheap.n;
+	for (; size-- > 0; ++pev) {
+		struct timeval *ev_tv = &(**pev).ev_timeout;
+		evutil_timersub(ev_tv, &off, ev_tv);
+	}
 }
 
 void
 timeout_process(struct event_base *base)
 {
 	struct timeval now;
-	struct event *ev, *next;
+	struct event *ev;
 
-	gettime(&now);
+	if (min_heap_empty(&base->timeheap))
+		return;
 
-	for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) {
-		if (timercmp(&ev->ev_timeout, &now, >))
-			break;
-		next = RB_NEXT(event_tree, &base->timetree, ev);
+	gettime(base, &now);
 
-		event_queue_remove(base, ev, EVLIST_TIMEOUT);
+	while ((ev = min_heap_top(&base->timeheap))) {
+		if (evutil_timercmp(&ev->ev_timeout, &now, >))
+			break;
 
 		/* delete this event from the I/O queues */
 		event_del(ev);
@@ -830,34 +914,28 @@
 void
 event_queue_remove(struct event_base *base, struct event *ev, int queue)
 {
-	int docount = 1;
-
 	if (!(ev->ev_flags & queue))
 		event_errx(1, "%s: %p(fd %d) not on queue %x", __func__,
 			   ev, ev->ev_fd, queue);
 
-	if (ev->ev_flags & EVLIST_INTERNAL)
-		docount = 0;
-
-	if (docount)
+	if (~ev->ev_flags & EVLIST_INTERNAL)
 		base->event_count--;
 
 	ev->ev_flags &= ~queue;
 	switch (queue) {
+	case EVLIST_INSERTED:
+		TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
+		break;
 	case EVLIST_ACTIVE:
-		if (docount)
-			base->event_count_active--;
+		base->event_count_active--;
 		TAILQ_REMOVE(base->activequeues[ev->ev_pri],
 		    ev, ev_active_next);
 		break;
-	case EVLIST_SIGNAL:
-		TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next);
-		break;
 	case EVLIST_TIMEOUT:
-		RB_REMOVE(event_tree, &base->timetree, ev);
+		min_heap_erase(&base->timeheap, ev);
 		break;
-	case EVLIST_INSERTED:
-		TAILQ_REMOVE(&base->eventqueue, ev, ev_next);
+	case EVLIST_SIGNAL:
+		TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next);
 		break;
 	default:
 		event_errx(1, "%s: unknown queue %x", __func__, queue);
@@ -867,8 +945,6 @@
 void
 event_queue_insert(struct event_base *base, struct event *ev, int queue)
 {
-	int docount = 1;
-
 	if (ev->ev_flags & queue) {
 		/* Double insertion is possible for active events */
 		if (queue & EVLIST_ACTIVE)
@@ -878,30 +954,25 @@
 			   ev, ev->ev_fd, queue);
 	}
 
-	if (ev->ev_flags & EVLIST_INTERNAL)
-		docount = 0;
-
-	if (docount)
+	if (~ev->ev_flags & EVLIST_INTERNAL)
 		base->event_count++;
 
 	ev->ev_flags |= queue;
 	switch (queue) {
+	case EVLIST_INSERTED:
+		TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
+		break;
 	case EVLIST_ACTIVE:
-		if (docount)
-			base->event_count_active++;
+		base->event_count_active++;
 		TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
 		    ev,ev_active_next);
 		break;
-	case EVLIST_SIGNAL:
-		TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next);
-		break;
 	case EVLIST_TIMEOUT: {
-		struct event *tmp = RB_INSERT(event_tree, &base->timetree, ev);
-		assert(tmp == NULL);
+		min_heap_push(&base->timeheap, ev);
 		break;
 	}
-	case EVLIST_INSERTED:
-		TAILQ_INSERT_TAIL(&base->eventqueue, ev, ev_next);
+	case EVLIST_SIGNAL:
+		TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next);
 		break;
 	default:
 		event_errx(1, "%s: unknown queue %x", __func__, queue);
Index: contrib/libevent/event.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event.h
--- contrib/libevent/event.h	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/event.h	29 May 2008 06:43:46 -0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Niels Provos <provos@citi.umich.edu>
+ * Copyright (c) 2000-2007 Niels Provos <provos@citi.umich.edu>
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,14 +27,153 @@
 #ifndef _EVENT_H_
 #define _EVENT_H_
 
+/** @mainpage
+
+  @section intro Introduction
+
+  libevent is an event notification library for developing scalable network
+  servers.  The libevent API provides a mechanism to execute a callback
+  function when a specific event occurs on a file descriptor or after a
+  timeout has been reached. Furthermore, libevent also support callbacks due
+  to signals or regular timeouts.
+
+  libevent is meant to replace the event loop found in event driven network
+  servers. An application just needs to call event_dispatch() and then add or
+  remove events dynamically without having to change the event loop.
+
+  Currently, libevent supports /dev/poll, kqueue(2), select(2), poll(2) and
+  epoll(4). It also has experimental support for real-time signals. The
+  internal event mechanism is completely independent of the exposed event API,
+  and a simple update of libevent can provide new functionality without having
+  to redesign the applications. As a result, Libevent allows for portable
+  application development and provides the most scalable event notification
+  mechanism available on an operating system. Libevent can also be used for
+  multi-threaded aplications; see Steven Grimm's explanation. Libevent should
+  compile on Linux, *BSD, Mac OS X, Solaris and Windows.
+
+  @section usage Standard usage
+
+  Every program that uses libevent must include the <event.h> header, and pass
+  the -levent flag to the linker.  Before using any of the functions in the
+  library, you must call event_init() or event_base_new() to perform one-time
+  initialization of the libevent library.
+
+  @section event Event notification
+
+  For each file descriptor that you wish to monitor, you must declare an event
+  structure and call event_set() to initialize the members of the structure.
+  To enable notification, you add the structure to the list of monitored
+  events by calling event_add().  The event structure must remain allocated as
+  long as it is active, so it should be allocated on the heap. Finally, you
+  call event_dispatch() to loop and dispatch events.
+
+  @section bufferevent I/O Buffers
+
+  libevent provides an abstraction on top of the regular event callbacks. This
+  abstraction is called a buffered event. 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 I/O, but instead is reading
+  from input and writing to output buffers.
+
+  Once initialized via bufferevent_new(), the bufferevent structure can be
+  used repeatedly with bufferevent_enable() and bufferevent_disable().
+  Instead of reading and writing directly to a socket, you would call
+  bufferevent_read() and bufferevent_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 0 by
+  default.
+
+  @section timers Timers
+
+  libevent can also be used to create timers that invoke a callback after a
+  certain amount of time has expired. The evtimer_set() function prepares an
+  event struct to be used as a timer. To activate the timer, call
+  evtimer_add(). Timers can be deactivated by calling evtimer_del().
+
+  @section timeouts Timeouts
+
+  In addition to simple timers, libevent can assign timeout events to file
+  descriptors that are triggered whenever a certain amount of time has passed
+  with no activity on a file descriptor.  The timeout_set() function
+  initializes an event struct for use as a timeout. Once initialized, the
+  event must be activated by using timeout_add().  To cancel the timeout, call
+  timeout_del().
+
+  @section evdns Asynchronous DNS resolution
+
+  libevent provides an asynchronous DNS resolver that should be used instead
+  of the standard DNS resolver functions.  These functions can be imported by
+  including the <evdns.h> header in your program. Before using any of the
+  resolver functions, you must call evdns_init() to initialize the library. To
+  convert a hostname to an IP address, you call the evdns_resolve_ipv4()
+  function.  To perform a reverse lookup, you would call the
+  evdns_resolve_reverse() function.  All of these functions use callbacks to
+  avoid blocking while the lookup is performed.
+
+  @section evhttp Event-driven HTTP servers
+
+  libevent provides a very simple event-driven HTTP server that can be
+  embedded in your program and used to service HTTP requests.
+
+  To use this capability, you need to include the <evhttp.h> header in your
+  program.  You create the server by calling evhttp_new(). Add addresses and
+  ports to listen on with evhttp_bind_socket(). You then register one or more
+  callbacks to handle incoming requests.  Each URI can be assigned a callback
+  via the evhttp_set_cb() function.  A generic callback function can also be
+  registered via evhttp_set_gencb(); this callback will be invoked if no other
+  callbacks have been registered for a given URI.
+
+  @section evrpc A framework for RPC servers and clients
+ 
+  libevents provides a framework for creating RPC servers and clients.  It
+  takes care of marshaling and unmarshaling all data structures.
+
+  @section api API Reference
+
+  To browse the complete documentation of the libevent API, click on any of
+  the following links.
+
+  event.h
+  The primary libevent header
+
+  evdns.h
+  Asynchronous DNS resolution
+
+  evhttp.h
+  An embedded libevent-based HTTP server
+
+  evrpc.h
+  A framework for creating RPC servers and clients
+
+ */
+
+/** @file event.h
+
+  A library for writing event-driven network servers
+
+ */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+#include <event-config.h>
+#ifdef _EVENT_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_TIME_H
 #include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_STDINT_H
 #include <stdint.h>
+#endif
 #include <stdarg.h>
 
+/* For int types. */
+#include <evutil.h>
+
 #ifdef WIN32
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
@@ -68,25 +207,16 @@
 	struct type **tqe_prev;	/* address of previous next element */	\
 }
 #endif /* !TAILQ_ENTRY */
-#ifndef RB_ENTRY
-#define _EVENT_DEFINED_RBENTRY
-#define RB_ENTRY(type)							\
-struct {								\
-	struct type *rbe_left;		/* left element */		\
-	struct type *rbe_right;		/* right element */		\
-	struct type *rbe_parent;	/* parent element */		\
-	int rbe_color;			/* node color */		\
-}
-#endif /* !RB_ENTRY */
 
 struct event_base;
 struct event {
 	TAILQ_ENTRY (event) ev_next;
 	TAILQ_ENTRY (event) ev_active_next;
 	TAILQ_ENTRY (event) ev_signal_next;
-	RB_ENTRY (event) ev_timeout_node;
+	unsigned int min_heap_idx;	/* for managing timeouts */
 
 	struct event_base *ev_base;
+
 	int ev_fd;
 	short ev_events;
 	short ev_ncalls;
@@ -126,52 +256,253 @@
 TAILQ_HEAD (event_list, event);
 TAILQ_HEAD (evkeyvalq, evkeyval);
 #endif /* _EVENT_DEFINED_TQENTRY */
-#ifdef _EVENT_DEFINED_RBENTRY
-#undef RB_ENTRY
-#undef _EVENT_DEFINED_RBENTRY
-#endif /* _EVENT_DEFINED_RBENTRY */
-
-struct eventop {
-	char *name;
-	void *(*init)(struct event_base *);
-	int (*add)(void *, struct event *);
-	int (*del)(void *, struct event *);
-	int (*recalc)(struct event_base *, void *, int);
-	int (*dispatch)(struct event_base *, void *, struct timeval *);
-	void (*dealloc)(struct event_base *, void *);
-};
 
-void *event_init(void);
+/**
+  Initialize the event API.
+
+  Use event_base_new() to initialize a new event base, but does not set
+  the current_base global.   If using only event_base_new(), each event
+  added must have an event base set with event_base_set()
+
+  @see event_base_set(), event_base_free(), event_init()
+ */
+struct event_base *event_base_new(void);
+
+/**
+  Initialize the event API.
+
+  The event API needs to be initialized with event_init() before it can be
+  used.  Sets the current_base global representing the default base for
+  events that have no base associated with them.
+
+  @see event_base_set(), event_base_new()
+ */
+struct event_base *event_init(void);
+
+/**
+  Reinitialized the event base after a fork
+
+  Some event mechanisms do not survive across fork.   The event base needs
+  to be reinitialized with the event_reinit() function.
+
+  @param base the event base that needs to be re-initialized
+  @return 0 if successful, or -1 if some events could not be re-added.
+  @see event_base_new(), event_init()
+*/
+int event_reinit(struct event_base *base);
+
+/**
+  Loop to process events.
+
+  In order to process events, an application needs to call
+  event_dispatch().  This function only returns on error, and should
+  replace the event core of the application program.
+
+  @see event_base_dispatch()
+ */
 int event_dispatch(void);
+
+
+/**
+  Threadsafe event dispatching loop.
+
+  @param eb the event_base structure returned by event_init()
+  @see event_init(), event_dispatch()
+ */
 int event_base_dispatch(struct event_base *);
+
+
+/**
+ Get the kernel event notification mechanism used by libevent.
+ 
+ @param eb the event_base structure returned by event_base_new()
+ @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
+const char *event_base_get_method(struct event_base *);
+        
+        
+/**
+  Deallocate all memory associated with an event_base, and free the base.
+
+  Note that this function will not close any fds or free any memory passed
+  to event_set as the argument to callback.
+
+  @param eb an event_base to be freed
+ */
 void event_base_free(struct event_base *);
 
+
 #define _EVENT_LOG_DEBUG 0
 #define _EVENT_LOG_MSG   1
 #define _EVENT_LOG_WARN  2
 #define _EVENT_LOG_ERR   3
 typedef void (*event_log_cb)(int severity, const char *msg);
+/**
+  Redirect libevent's log messages.
+
+  @param cb a function taking two arguments: an integer severity between
+     _EVENT_LOG_DEBUG and _EVENT_LOG_ERR, and a string.  If cb is NULL,
+	 then the default log is used.
+  */
 void event_set_log_callback(event_log_cb cb);
 
-/* Associate a different event base with an event */
+/**
+  Associate a different event base with an event.
+
+  @param eb the event base
+  @param ev the event
+ */
 int event_base_set(struct event_base *, struct event *);
 
-#define EVLOOP_ONCE	0x01
-#define EVLOOP_NONBLOCK	0x02
+/**
+ event_loop() flags
+ */
+/*@{*/
+#define EVLOOP_ONCE	0x01	/**< Block at most once. */
+#define EVLOOP_NONBLOCK	0x02	/**< Do not block. */
+/*@}*/
+
+/**
+  Handle events.
+
+  This is a more flexible version of event_dispatch().
+
+  @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+  @return 0 if successful, -1 if an error occurred, or 1 if no events were
+    registered.
+  @see event_loopexit(), event_base_loop()
+*/
 int event_loop(int);
+
+/**
+  Handle events (threadsafe version).
+
+  This is a more flexible version of event_base_dispatch().
+
+  @param eb the event_base structure returned by event_init()
+  @param flags any combination of EVLOOP_ONCE | EVLOOP_NONBLOCK
+  @return 0 if successful, -1 if an error occurred, or 1 if no events were
+    registered.
+  @see event_loopexit(), event_base_loop()
+  */
 int event_base_loop(struct event_base *, int);
-int event_loopexit(struct timeval *);	/* Causes the loop to exit */
-int event_base_loopexit(struct event_base *, struct timeval *);
 
+/**
+  Exit the event loop after the specified time.
+
+  The next event_loop() iteration after the given timer expires will
+  complete normally (handling all queued events) then exit without
+  blocking for events again.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @param tv the amount of time after which the loop should terminate.
+  @return 0 if successful, or -1 if an error occurred
+  @see event_loop(), event_base_loop(), event_base_loopexit()
+  */
+int event_loopexit(const struct timeval *);
+
+
+/**
+  Exit the event loop after the specified time (threadsafe variant).
+
+  The next event_base_loop() iteration after the given timer expires will
+  complete normally (handling all queued events) then exit without
+  blocking for events again.
+
+  Subsequent invocations of event_base_loop() will proceed normally.
+
+  @param eb the event_base structure returned by event_init()
+  @param tv the amount of time after which the loop should terminate.
+  @return 0 if successful, or -1 if an error occurred
+  @see event_loopexit()
+ */
+int event_base_loopexit(struct event_base *, const struct timeval *);
+
+/**
+  Abort the active event_loop() immediately.
+
+  event_loop() will abort the loop after the next event is completed;
+  event_loopbreak() is typically invoked from this event's callback.
+  This behavior is analogous to the "break;" statement.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_loopbreak(), event_loopexit()
+ */
+int event_loopbreak(void);
+
+/**
+  Abort the active event_base_loop() immediately.
+
+  event_base_loop() will abort the loop after the next event is completed;
+  event_base_loopbreak() is typically invoked from this event's callback.
+  This behavior is analogous to the "break;" statement.
+
+  Subsequent invocations of event_loop() will proceed normally.
+
+  @param eb the event_base structure returned by event_init()
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_loopexit
+ */
+int event_base_loopbreak(struct event_base *);
+
+
+/**
+  Add a timer event.
+
+  @param ev the event struct
+  @param tv timeval struct
+ */
 #define evtimer_add(ev, tv)		event_add(ev, tv)
+
+
+/**
+  Define a timer event.
+
+  @param ev event struct to be modified
+  @param cb callback function
+  @param arg argument that will be passed to the callback function
+ */
 #define evtimer_set(ev, cb, arg)	event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Delete a timer event.
+ *
+ * @param ev the event struct to be disabled
+ */
 #define evtimer_del(ev)			event_del(ev)
 #define evtimer_pending(ev, tv)		event_pending(ev, EV_TIMEOUT, tv)
 #define evtimer_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
 
+/**
+ * Add a timeout event.
+ *
+ * @param ev the event struct to be disabled
+ * @param tv the timeout value, in seconds
+ */
 #define timeout_add(ev, tv)		event_add(ev, tv)
+
+
+/**
+ * Define a timeout event.
+ *
+ * @param ev the event struct to be defined
+ * @param cb the callback to be invoked when the timeout expires
+ * @param arg the argument to be passed to the callback
+ */
 #define timeout_set(ev, cb, arg)	event_set(ev, -1, 0, cb, arg)
+
+
+/**
+ * Disable a timeout event.
+ *
+ * @param ev the timeout event to be disabled
+ */
 #define timeout_del(ev)			event_del(ev)
+
 #define timeout_pending(ev, tv)		event_pending(ev, EV_TIMEOUT, tv)
 #define timeout_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
 
@@ -182,32 +513,210 @@
 #define signal_pending(ev, tv)		event_pending(ev, EV_SIGNAL, tv)
 #define signal_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
 
+/**
+  Prepare an event structure to be added.
+
+  The function event_set() prepares the event structure ev to be used in
+  future calls to event_add() and event_del().  The event will be prepared to
+  call the function specified by the fn argument with an int argument
+  indicating the file descriptor, a short argument indicating the type of
+  event, and a void * argument given in the arg argument.  The fd indicates
+  the file descriptor that should be monitored for events.  The events can be
+  either EV_READ, EV_WRITE, or both.  Indicating that an application can read
+  or write from the file descriptor respectively without blocking.
+
+  The function fn will be called with the file descriptor that triggered the
+  event and the type of event which will be either EV_TIMEOUT, EV_SIGNAL,
+  EV_READ, or EV_WRITE.  The additional flag EV_PERSIST makes an event_add()
+  persistent until event_del() has been called.
+
+  @param ev an event struct to be modified
+  @param fd the file descriptor to be monitored
+  @param event desired events to monitor; can be EV_READ and/or EV_WRITE
+  @param fn callback function to be invoked when the event occurs
+  @param arg an argument to be passed to the callback function
+
+  @see event_add(), event_del(), event_once()
+
+ */
 void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
-int event_once(int, short, void (*)(int, short, void *), void *, struct timeval *);
-int event_base_once(struct event_base *, int, short, void (*)(int, short, void *), void *, struct timeval *);
 
-int event_add(struct event *, struct timeval *);
+/**
+  Schedule a one-time event to occur.
+
+  The function event_once() is similar to event_set().  However, it schedules
+  a callback to be called exactly once and does not require the caller to
+  prepare an event structure.
+
+  @param fd a file descriptor to monitor
+  @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+         EV_WRITE
+  @param callback callback function to be invoked when the event occurs
+  @param arg an argument to be passed to the callback function
+  @param timeout the maximum amount of time to wait for the event, or NULL
+         to wait forever
+  @return 0 if successful, or -1 if an error occurred
+  @see event_set()
+
+ */
+int event_once(int, short, void (*)(int, short, void *), void *,
+    const struct timeval *);
+
+
+/**
+  Schedule a one-time event (threadsafe variant)
+
+  The function event_base_once() is similar to event_set().  However, it
+  schedules a callback to be called exactly once and does not require the
+  caller to prepare an event structure.
+
+  @param base an event_base returned by event_init()
+  @param fd a file descriptor to monitor
+  @param events event(s) to monitor; can be any of EV_TIMEOUT | EV_READ |
+         EV_WRITE
+  @param callback callback function to be invoked when the event occurs
+  @param arg an argument to be passed to the callback function
+  @param timeout the maximum amount of time to wait for the event, or NULL
+         to wait forever
+  @return 0 if successful, or -1 if an error occurred
+  @see event_once()
+ */
+int event_base_once(struct event_base *base, int fd, short events,
+    void (*callback)(int, short, void *), void *arg,
+    const struct timeval *timeout);
+
+
+/**
+  Add an event to the set of monitored events.
+
+  The function event_add() schedules the execution of the ev event when the
+  event specified in event_set() occurs or in at least the time specified in
+  the tv.  If tv is NULL, no timeout occurs and the function will only be
+  called if a matching event occurs on the file descriptor.  The event in the
+  ev argument must be already initialized by event_set() and may not be used
+  in calls to event_set() until it has timed out or been removed with
+  event_del().  If the event in the ev argument already has a scheduled
+  timeout, the old timeout will be replaced by the new one.
+
+  @param ev an event struct initialized via event_set()
+  @param timeout the maximum amount of time to wait for the event, or NULL
+         to wait forever
+  @return 0 if successful, or -1 if an error occurred
+  @see event_del(), event_set()
+  */
+int event_add(struct event *ev, const struct timeval *timeout);
+
+
+/**
+  Remove an event from the set of monitored events.
+
+  The function event_del() will cancel the event in the argument ev.  If the
+  event has already executed or has never been added the call will have no
+  effect.
+
+  @param ev an event struct to be removed from the working set
+  @return 0 if successful, or -1 if an error occurred
+  @see event_add()
+ */
 int event_del(struct event *);
+
 void event_active(struct event *, int, short);
 
-int event_pending(struct event *, short, struct timeval *);
 
+/**
+  Checks if a specific event is pending or scheduled.
+
+  @param ev an event struct previously passed to event_add()
+  @param event the requested event type; any of EV_TIMEOUT|EV_READ|
+         EV_WRITE|EV_SIGNAL
+  @param tv an alternate timeout (FIXME - is this true?)
+
+  @return 1 if the event is pending, or 0 if the event has not occurred
+
+ */
+int event_pending(struct event *ev, short event, struct timeval *tv);
+
+
+/**
+  Test if an event structure has been initialized.
+
+  The event_initialized() macro can be used to check if an event has been
+  initialized.
+
+  @param ev an event structure to be tested
+  @return 1 if the structure has been initialized, or 0 if it has not been
+          initialized
+ */
 #ifdef WIN32
 #define event_initialized(ev)		((ev)->ev_flags & EVLIST_INIT && (ev)->ev_fd != (int)INVALID_HANDLE_VALUE)
 #else
 #define event_initialized(ev)		((ev)->ev_flags & EVLIST_INIT)
 #endif
 
-/* Some simple debugging functions */
+
+/**
+  Get the libevent version number.
+
+  @return a string containing the version number of libevent
+ */
 const char *event_get_version(void);
+
+
+/**
+  Get the kernel event notification mechanism used by libevent.
+
+  @return a string identifying the kernel event mechanism (kqueue, epoll, etc.)
+ */
 const char *event_get_method(void);
 
-/* These functions deal with event priorities */
 
+/**
+  Set the number of different event priorities.
+
+  By default libevent schedules all active events with the same priority.
+  However, some time it is desirable to process some events with a higher
+  priority than others.  For that reason, libevent supports strict priority
+  queues.  Active events with a lower priority are always processed before
+  events with a higher priority.
+
+  The number of different priorities can be set initially with the
+  event_priority_init() function.  This function should be called before the
+  first call to event_dispatch().  The event_priority_set() function can be
+  used to assign a priority to an event.  By default, libevent assigns the
+  middle priority to all events unless their priority is explicitly set.
+
+  @param npriorities the maximum number of priorities
+  @return 0 if successful, or -1 if an error occurred
+  @see event_base_priority_init(), event_priority_set()
+
+ */
 int	event_priority_init(int);
+
+
+/**
+  Set the number of different event priorities (threadsafe variant).
+
+  See the description of event_priority_init() for more information.
+
+  @param eb the event_base structure returned by event_init()
+  @param npriorities the maximum number of priorities
+  @return 0 if successful, or -1 if an error occurred
+  @see event_priority_init(), event_priority_set()
+ */
 int	event_base_priority_init(struct event_base *, int);
+
+
+/**
+  Assign a priority to an event.
+
+  @param ev an event struct
+  @param priority the new priority to be assigned
+  @return 0 if successful, or -1 if an error occurred
+  @see event_priority_init()
+  */
 int	event_priority_set(struct event *, int);
 
+
 /* These functions deal with buffering input and output */
 
 struct evbuffer {
@@ -239,6 +748,8 @@
 };
 
 struct bufferevent {
+	struct event_base *ev_base;
+
 	struct event ev_read;
 	struct event ev_write;
 
@@ -259,40 +770,355 @@
 	short enabled;	/* events that are currently enabled */
 };
 
+
+/**
+  Create a new bufferevent.
+
+  libevent provides an abstraction on top of the regular event callbacks.
+  This abstraction is called a buffered event.  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 I/O, but
+  instead is reading from input and writing to output buffers.
+
+  Once initialized, the bufferevent structure can be used repeatedly with
+  bufferevent_enable() and bufferevent_disable().
+
+  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 0 by
+  default.
+
+  If multiple bases are in use, bufferevent_base_set() must be called before
+  enabling the bufferevent for the first time.
+
+  @param fd the file descriptor from which data is read and written to.
+  		This file descriptor is not allowed to be a pipe(2).
+  @param readcb callback to invoke when there is data to be read, or NULL if
+         no callback is desired
+  @param writecb callback to invoke when the file descriptor is ready for
+         writing, or NULL if no callback is desired
+  @param errorcb callback to invoke when there is an error on the file
+         descriptor
+  @param cbarg an argument that will be supplied to each of the callbacks
+         (readcb, writecb, and errorcb)
+  @return a pointer to a newly allocated bufferevent struct, or NULL if an
+          error occurred
+  @see bufferevent_base_set(), bufferevent_free()
+  */
 struct bufferevent *bufferevent_new(int fd,
     evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+
+/**
+  Assign a bufferevent to a specific event_base.
+
+  @param base an event_base returned by event_init()
+  @param bufev a bufferevent struct returned by bufferevent_new()
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_new()
+ */
 int bufferevent_base_set(struct event_base *base, struct bufferevent *bufev);
+
+
+/**
+  Assign a priority to a bufferevent.
+
+  @param bufev a bufferevent struct
+  @param pri the priority to be assigned
+  @return 0 if successful, or -1 if an error occurred
+  */
 int bufferevent_priority_set(struct bufferevent *bufev, int pri);
+
+
+/**
+  Deallocate the storage associated with a bufferevent structure.
+
+  @param bufev the bufferevent structure to be freed.
+  */
 void bufferevent_free(struct bufferevent *bufev);
-int bufferevent_write(struct bufferevent *bufev, void *data, size_t size);
+
+
+/**
+  Changes the callbacks for a bufferevent.
+
+  @param bufev the bufferevent object for which to change callbacks
+  @param readcb callback to invoke when there is data to be read, or NULL if
+         no callback is desired
+  @param writecb callback to invoke when the file descriptor is ready for
+         writing, or NULL if no callback is desired
+  @param errorcb callback to invoke when there is an error on the file
+         descriptor
+  @param cbarg an argument that will be supplied to each of the callbacks
+         (readcb, writecb, and errorcb)
+  @see bufferevent_new()
+  */
+void bufferevent_setcb(struct bufferevent *bufev,
+    evbuffercb readcb, evbuffercb writecb, everrorcb errorcb, void *cbarg);
+
+/**
+  Changes the file descriptor on which the bufferevent operates.
+
+  @param bufev the bufferevent object for which to change the file descriptor
+  @param fd the file descriptor to operate on
+*/
+void bufferevent_setfd(struct bufferevent *bufev, int fd);
+
+/**
+  Write data to a bufferevent buffer.
+
+  The bufferevent_write() function can be used to write data to the file
+  descriptor.  The data is appended to the output buffer and written to the
+  descriptor automatically as it becomes available for writing.
+
+  @param bufev the bufferevent to be written to
+  @param data a pointer to the data to be written
+  @param size the length of the data, in bytes
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_write_buffer()
+  */
+int bufferevent_write(struct bufferevent *bufev,
+    const void *data, size_t size);
+
+
+/**
+  Write data from an evbuffer to a bufferevent buffer.  The evbuffer is
+  being drained as a result.
+
+  @param bufev the bufferevent to be written to
+  @param buf the evbuffer to be written
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_write()
+ */
 int bufferevent_write_buffer(struct bufferevent *bufev, struct evbuffer *buf);
+
+
+/**
+  Read data from a bufferevent buffer.
+
+  The bufferevent_read() function is used to read data from the input buffer.
+
+  @param bufev the bufferevent to be read from
+  @param data pointer to a buffer that will store the data
+  @param size the size of the data buffer, in bytes
+  @return the amount of data read, in bytes.
+ */
 size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
+
+/**
+  Enable a bufferevent.
+
+  @param bufev the bufferevent to be enabled
+  @param event any combination of EV_READ | EV_WRITE.
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_disable()
+ */
 int bufferevent_enable(struct bufferevent *bufev, short event);
+
+
+/**
+  Disable a bufferevent.
+
+  @param bufev the bufferevent to be disabled
+  @param event any combination of EV_READ | EV_WRITE.
+  @return 0 if successful, or -1 if an error occurred
+  @see bufferevent_enable()
+ */
 int bufferevent_disable(struct bufferevent *bufev, short event);
+
+
+/**
+  Set the read and write timeout for a buffered event.
+
+  @param bufev the bufferevent to be modified
+  @param timeout_read the read timeout
+  @param timeout_write the write timeout
+ */
 void bufferevent_settimeout(struct bufferevent *bufev,
     int timeout_read, int timeout_write);
 
+
+/**
+  Sets the watermarks for read and write events.
+
+  On input, a bufferevent does not invoke the user read callback unless
+  there is at least low watermark data in the buffer.   If the read buffer
+  is beyond the high watermark, the buffevent stops reading from the network.
+
+  On output, the user write callback is invoked whenever the buffered data
+  falls below the low watermark.
+
+  @param bufev the bufferevent to be modified
+  @param events EV_READ, EV_WRITE or both
+  @param lowmark the lower watermark to set
+  @param highmark the high watermark to set
+*/
+
+void bufferevent_setwatermark(struct bufferevent *bufev, short events,
+    size_t lowmark, size_t highmark);
+
 #define EVBUFFER_LENGTH(x)	(x)->off
 #define EVBUFFER_DATA(x)	(x)->buffer
 #define EVBUFFER_INPUT(x)	(x)->input
 #define EVBUFFER_OUTPUT(x)	(x)->output
 
+
+/**
+  Allocate storage for a new evbuffer.
+
+  @return a pointer to a newly allocated evbuffer struct, or NULL if an error
+          occurred
+ */
 struct evbuffer *evbuffer_new(void);
+
+
+/**
+  Deallocate storage for an evbuffer.
+
+  @param pointer to the evbuffer to be freed
+ */
 void evbuffer_free(struct evbuffer *);
+
+
+/**
+  Expands the available space in an event buffer.
+
+  Expands the available space in the event buffer to at least datlen
+
+  @param buf the event buffer to be expanded
+  @param datlen the new minimum length requirement
+  @return 0 if successful, or -1 if an error occurred
+*/
 int evbuffer_expand(struct evbuffer *, size_t);
+
+
+/**
+  Append data to the end of an evbuffer.
+
+  @param buf the event buffer to be appended to
+  @param data pointer to the beginning of the data buffer
+  @param datlen the number of bytes to be copied from the data buffer
+ */
 int evbuffer_add(struct evbuffer *, const void *, size_t);
+
+
+
+/**
+  Read data from an event buffer and drain the bytes read.
+
+  @param buf the event buffer to be read from
+  @param data the destination buffer to store the result
+  @param datlen the maximum size of the destination buffer
+  @return the number of bytes read
+ */
 int evbuffer_remove(struct evbuffer *, void *, size_t);
+
+
+/**
+ * Read a single line from an event buffer.
+ *
+ * Reads a line terminated by either '\r\n', '\n\r' or '\r' or '\n'.
+ * The returned buffer needs to be freed by the caller.
+ *
+ * @param buffer the evbuffer to read from
+ * @return pointer to a single line, or NULL if an error occurred
+ */
 char *evbuffer_readline(struct evbuffer *);
+
+
+/**
+  Move data from one evbuffer into another evbuffer.
+
+  This is a destructive add.  The data from one buffer moves into
+  the other buffer. The destination buffer is expanded as needed.
+
+  @param outbuf the output buffer
+  @param inbuf the input buffer
+  @return 0 if successful, or -1 if an error occurred
+ */
 int evbuffer_add_buffer(struct evbuffer *, struct evbuffer *);
-int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...);
+
+
+/**
+  Append a formatted string to the end of an evbuffer.
+
+  @param buf the evbuffer that will be appended to
+  @param fmt a format string
+  @param ... arguments that will be passed to printf(3)
+  @return The number of bytes added if successful, or -1 if an error occurred.
+ */
+int evbuffer_add_printf(struct evbuffer *, const char *fmt, ...)
+#ifdef __GNUC__
+  __attribute__((format(printf, 2, 3)))
+#endif
+;
+
+
+/**
+  Append a va_list formatted string to the end of an evbuffer.
+
+  @param buf the evbuffer that will be appended to
+  @param fmt a format string
+  @param ap a varargs va_list argument array that will be passed to vprintf(3)
+  @return The number of bytes added if successful, or -1 if an error occurred.
+ */
 int evbuffer_add_vprintf(struct evbuffer *, const char *fmt, va_list ap);
+
+
+/**
+  Remove a specified number of bytes data from the beginning of an evbuffer.
+
+  @param buf the evbuffer to be drained
+  @param len the number of bytes to drain from the beginning of the buffer
+  @return 0 if successful, or -1 if an error occurred
+ */
 void evbuffer_drain(struct evbuffer *, size_t);
+
+
+/**
+  Write the contents of an evbuffer to a file descriptor.
+
+  The evbuffer will be drained after the bytes have been successfully written.
+
+  @param buffer the evbuffer to be written and drained
+  @param fd the file descriptor to be written to
+  @return the number of bytes written, or -1 if an error occurred
+  @see evbuffer_read()
+ */
 int evbuffer_write(struct evbuffer *, int);
+
+
+/**
+  Read from a file descriptor and store the result in an evbuffer.
+
+  @param buf the evbuffer to store the result
+  @param fd the file descriptor to read from
+  @param howmuch the number of bytes to be read
+  @return the number of bytes read, or -1 if an error occurred
+  @see evbuffer_write()
+ */
 int evbuffer_read(struct evbuffer *, int, int);
+
+
+/**
+  Find a string within an evbuffer.
+
+  @param buffer the evbuffer to be searched
+  @param what the string to be searched for
+  @param len the length of the search string
+  @return a pointer to the beginning of the search string, or NULL if the search failed.
+ */
 u_char *evbuffer_find(struct evbuffer *, const u_char *, size_t);
+
+/**
+  Set a callback to invoke when the evbuffer is modified.
+
+  @param buffer the evbuffer to be monitored
+  @param cb the callback function to invoke when the evbuffer is modified
+  @param cbarg an argument to be provided to the callback function
+ */
 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.
@@ -300,37 +1126,47 @@
 
 void evtag_init(void);
 
-void evtag_marshal(struct evbuffer *evbuf, uint8_t tag, const void *data,
-    uint32_t len);
+void evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag, const void *data,
+    ev_uint32_t len);
 
-void encode_int(struct evbuffer *evbuf, uint32_t number);
+/**
+  Encode an integer and store it in an evbuffer.
 
-void evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer);
+  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 evtag_marshal_string(struct evbuffer *buf, uint8_t tag,
+  @param evbuf evbuffer to store the encoded number
+  @param number a 32-bit integer
+ */
+void encode_int(struct evbuffer *evbuf, ev_uint32_t number);
+
+void evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag,
+    ev_uint32_t integer);
+
+void evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag,
     const char *string);
 
-void evtag_marshal_timeval(struct evbuffer *evbuf, uint8_t tag,
+void evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag,
     struct timeval *tv);
 
-void evtag_test(void);
-
-int evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst);
-int evtag_peek(struct evbuffer *evbuf, uint8_t *ptag);
-int evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength);
-int evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength);
+int evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag,
+    struct evbuffer *dst);
+int evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag);
+int evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength);
+int evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength);
 int evtag_consume(struct evbuffer *evbuf);
 
-int evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag,
-    uint32_t *pinteger);
+int evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    ev_uint32_t *pinteger);
 
-int evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data,
-    size_t len);
+int evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag,
+    void *data, size_t len);
 
-int evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag,
+int evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
     char **pstring);
 
-int evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag,
+int evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
     struct timeval *ptv);
 
 #ifdef __cplusplus
Index: contrib/libevent/event_tagging.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/event_tagging.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 event_tagging.c
--- contrib/libevent/event_tagging.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/event_tagging.c	24 Apr 2008 18:28:48 -0000
@@ -25,22 +25,26 @@
  * 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
 
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
 #ifdef WIN32
 #define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
 #include <windows.h>
 #undef WIN32_LEAN_AND_MEAN
 #else
 #include <sys/ioctl.h>
 #endif
 
-#include <sys/tree.h>
 #include <sys/queue.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
@@ -53,17 +57,22 @@
 #ifndef WIN32
 #include <syslog.h>
 #endif
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 
 #include "event.h"
+#include "evutil.h"
 #include "log.h"
 
-int decode_int(uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf);
+int evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag);
+int evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf);
 
 static struct evbuffer *_buf;	/* not thread safe */
 
 void
-evtag_init()
+evtag_init(void)
 {
 	if (_buf != NULL)
 		return;
@@ -79,12 +88,12 @@
  */
 
 void
-encode_int(struct evbuffer *evbuf, uint32_t number)
+encode_int(struct evbuffer *evbuf, ev_uint32_t number)
 {
 	int off = 1, nibbles = 0;
-	uint8_t data[5];
+	ev_uint8_t data[5];
 
-	memset(data, 0, sizeof(data));
+	memset(data, 0, sizeof(ev_uint32_t)+1);
 	while (number) {
 		if (off & 0x1)
 			data[off/2] = (data[off/2] & 0xf0) | (number & 0x0f);
@@ -105,40 +114,105 @@
 }
 
 /*
+ * Support variable length encoding of tags; we use the high bit in each
+ * octet as a continuation signal.
+ */
+
+int
+evtag_encode_tag(struct evbuffer *evbuf, ev_uint32_t tag)
+{
+	int bytes = 0;
+	ev_uint8_t data[5];
+
+	memset(data, 0, sizeof(data));
+	do {
+		ev_uint8_t lower = tag & 0x7f;
+		tag >>= 7;
+
+		if (tag)
+			lower |= 0x80;
+
+		data[bytes++] = lower;
+	} while (tag);
+
+	if (evbuf != NULL)
+		evbuffer_add(evbuf, data, bytes);
+
+	return (bytes);
+}
+
+static int
+decode_tag_internal(ev_uint32_t *ptag, struct evbuffer *evbuf, int dodrain)
+{
+	ev_uint32_t number = 0;
+	ev_uint8_t *data = EVBUFFER_DATA(evbuf);
+	int len = EVBUFFER_LENGTH(evbuf);
+	int count = 0, shift = 0, done = 0;
+
+	while (count++ < len) {
+		ev_uint8_t lower = *data++;
+		number |= (lower & 0x7f) << shift;
+		shift += 7;
+
+		if (!(lower & 0x80)) {
+			done = 1;
+			break;
+		}
+	}
+
+	if (!done)
+		return (-1);
+
+	if (dodrain)
+		evbuffer_drain(evbuf, count);
+
+	if (ptag != NULL)
+		*ptag = number;
+
+	return (count);
+}
+
+int
+evtag_decode_tag(ev_uint32_t *ptag, struct evbuffer *evbuf)
+{
+	return (decode_tag_internal(ptag, evbuf, 1 /* dodrain */));
+}
+
+/*
  * 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, uint8_t tag,
-    const void *data, uint32_t len)
+evtag_marshal(struct evbuffer *evbuf, ev_uint32_t tag,
+    const void *data, ev_uint32_t len)
 {
-	evbuffer_add(evbuf, &tag, sizeof(tag));
+	evtag_encode_tag(evbuf, tag);
 	encode_int(evbuf, len);
 	evbuffer_add(evbuf, (void *)data, len);
 }
 
 /* Marshaling for integers */
 void
-evtag_marshal_int(struct evbuffer *evbuf, uint8_t tag, uint32_t integer)
+evtag_marshal_int(struct evbuffer *evbuf, ev_uint32_t tag, ev_uint32_t integer)
 {
 	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
 	encode_int(_buf, integer);
 
-	evbuffer_add(evbuf, &tag, sizeof(tag));
+	evtag_encode_tag(evbuf, tag);
 	encode_int(evbuf, EVBUFFER_LENGTH(_buf));
 	evbuffer_add_buffer(evbuf, _buf);
 }
 
 void
-evtag_marshal_string(struct evbuffer *buf, uint8_t tag, const char *string)
+evtag_marshal_string(struct evbuffer *buf, ev_uint32_t tag, const char *string)
 {
 	evtag_marshal(buf, tag, string, strlen(string));
 }
 
 void
-evtag_marshal_timeval(struct evbuffer *evbuf, uint8_t tag, struct timeval *tv)
+evtag_marshal_timeval(struct evbuffer *evbuf, ev_uint32_t tag, struct timeval *tv)
 {
 	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
 
@@ -150,31 +224,30 @@
 }
 
 static int
-decode_int_internal(uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
+decode_int_internal(ev_uint32_t *pnumber, struct evbuffer *evbuf, int dodrain)
 {
-	uint32_t number = 0;
-	uint8_t *data = EVBUFFER_DATA(evbuf);
+	ev_uint32_t number = 0;
+	ev_uint8_t *data = EVBUFFER_DATA(evbuf);
 	int len = EVBUFFER_LENGTH(evbuf);
-	int nibbles = 0, off;
+	int nibbles = 0;
 
 	if (!len)
 		return (-1);
 
 	nibbles = ((data[0] & 0xf0) >> 4) + 1;
-	if (nibbles > 8 || (nibbles >> 1) > len - 1)
+	if (nibbles > 8 || (nibbles >> 1) + 1 > len)
 		return (-1);
+	len = (nibbles >> 1) + 1;
 
-	off = nibbles;
-	while (off > 0) {
+	while (nibbles > 0) {
 		number <<= 4;
-		if (off & 0x1)
-			number |= data[off >> 1] & 0x0f;
+		if (nibbles & 0x1)
+			number |= data[nibbles >> 1] & 0x0f;
 		else
-			number |= (data[off >> 1] & 0xf0) >> 4;
-		off--;
+			number |= (data[nibbles >> 1] & 0xf0) >> 4;
+		nibbles--;
 	}
 
-	len = (nibbles >> 1) + 1;
 	if (dodrain)
 		evbuffer_drain(evbuf, len);
 
@@ -184,55 +257,53 @@
 }
 
 int
-decode_int(uint32_t *pnumber, struct evbuffer *evbuf)
+evtag_decode_int(ev_uint32_t *pnumber, struct evbuffer *evbuf)
 {
 	return (decode_int_internal(pnumber, evbuf, 1) == -1 ? -1 : 0);
 }
 
 int
-evtag_peek(struct evbuffer *evbuf, uint8_t *ptag)
+evtag_peek(struct evbuffer *evbuf, ev_uint32_t *ptag)
 {
-	if (EVBUFFER_LENGTH(evbuf) < 2)
-		return (-1);
-	*ptag = EVBUFFER_DATA(evbuf)[0];
-
-	return (0);
+	return (decode_tag_internal(ptag, evbuf, 0 /* dodrain */));
 }
 
 int
-evtag_peek_length(struct evbuffer *evbuf, uint32_t *plength)
+evtag_peek_length(struct evbuffer *evbuf, ev_uint32_t *plength)
 {
 	struct evbuffer tmp;
-	int res;
+	int res, len;
 
-	if (EVBUFFER_LENGTH(evbuf) < 2)
+	len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+	if (len == -1)
 		return (-1);
 
 	tmp = *evbuf;
-	tmp.buffer += 1;
-	tmp.off -= 1;
+	tmp.buffer += len;
+	tmp.off -= len;
 
 	res = decode_int_internal(plength, &tmp, 0);
 	if (res == -1)
 		return (-1);
 
-	*plength += res + 1;
+	*plength += res + len;
 
 	return (0);
 }
 
 int
-evtag_payload_length(struct evbuffer *evbuf, uint32_t *plength)
+evtag_payload_length(struct evbuffer *evbuf, ev_uint32_t *plength)
 {
 	struct evbuffer tmp;
-	int res;
+	int res, len;
 
-	if (EVBUFFER_LENGTH(evbuf) < 2)
+	len = decode_tag_internal(NULL, evbuf, 0 /* dodrain */);
+	if (len == -1)
 		return (-1);
 
 	tmp = *evbuf;
-	tmp.buffer += 1;
-	tmp.off -= 1;
+	tmp.buffer += len;
+	tmp.off -= len;
 
 	res = decode_int_internal(plength, &tmp, 0);
 	if (res == -1)
@@ -244,9 +315,10 @@
 int
 evtag_consume(struct evbuffer *evbuf)
 {
-	uint32_t len;
-	evbuffer_drain(evbuf, 1);
-	if (decode_int(&len, evbuf) == -1)
+	ev_uint32_t len;
+	if (decode_tag_internal(NULL, evbuf, 1 /* dodrain */) == -1)
+		return (-1);
+	if (evtag_decode_int(&len, evbuf) == -1)
 		return (-1);
 	evbuffer_drain(evbuf, len);
 
@@ -256,15 +328,14 @@
 /* Reads the data type from an event buffer */
 
 int
-evtag_unmarshal(struct evbuffer *src, uint8_t *ptag, struct evbuffer *dst)
+evtag_unmarshal(struct evbuffer *src, ev_uint32_t *ptag, struct evbuffer *dst)
 {
-	uint8_t tag;
-	uint32_t len;
-	uint32_t integer;
+	ev_uint32_t len;
+	ev_uint32_t integer;
 
-	if (evbuffer_remove(src, &tag, sizeof(tag)) != sizeof(tag))
+	if (decode_tag_internal(ptag, src, 1 /* dodrain */) == -1)
 		return (-1);
-	if (decode_int(&integer, src) == -1)
+	if (evtag_decode_int(&integer, src) == -1)
 		return (-1);
 	len = integer;
 
@@ -276,24 +347,24 @@
 
 	evbuffer_drain(src, len);
 
-	*ptag = tag;
 	return (len);
 }
 
 /* Marshaling for integers */
 
 int
-evtag_unmarshal_int(struct evbuffer *evbuf, uint8_t need_tag,
-    uint32_t *pinteger)
+evtag_unmarshal_int(struct evbuffer *evbuf, ev_uint32_t need_tag,
+    ev_uint32_t *pinteger)
 {
-	uint8_t tag;
-	uint32_t len;
-	uint32_t integer;
+	ev_uint32_t tag;
+	ev_uint32_t len;
+	ev_uint32_t integer;
 
-	if (evbuffer_remove(evbuf, &tag, sizeof(tag)) != sizeof(tag) ||
-	    tag != need_tag)
+	if (decode_tag_internal(&tag, evbuf, 1 /* dodrain */) == -1)
+		return (-1);
+	if (need_tag != tag)
 		return (-1);
-	if (decode_int(&integer, evbuf) == -1)
+	if (evtag_decode_int(&integer, evbuf) == -1)
 		return (-1);
 	len = integer;
 
@@ -306,16 +377,16 @@
 
 	evbuffer_drain(evbuf, len);
 
-	return (decode_int(pinteger, _buf));
+	return (evtag_decode_int(pinteger, _buf));
 }
 
 /* Unmarshal a fixed length tag */
 
 int
-evtag_unmarshal_fixed(struct evbuffer *src, uint8_t need_tag, void *data,
+evtag_unmarshal_fixed(struct evbuffer *src, ev_uint32_t need_tag, void *data,
     size_t len)
 {
-	uint8_t tag;
+	ev_uint32_t tag;
 
 	/* Initialize this event buffer so that we can read into it */
 	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
@@ -332,10 +403,10 @@
 }
 
 int
-evtag_unmarshal_string(struct evbuffer *evbuf, uint8_t need_tag,
+evtag_unmarshal_string(struct evbuffer *evbuf, ev_uint32_t need_tag,
     char **pstring)
 {
-	uint8_t tag;
+	ev_uint32_t tag;
 
 	evbuffer_drain(_buf, EVBUFFER_LENGTH(_buf));
 
@@ -351,20 +422,20 @@
 }
 
 int
-evtag_unmarshal_timeval(struct evbuffer *evbuf, uint8_t need_tag,
+evtag_unmarshal_timeval(struct evbuffer *evbuf, ev_uint32_t need_tag,
     struct timeval *ptv)
 {
-	uint8_t tag;
-	uint32_t integer;
+	ev_uint32_t tag;
+	ev_uint32_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)
+	if (evtag_decode_int(&integer, _buf) == -1)
 		return (-1);
 	ptv->tv_sec = integer;
-	if (decode_int(&integer, _buf) == -1)
+	if (evtag_decode_int(&integer, _buf) == -1)
 		return (-1);
 	ptv->tv_usec = integer;
 
Index: contrib/libevent/evhttp.h
===================================================================
RCS file: contrib/libevent/evhttp.h
diff -N contrib/libevent/evhttp.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/evhttp.h	14 May 2008 04:07:41 -0000
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@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 _EVHTTP_H_
+#define _EVHTTP_H_
+
+#include <event.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+/** @file evhttp.h
+ *
+ * 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_NOCONTENT		204
+#define HTTP_MOVEPERM		301
+#define HTTP_MOVETEMP		302
+#define HTTP_NOTMODIFIED	304
+#define HTTP_BADREQUEST		400
+#define HTTP_NOTFOUND		404
+#define HTTP_SERVUNAVAIL	503
+
+struct evhttp;
+struct evhttp_request;
+struct evkeyvalq;
+
+/** Create a new HTTP server
+ *
+ * @param base (optional) the event base to receive the HTTP events
+ * @return a pointer to a newly initialized evhttp server structure
+ */
+struct evhttp *evhttp_new(struct event_base *base);
+
+/**
+ * Binds an HTTP server on the specified address and port.
+ *
+ * Can be called multiple times to bind the same http server
+ * to multiple different ports.
+ *
+ * @param http a pointer to an evhttp object
+ * @param address a string containing the IP address to listen(2) on
+ * @param port the port number to listen on
+ * @return a newly allocated evhttp struct
+ * @see evhttp_free()
+ */
+int evhttp_bind_socket(struct evhttp *http, const char *address, u_short port);
+
+/**
+ * Makes an HTTP server accept connections on the specified socket
+ *
+ * This may be useful to create a socket and then fork multiple instances
+ * of an http server, or when a socket has been communicated via file
+ * descriptor passing in situations where an http servers does not have
+ * permissions to bind to a low-numbered port.
+ *
+ * Can be called multiple times to have the http server listen to
+ * multiple different sockets.
+ *
+ * @param http a pointer to an evhttp object
+ * @param fd a socket fd that is ready for accepting connections
+ * @return 0 on success, -1 on failure.
+ * @see evhttp_free(), evhttp_bind_socket()
+ */
+int evhttp_accept_socket(struct evhttp *http, int fd);
+
+/**
+ * Free the previously created HTTP server.
+ *
+ * Works only if no requests are currently being served.
+ *
+ * @param http the evhttp server object to be freed
+ * @see evhttp_start()
+ */
+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 *);
+
+/** Removes the callback for a specified URI */
+int evhttp_del_cb(struct evhttp *, const char *);
+
+/** 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 *);
+
+/**
+ * Set the timeout for an HTTP request.
+ *
+ * @param http an evhttp object
+ * @param timeout_in_secs the timeout, in seconds
+ */
+void evhttp_set_timeout(struct evhttp *, int timeout_in_secs);
+
+/* Request/Response functionality */
+
+/**
+ * Send an HTML error message to the client.
+ *
+ * @param req a request object
+ * @param error the HTTP error code
+ * @param reason a brief explanation of the error
+ */
+void evhttp_send_error(struct evhttp_request *req, int error,
+    const char *reason);
+
+/**
+ * Send an HTML reply to the client.
+ *
+ * @param req a request object
+ * @param code the HTTP response code to send
+ * @param reason a brief message to send with the response code
+ * @param databuf the body of the response
+ */
+void evhttp_send_reply(struct evhttp_request *req, int code,
+    const char *reason, struct evbuffer *databuf);
+
+/* Low-level response interface, for streaming/chunked replies */
+void evhttp_send_reply_start(struct evhttp_request *, int, const char *);
+void evhttp_send_reply_chunk(struct evhttp_request *, struct evbuffer *);
+void evhttp_send_reply_end(struct evhttp_request *);
+
+/**
+ * Start an HTTP server on the specified address and port
+ *
+ * DEPRECATED: it does not allow an event base to be specified
+ *
+ * @param address the address to which the HTTP server should be bound
+ * @param port the port number on which the HTTP server should listen
+ * @return an struct evhttp object
+ */
+struct evhttp *evhttp_start(const char *address, u_short port);
+
+/*
+ * Interfaces for making requests
+ */
+enum evhttp_cmd_type { EVHTTP_REQ_GET, EVHTTP_REQ_POST, EVHTTP_REQ_HEAD };
+
+enum evhttp_request_kind { EVHTTP_REQUEST, EVHTTP_RESPONSE };
+
+/**
+ * the request structure that a server receives.
+ * WARNING: expect this structure to change.  I will try to provide
+ * reasonable accessors.
+ */
+struct evhttp_request {
+#if defined(TAILQ_ENTRY)
+	TAILQ_ENTRY(evhttp_request) next;
+#else
+struct {
+	struct evhttp_request *tqe_next;
+	struct evhttp_request **tqe_prev;
+}       next;
+#endif
+
+	/* the connection object that this request belongs to */
+	struct evhttp_connection *evcon;
+	int flags;
+#define EVHTTP_REQ_OWN_CONNECTION	0x0001
+#define EVHTTP_PROXY_REQUEST		0x0002
+
+	struct evkeyvalq *input_headers;
+	struct evkeyvalq *output_headers;
+
+	/* address of the remote host and the port connection came from */
+	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 */
+
+	struct evbuffer *input_buffer;	/* read data */
+	ev_int64_t ntoread;
+	int chunked;
+
+	struct evbuffer *output_buffer;	/* outgoing post or data */
+
+	/* Callback */
+	void (*cb)(struct evhttp_request *, void *);
+	void *cb_arg;
+
+	/*
+	 * Chunked data callback - call for each completed chunk if
+	 * specified.  If not specified, all the data is delivered via
+	 * the regular callback.
+	 */
+	void (*chunk_cb)(struct evhttp_request *, void *);
+};
+
+/**
+ * Creates a new request object that needs to be filled in with the request
+ * parameters.  The callback is executed when the request completed or an
+ * error occurred.
+ */
+struct evhttp_request *evhttp_request_new(
+	void (*cb)(struct evhttp_request *, void *), void *arg);
+
+/** enable delivery of chunks to requestor */
+void evhttp_request_set_chunked_cb(struct evhttp_request *,
+    void (*cb)(struct evhttp_request *, void *));
+
+/** Frees the request object and removes associated events. */
+void evhttp_request_free(struct evhttp_request *req);
+
+/**
+ * A connection object that can be used to for making HTTP requests.  The
+ * connection object tries to establish the connection when it is given an
+ * http request object.
+ */
+struct evhttp_connection *evhttp_connection_new(
+	const char *address, unsigned short port);
+
+/** Frees an http connection */
+void evhttp_connection_free(struct evhttp_connection *evcon);
+
+/** sets the ip address from which http connections are made */
+void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+    const char *address);
+
+/** Sets the timeout for events related to this connection */
+void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+    int timeout_in_secs);
+
+/** Sets the retry limit for this connection - -1 repeats indefnitely */
+void evhttp_connection_set_retries(struct evhttp_connection *evcon,
+    int retry_max);
+
+/** Set a callback for connection close. */
+void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+    void (*)(struct evhttp_connection *, void *), void *);
+
+/**
+ * Associates an event base with the connection - can only be called
+ * on a freshly created connection object that has not been used yet.
+ */
+void evhttp_connection_set_base(struct evhttp_connection *evcon,
+    struct event_base *base);
+
+/** Get the remote address and port associated with this connection. */
+void evhttp_connection_get_peer(struct evhttp_connection *evcon,
+    char **address, u_short *port);
+
+/** The connection gets ownership of the request */
+int evhttp_make_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req,
+    enum evhttp_cmd_type type, const char *uri);
+
+const char *evhttp_request_uri(struct evhttp_request *req);
+
+/* Interfaces for dealing with HTTP headers */
+
+const char *evhttp_find_header(const 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 */
+
+
+/**
+  Helper function to encode a URI.
+
+  The returned string must be freed by the caller.
+
+  @param uri an unencoded URI
+  @return a newly allocated URI-encoded string
+ */
+char *evhttp_encode_uri(const char *uri);
+
+
+/**
+  Helper function to decode a URI.
+
+  The returned string must be freed by the caller.
+
+  @param uri an encoded URI
+  @return a newly allocated unencoded URI
+ */
+char *evhttp_decode_uri(const char *uri);
+
+
+/**
+ * Helper function to parse out arguments in a query.
+ * The arguments are separated by key and value.
+ * URI should already be decoded.
+ */
+void evhttp_parse_query(const char *uri, struct evkeyvalq *);
+
+
+/**
+ * Escape HTML character entities in a string.
+ *
+ * Replaces <, >, ", ' and & with &lt;, &gt;, &quot;,
+ * &#039; and &amp; correspondingly.
+ *
+ * The returned string needs to be freed by the caller.
+ *
+ * @param html an unescaped HTML string
+ * @return an escaped HTML string
+ */
+char *evhttp_htmlescape(const char *html);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVHTTP_H_ */
Index: contrib/libevent/evrpc-internal.h
===================================================================
RCS file: contrib/libevent/evrpc-internal.h
diff -N contrib/libevent/evrpc-internal.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/evrpc-internal.h	12 Nov 2007 02:37:32 -0000
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@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 _EVRPC_INTERNAL_H_
+#define _EVRPC_INTERNAL_H_
+
+#include "http-internal.h"
+
+struct evrpc;
+
+#define EVRPC_URI_PREFIX "/.rpc."
+
+struct evrpc_hook {
+	TAILQ_ENTRY(evrpc_hook) (next);
+
+	/* returns -1; if the rpc should be aborted, is allowed to rewrite */
+	int (*process)(struct evhttp_request *, struct evbuffer *, void *);
+	void *process_arg;
+};
+
+TAILQ_HEAD(evrpc_hook_list, evrpc_hook);
+
+/*
+ * this is shared between the base and the pool, so that we can reuse
+ * the hook adding functions; we alias both evrpc_pool and evrpc_base
+ * to this common structure.
+ */
+struct _evrpc_hooks {
+	/* hooks for processing outbound and inbound rpcs */
+	struct evrpc_hook_list in_hooks;
+	struct evrpc_hook_list out_hooks;
+};
+
+#define input_hooks common.in_hooks
+#define output_hooks common.out_hooks
+
+struct evrpc_base {
+	struct _evrpc_hooks common;
+
+	/* the HTTP server under which we register our RPC calls */
+	struct evhttp* http_server;
+
+	/* a list of all RPCs registered with us */
+	TAILQ_HEAD(evrpc_list, evrpc) registered_rpcs;
+};
+
+struct evrpc_req_generic;
+void evrpc_reqstate_free(struct evrpc_req_generic* rpc_state);
+
+/* A pool for holding evhttp_connection objects */
+struct evrpc_pool {
+	struct _evrpc_hooks common;
+
+	struct event_base *base;
+
+	struct evconq connections;
+
+	int timeout;
+
+	TAILQ_HEAD(evrpc_requestq, evrpc_request_wrapper) requests;
+};
+
+
+#endif /* _EVRPC_INTERNAL_H_ */
Index: contrib/libevent/evrpc.c
===================================================================
RCS file: contrib/libevent/evrpc.c
diff -N contrib/libevent/evrpc.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/evrpc.c	20 Jun 2008 06:54:58 -0000
@@ -0,0 +1,657 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@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 HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifndef WIN32
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#include <sys/queue.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef WIN32
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+
+#include "event.h"
+#include "evrpc.h"
+#include "evrpc-internal.h"
+#include "evhttp.h"
+#include "evutil.h"
+#include "log.h"
+
+struct evrpc_base *
+evrpc_init(struct evhttp *http_server)
+{
+	struct evrpc_base* base = calloc(1, sizeof(struct evrpc_base));
+	if (base == NULL)
+		return (NULL);
+
+	/* we rely on the tagging sub system */
+	evtag_init();
+
+	TAILQ_INIT(&base->registered_rpcs);
+	TAILQ_INIT(&base->input_hooks);
+	TAILQ_INIT(&base->output_hooks);
+	base->http_server = http_server;
+
+	return (base);
+}
+
+void
+evrpc_free(struct evrpc_base *base)
+{
+	struct evrpc *rpc;
+	struct evrpc_hook *hook;
+
+	while ((rpc = TAILQ_FIRST(&base->registered_rpcs)) != NULL) {
+		assert(evrpc_unregister_rpc(base, rpc->uri));
+	}
+	while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
+		assert(evrpc_remove_hook(base, EVRPC_INPUT, hook));
+	}
+	while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
+		assert(evrpc_remove_hook(base, EVRPC_OUTPUT, hook));
+	}
+	free(base);
+}
+
+void *
+evrpc_add_hook(void *vbase,
+    enum EVRPC_HOOK_TYPE hook_type,
+    int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
+    void *cb_arg)
+{
+	struct _evrpc_hooks *base = vbase;
+	struct evrpc_hook_list *head = NULL;
+	struct evrpc_hook *hook = NULL;
+	switch (hook_type) {
+	case EVRPC_INPUT:
+		head = &base->in_hooks;
+		break;
+	case EVRPC_OUTPUT:
+		head = &base->out_hooks;
+		break;
+	default:
+		assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+	}
+
+	hook = calloc(1, sizeof(struct evrpc_hook));
+	assert(hook != NULL);
+	
+	hook->process = cb;
+	hook->process_arg = cb_arg;
+	TAILQ_INSERT_TAIL(head, hook, next);
+
+	return (hook);
+}
+
+static int
+evrpc_remove_hook_internal(struct evrpc_hook_list *head, void *handle)
+{
+	struct evrpc_hook *hook = NULL;
+	TAILQ_FOREACH(hook, head, next) {
+		if (hook == handle) {
+			TAILQ_REMOVE(head, hook, next);
+			free(hook);
+			return (1);
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * remove the hook specified by the handle
+ */
+
+int
+evrpc_remove_hook(void *vbase, enum EVRPC_HOOK_TYPE hook_type, void *handle)
+{
+	struct _evrpc_hooks *base = vbase;
+	struct evrpc_hook_list *head = NULL;
+	switch (hook_type) {
+	case EVRPC_INPUT:
+		head = &base->in_hooks;
+		break;
+	case EVRPC_OUTPUT:
+		head = &base->out_hooks;
+		break;
+	default:
+		assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
+	}
+
+	return (evrpc_remove_hook_internal(head, handle));
+}
+
+static int
+evrpc_process_hooks(struct evrpc_hook_list *head,
+    struct evhttp_request *req, struct evbuffer *evbuf)
+{
+	struct evrpc_hook *hook;
+	TAILQ_FOREACH(hook, head, next) {
+		if (hook->process(req, evbuf, hook->process_arg) == -1)
+			return (-1);
+	}
+
+	return (0);
+}
+
+static void evrpc_pool_schedule(struct evrpc_pool *pool);
+static void evrpc_request_cb(struct evhttp_request *, void *);
+void evrpc_request_done(struct evrpc_req_generic*);
+
+/*
+ * Registers a new RPC with the HTTP server.   The evrpc object is expected
+ * to have been filled in via the EVRPC_REGISTER_OBJECT macro which in turn
+ * calls this function.
+ */
+
+static char *
+evrpc_construct_uri(const char *uri)
+{
+	char *constructed_uri;
+	int constructed_uri_len;
+
+	constructed_uri_len = strlen(EVRPC_URI_PREFIX) + strlen(uri) + 1;
+	if ((constructed_uri = malloc(constructed_uri_len)) == NULL)
+		event_err(1, "%s: failed to register rpc at %s",
+		    __func__, uri);
+	memcpy(constructed_uri, EVRPC_URI_PREFIX, strlen(EVRPC_URI_PREFIX));
+	memcpy(constructed_uri + strlen(EVRPC_URI_PREFIX), uri, strlen(uri));
+	constructed_uri[constructed_uri_len - 1] = '\0';
+
+	return (constructed_uri);
+}
+
+int
+evrpc_register_rpc(struct evrpc_base *base, struct evrpc *rpc,
+    void (*cb)(struct evrpc_req_generic *, void *), void *cb_arg)
+{
+	char *constructed_uri = evrpc_construct_uri(rpc->uri);
+
+	rpc->base = base;
+	rpc->cb = cb;
+	rpc->cb_arg = cb_arg;
+
+	TAILQ_INSERT_TAIL(&base->registered_rpcs, rpc, next);
+
+	evhttp_set_cb(base->http_server,
+	    constructed_uri,
+	    evrpc_request_cb,
+	    rpc);
+	
+	free(constructed_uri);
+
+	return (0);
+}
+
+int
+evrpc_unregister_rpc(struct evrpc_base *base, const char *name)
+{
+	char *registered_uri = NULL;
+	struct evrpc *rpc;
+
+	/* find the right rpc; linear search might be slow */
+	TAILQ_FOREACH(rpc, &base->registered_rpcs, next) {
+		if (strcmp(rpc->uri, name) == 0)
+			break;
+	}
+	if (rpc == NULL) {
+		/* We did not find an RPC with this name */
+		return (-1);
+	}
+	TAILQ_REMOVE(&base->registered_rpcs, rpc, next);
+	
+	free((char *)rpc->uri);
+	free(rpc);
+
+        registered_uri = evrpc_construct_uri(name);
+
+	/* remove the http server callback */
+	assert(evhttp_del_cb(base->http_server, registered_uri) == 0);
+
+	free(registered_uri);
+	return (0);
+}
+
+static void
+evrpc_request_cb(struct evhttp_request *req, void *arg)
+{
+	struct evrpc *rpc = arg;
+	struct evrpc_req_generic *rpc_state = NULL;
+
+	/* let's verify the outside parameters */
+	if (req->type != EVHTTP_REQ_POST ||
+	    EVBUFFER_LENGTH(req->input_buffer) <= 0)
+		goto error;
+
+	/*
+	 * we might want to allow hooks to suspend the processing,
+	 * but at the moment, we assume that they just act as simple
+	 * filters.
+	 */
+	if (evrpc_process_hooks(&rpc->base->input_hooks,
+		req, req->input_buffer) == -1)
+		goto error;
+
+	rpc_state = calloc(1, sizeof(struct evrpc_req_generic));
+	if (rpc_state == NULL)
+		goto error;
+
+	/* let's check that we can parse the request */
+	rpc_state->request = rpc->request_new();
+	if (rpc_state->request == NULL)
+		goto error;
+
+	rpc_state->rpc = rpc;
+
+	if (rpc->request_unmarshal(
+		    rpc_state->request, req->input_buffer) == -1) {
+		/* we failed to parse the request; that's a bummer */
+		goto error;
+	}
+
+	/* at this point, we have a well formed request, prepare the reply */
+
+	rpc_state->reply = rpc->reply_new();
+	if (rpc_state->reply == NULL)
+		goto error;
+
+	rpc_state->http_req = req;
+	rpc_state->done = evrpc_request_done;
+
+	/* give the rpc to the user; they can deal with it */
+	rpc->cb(rpc_state, rpc->cb_arg);
+
+	return;
+
+error:
+	evrpc_reqstate_free(rpc_state);
+	evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
+	return;
+}
+
+void
+evrpc_reqstate_free(struct evrpc_req_generic* rpc_state)
+{
+	/* clean up all memory */
+	if (rpc_state != NULL) {
+		struct evrpc *rpc = rpc_state->rpc;
+
+		if (rpc_state->request != NULL)
+			rpc->request_free(rpc_state->request);
+		if (rpc_state->reply != NULL)
+			rpc->reply_free(rpc_state->reply);
+		free(rpc_state);
+	}
+}
+
+void
+evrpc_request_done(struct evrpc_req_generic* rpc_state)
+{
+	struct evhttp_request *req = rpc_state->http_req;
+	struct evrpc *rpc = rpc_state->rpc;
+	struct evbuffer* data = NULL;
+
+	if (rpc->reply_complete(rpc_state->reply) == -1) {
+		/* the reply was not completely filled in.  error out */
+		goto error;
+	}
+
+	if ((data = evbuffer_new()) == NULL) {
+		/* out of memory */
+		goto error;
+	}
+
+	/* serialize the reply */
+	rpc->reply_marshal(data, rpc_state->reply);
+
+	/* do hook based tweaks to the request */
+	if (evrpc_process_hooks(&rpc->base->output_hooks,
+		req, data) == -1)
+		goto error;
+
+	/* on success, we are going to transmit marshaled binary data */
+	if (evhttp_find_header(req->output_headers, "Content-Type") == NULL) {
+		evhttp_add_header(req->output_headers,
+		    "Content-Type", "application/octet-stream");
+	}
+
+	evhttp_send_reply(req, HTTP_OK, "OK", data);
+
+	evbuffer_free(data);
+
+	evrpc_reqstate_free(rpc_state);
+
+	return;
+
+error:
+	if (data != NULL)
+		evbuffer_free(data);
+	evrpc_reqstate_free(rpc_state);
+	evhttp_send_error(req, HTTP_SERVUNAVAIL, "Service Error");
+	return;
+}
+
+/* Client implementation of RPC site */
+
+static int evrpc_schedule_request(struct evhttp_connection *connection,
+    struct evrpc_request_wrapper *ctx);
+
+struct evrpc_pool *
+evrpc_pool_new(struct event_base *base)
+{
+	struct evrpc_pool *pool = calloc(1, sizeof(struct evrpc_pool));
+	if (pool == NULL)
+		return (NULL);
+
+	TAILQ_INIT(&pool->connections);
+	TAILQ_INIT(&pool->requests);
+
+	TAILQ_INIT(&pool->input_hooks);
+	TAILQ_INIT(&pool->output_hooks);
+
+	pool->base = base;
+	pool->timeout = -1;
+
+	return (pool);
+}
+
+static void
+evrpc_request_wrapper_free(struct evrpc_request_wrapper *request)
+{
+	free(request->name);
+	free(request);
+}
+
+void
+evrpc_pool_free(struct evrpc_pool *pool)
+{
+	struct evhttp_connection *connection;
+	struct evrpc_request_wrapper *request;
+	struct evrpc_hook *hook;
+
+	while ((request = TAILQ_FIRST(&pool->requests)) != NULL) {
+		TAILQ_REMOVE(&pool->requests, request, next);
+		/* if this gets more complicated we need our own function */
+		evrpc_request_wrapper_free(request);
+	}
+
+	while ((connection = TAILQ_FIRST(&pool->connections)) != NULL) {
+		TAILQ_REMOVE(&pool->connections, connection, next);
+		evhttp_connection_free(connection);
+	}
+
+	while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
+		assert(evrpc_remove_hook(pool, EVRPC_INPUT, hook));
+	}
+
+	while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
+		assert(evrpc_remove_hook(pool, EVRPC_OUTPUT, hook));
+	}
+
+	free(pool);
+}
+
+/*
+ * Add a connection to the RPC pool.   A request scheduled on the pool
+ * may use any available connection.
+ */
+
+void
+evrpc_pool_add_connection(struct evrpc_pool *pool,
+    struct evhttp_connection *connection) {
+	assert(connection->http_server == NULL);
+	TAILQ_INSERT_TAIL(&pool->connections, connection, next);
+
+	/*
+	 * associate an event base with this connection
+	 */
+	if (pool->base != NULL)
+		evhttp_connection_set_base(connection, pool->base);
+
+	/* 
+	 * unless a timeout was specifically set for a connection,
+	 * the connection inherits the timeout from the pool.
+	 */
+	if (connection->timeout == -1)
+		connection->timeout = pool->timeout;
+
+	/* 
+	 * if we have any requests pending, schedule them with the new
+	 * connections.
+	 */
+
+	if (TAILQ_FIRST(&pool->requests) != NULL) {
+		struct evrpc_request_wrapper *request = 
+		    TAILQ_FIRST(&pool->requests);
+		TAILQ_REMOVE(&pool->requests, request, next);
+		evrpc_schedule_request(connection, request);
+	}
+}
+
+void
+evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs)
+{
+	struct evhttp_connection *evcon;
+	TAILQ_FOREACH(evcon, &pool->connections, next) {
+		evcon->timeout = timeout_in_secs;
+	}
+	pool->timeout = timeout_in_secs;
+}
+
+
+static void evrpc_reply_done(struct evhttp_request *, void *);
+static void evrpc_request_timeout(int, short, void *);
+
+/*
+ * Finds a connection object associated with the pool that is currently
+ * idle and can be used to make a request.
+ */
+static struct evhttp_connection *
+evrpc_pool_find_connection(struct evrpc_pool *pool)
+{
+	struct evhttp_connection *connection;
+	TAILQ_FOREACH(connection, &pool->connections, next) {
+		if (TAILQ_FIRST(&connection->requests) == NULL)
+			return (connection);
+	}
+
+	return (NULL);
+}
+
+/*
+ * We assume that the ctx is no longer queued on the pool.
+ */
+static int
+evrpc_schedule_request(struct evhttp_connection *connection,
+    struct evrpc_request_wrapper *ctx)
+{
+	struct evhttp_request *req = NULL;
+	struct evrpc_pool *pool = ctx->pool;
+	struct evrpc_status status;
+	char *uri = NULL;
+	int res = 0;
+
+	if ((req = evhttp_request_new(evrpc_reply_done, ctx)) == NULL)
+		goto error;
+
+	/* serialize the request data into the output buffer */
+	ctx->request_marshal(req->output_buffer, ctx->request);
+
+	uri = evrpc_construct_uri(ctx->name);
+	if (uri == NULL)
+		goto error;
+
+	/* we need to know the connection that we might have to abort */
+	ctx->evcon = connection;
+
+	/* apply hooks to the outgoing request */
+	if (evrpc_process_hooks(&pool->output_hooks,
+		req, req->output_buffer) == -1)
+		goto error;
+
+	if (pool->timeout > 0) {
+		/* 
+		 * a timeout after which the whole rpc is going to be aborted.
+		 */
+		struct timeval tv;
+		evutil_timerclear(&tv);
+		tv.tv_sec = pool->timeout;
+		evtimer_add(&ctx->ev_timeout, &tv);
+	}
+
+	/* start the request over the connection */
+	res = evhttp_make_request(connection, req, EVHTTP_REQ_POST, uri);
+	free(uri);
+
+	if (res == -1)
+		goto error;
+
+	return (0);
+
+error:
+	memset(&status, 0, sizeof(status));
+	status.error = EVRPC_STATUS_ERR_UNSTARTED;
+	(*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+	evrpc_request_wrapper_free(ctx);
+	return (-1);
+}
+
+int
+evrpc_make_request(struct evrpc_request_wrapper *ctx)
+{
+	struct evrpc_pool *pool = ctx->pool;
+
+	/* initialize the event structure for this rpc */
+	evtimer_set(&ctx->ev_timeout, evrpc_request_timeout, ctx);
+	if (pool->base != NULL)
+		event_base_set(pool->base, &ctx->ev_timeout);
+
+	/* we better have some available connections on the pool */
+	assert(TAILQ_FIRST(&pool->connections) != NULL);
+
+	/* 
+	 * if no connection is available, we queue the request on the pool,
+	 * the next time a connection is empty, the rpc will be send on that.
+	 */
+	TAILQ_INSERT_TAIL(&pool->requests, ctx, next);
+
+	evrpc_pool_schedule(pool);
+
+	return (0);
+}
+
+static void
+evrpc_reply_done(struct evhttp_request *req, void *arg)
+{
+	struct evrpc_request_wrapper *ctx = arg;
+	struct evrpc_pool *pool = ctx->pool;
+	struct evrpc_status status;
+	int res = -1;
+	
+	/* cancel any timeout we might have scheduled */
+	event_del(&ctx->ev_timeout);
+
+	memset(&status, 0, sizeof(status));
+	status.http_req = req;
+
+	/* we need to get the reply now */
+	if (req != NULL) {
+		/* apply hooks to the incoming request */
+		if (evrpc_process_hooks(&pool->input_hooks,
+			req, req->input_buffer) == -1) {
+			status.error = EVRPC_STATUS_ERR_HOOKABORTED;
+			res = -1;
+		} else {
+			res = ctx->reply_unmarshal(ctx->reply,
+			    req->input_buffer);
+			if (res == -1) {
+				status.error = EVRPC_STATUS_ERR_BADPAYLOAD;
+			}
+		}
+	} else {
+		status.error = EVRPC_STATUS_ERR_TIMEOUT;
+	}
+
+	if (res == -1) {
+		/* clear everything that we might have written previously */
+		ctx->reply_clear(ctx->reply);
+	}
+
+	(*ctx->cb)(&status, ctx->request, ctx->reply, ctx->cb_arg);
+	
+	evrpc_request_wrapper_free(ctx);
+
+	/* the http layer owns the request structure */
+
+	/* see if we can schedule another request */
+	evrpc_pool_schedule(pool);
+}
+
+static void
+evrpc_pool_schedule(struct evrpc_pool *pool)
+{
+	struct evrpc_request_wrapper *ctx = TAILQ_FIRST(&pool->requests);
+	struct evhttp_connection *evcon;
+
+	/* if no requests are pending, we have no work */
+	if (ctx == NULL)
+		return;
+
+	if ((evcon = evrpc_pool_find_connection(pool)) != NULL) {
+		TAILQ_REMOVE(&pool->requests, ctx, next);
+		evrpc_schedule_request(evcon, ctx);
+	}
+}
+
+static void
+evrpc_request_timeout(int fd, short what, void *arg)
+{
+	struct evrpc_request_wrapper *ctx = arg;
+	struct evhttp_connection *evcon = ctx->evcon;
+	assert(evcon != NULL);
+
+	evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+}
Index: contrib/libevent/evrpc.h
===================================================================
RCS file: contrib/libevent/evrpc.h
diff -N contrib/libevent/evrpc.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/evrpc.h	20 Jun 2008 06:54:58 -0000
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@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 _EVRPC_H_
+#define _EVRPC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** @file evrpc.h
+ *
+ * This header files provides basic support for an RPC server and client.
+ *
+ * To support RPCs in a server, every supported RPC command needs to be
+ * defined and registered.
+ *
+ * EVRPC_HEADER(SendCommand, Request, Reply);
+ *
+ *  SendCommand is the name of the RPC command.
+ *  Request is the name of a structure generated by event_rpcgen.py.
+ *    It contains all parameters relating to the SendCommand RPC.  The
+ *    server needs to fill in the Reply structure.
+ *  Reply is the name of a structure generated by event_rpcgen.py.  It
+ *    contains the answer to the RPC.
+ *
+ * To register an RPC with an HTTP server, you need to first create an RPC
+ * base with:
+ *
+ *   struct evrpc_base *base = evrpc_init(http);
+ *
+ * A specific RPC can then be registered with
+ *
+ * EVRPC_REGISTER(base, SendCommand, Request, Reply,  FunctionCB, arg);
+ *
+ * when the server receives an appropriately formatted RPC, the user callback
+ * is invokved.   The callback needs to fill in the reply structure.
+ *
+ * void FunctionCB(EVRPC_STRUCT(SendCommand)* rpc, void *arg);
+ *
+ * To send the reply, call EVRPC_REQUEST_DONE(rpc);
+ *
+ * See the regression test for an example.
+ */
+
+struct evbuffer;
+struct event_base;
+struct evrpc_req_generic;
+
+/* Encapsulates a request */
+struct evrpc {
+	TAILQ_ENTRY(evrpc) next;
+
+	/* the URI at which the request handler lives */
+	const char* uri;
+
+	/* creates a new request structure */
+	void *(*request_new)(void);
+
+	/* frees the request structure */
+	void (*request_free)(void *);
+
+	/* unmarshals the buffer into the proper request structure */
+	int (*request_unmarshal)(void *, struct evbuffer *);
+
+	/* creates a new reply structure */
+	void *(*reply_new)(void);
+
+	/* creates a new reply structure */
+	void (*reply_free)(void *);
+
+	/* verifies that the reply is valid */
+	int (*reply_complete)(void *);
+	
+	/* marshals the reply into a buffer */
+	void (*reply_marshal)(struct evbuffer*, void *);
+
+	/* the callback invoked for each received rpc */
+	void (*cb)(struct evrpc_req_generic *, void *);
+	void *cb_arg;
+
+	/* reference for further configuration */
+	struct evrpc_base *base;
+};
+
+/** The type of a specific RPC Message
+ *
+ * @param rpcname the name of the RPC message
+ */
+#define EVRPC_STRUCT(rpcname) struct evrpc_req__##rpcname
+
+struct evhttp_request;
+struct evrpc_status;
+
+/* We alias the RPC specific structs to this voided one */
+struct evrpc_req_generic {
+	/* the unmarshaled request object */
+	void *request;
+
+	/* the empty reply object that needs to be filled in */
+	void *reply;
+
+	/* 
+	 * the static structure for this rpc; that can be used to
+	 * automatically unmarshal and marshal the http buffers.
+	 */
+	struct evrpc *rpc;
+
+	/*
+	 * the http request structure on which we need to answer.
+	 */
+	struct evhttp_request* http_req;
+
+	/*
+	 * callback to reply and finish answering this rpc
+	 */
+	void (*done)(struct evrpc_req_generic* rpc); 
+};
+
+/** Creates the definitions and prototypes for an RPC
+ *
+ * You need to use EVRPC_HEADER to create structures and function prototypes
+ * needed by the server and client implementation.  The structures have to be
+ * defined in an .rpc file and converted to source code via event_rpcgen.py
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_GENERATE()
+ */
+#define EVRPC_HEADER(rpcname, reqstruct, rplystruct) \
+EVRPC_STRUCT(rpcname) {	\
+	struct reqstruct* request; \
+	struct rplystruct* reply; \
+	struct evrpc* rpc; \
+	struct evhttp_request* http_req; \
+	void (*done)(struct evrpc_status *, \
+	    struct evrpc* rpc, void *request, void *reply);	     \
+};								     \
+int evrpc_send_request_##rpcname(struct evrpc_pool *, \
+    struct reqstruct *, struct rplystruct *, \
+    void (*)(struct evrpc_status *, \
+	struct reqstruct *, struct rplystruct *, void *cbarg),	\
+    void *);
+
+/** Generates the code for receiving and sending an RPC message
+ *
+ * EVRPC_GENERATE is used to create the code corresponding to sending
+ * and receiving a particular RPC message
+ *
+ * @param rpcname the name of the RPC
+ * @param reqstruct the name of the RPC request structure
+ * @param replystruct the name of the RPC reply structure
+ * @see EVRPC_HEADER()
+ */
+#define EVRPC_GENERATE(rpcname, reqstruct, rplystruct) \
+int evrpc_send_request_##rpcname(struct evrpc_pool *pool, \
+    struct reqstruct *request, struct rplystruct *reply, \
+    void (*cb)(struct evrpc_status *, \
+	struct reqstruct *, struct rplystruct *, void *cbarg),	\
+    void *cbarg) { \
+	struct evrpc_status status;				    \
+	struct evrpc_request_wrapper *ctx;			    \
+	ctx = (struct evrpc_request_wrapper *) \
+	    malloc(sizeof(struct evrpc_request_wrapper));	    \
+	if (ctx == NULL)					    \
+		goto error;					    \
+	ctx->pool = pool;					    \
+	ctx->evcon = NULL;					    \
+	ctx->name = strdup(#rpcname);				    \
+	if (ctx->name == NULL) {				    \
+		free(ctx);					    \
+		goto error;					    \
+	}							    \
+	ctx->cb = (void (*)(struct evrpc_status *, \
+		void *, void *, void *))cb;			    \
+	ctx->cb_arg = cbarg;					    \
+	ctx->request = (void *)request;				    \
+	ctx->reply = (void *)reply;				    \
+	ctx->request_marshal = (void (*)(struct evbuffer *, void *))reqstruct##_marshal; \
+	ctx->reply_clear = (void (*)(void *))rplystruct##_clear;    \
+	ctx->reply_unmarshal = (int (*)(void *, struct evbuffer *))rplystruct##_unmarshal; \
+	return (evrpc_make_request(ctx));			    \
+error:								    \
+	memset(&status, 0, sizeof(status));			    \
+	status.error = EVRPC_STATUS_ERR_UNSTARTED;		    \
+	(*(cb))(&status, request, reply, cbarg);		    \
+	return (-1);						    \
+}
+
+/** Provides access to the HTTP request object underlying an RPC
+ *
+ * Access to the underlying http object; can be used to look at headers or
+ * for getting the remote ip address
+ *
+ * @param rpc_req the rpc request structure provided to the server callback
+ * @return an struct evhttp_request object that can be inspected for
+ * HTTP headers or sender information.
+ */
+#define EVRPC_REQUEST_HTTP(rpc_req) (rpc_req)->http_req
+
+/** Creates the reply to an RPC request
+ * 
+ * EVRPC_REQUEST_DONE is used to answer a request; the reply is expected
+ * to have been filled in.  The request and reply pointers become invalid
+ * after this call has finished.
+ * 
+ * @param rpc_req the rpc request structure provided to the server callback
+ */
+#define EVRPC_REQUEST_DONE(rpc_req) do { \
+  struct evrpc_req_generic *_req = (struct evrpc_req_generic *)(rpc_req); \
+  _req->done(_req); \
+} while (0)
+  
+
+/* Takes a request object and fills it in with the right magic */
+#define EVRPC_REGISTER_OBJECT(rpc, name, request, reply) \
+  do { \
+    (rpc)->uri = strdup(#name); \
+    if ((rpc)->uri == NULL) {			 \
+      fprintf(stderr, "failed to register object\n");	\
+      exit(1);						\
+    } \
+    (rpc)->request_new = (void *(*)(void))request##_new; \
+    (rpc)->request_free = (void (*)(void *))request##_free; \
+    (rpc)->request_unmarshal = (int (*)(void *, struct evbuffer *))request##_unmarshal; \
+    (rpc)->reply_new = (void *(*)(void))reply##_new; \
+    (rpc)->reply_free = (void (*)(void *))reply##_free; \
+    (rpc)->reply_complete = (int (*)(void *))reply##_complete; \
+    (rpc)->reply_marshal = (void (*)(struct evbuffer*, void *))reply##_marshal; \
+  } while (0)
+
+struct evrpc_base;
+struct evhttp;
+
+/* functions to start up the rpc system */
+
+/** Creates a new rpc base from which RPC requests can be received
+ *
+ * @param server a pointer to an existing HTTP server
+ * @return a newly allocated evrpc_base struct
+ * @see evrpc_free()
+ */
+struct evrpc_base *evrpc_init(struct evhttp *server);
+
+/** 
+ * Frees the evrpc base
+ *
+ * For now, you are responsible for making sure that no rpcs are ongoing.
+ *
+ * @param base the evrpc_base object to be freed
+ * @see evrpc_init
+ */
+void evrpc_free(struct evrpc_base *base);
+
+/** register RPCs with the HTTP Server
+ *
+ * registers a new RPC with the HTTP server, each RPC needs to have
+ * a unique name under which it can be identified.
+ *
+ * @param base the evrpc_base structure in which the RPC should be
+ *   registered.
+ * @param name the name of the RPC
+ * @param request the name of the RPC request structure
+ * @param reply the name of the RPC reply structure
+ * @param callback the callback that should be invoked when the RPC
+ * is received.  The callback has the following prototype
+ *   void (*callback)(EVRPC_STRUCT(Message)* rpc, void *arg)
+ * @param cbarg an additional parameter that can be passed to the callback.
+ *   The parameter can be used to carry around state.
+ */
+#define EVRPC_REGISTER(base, name, request, reply, callback, cbarg) \
+  do { \
+    struct evrpc* rpc = (struct evrpc *)calloc(1, sizeof(struct evrpc)); \
+    EVRPC_REGISTER_OBJECT(rpc, name, request, reply); \
+    evrpc_register_rpc(base, rpc, \
+	(void (*)(struct evrpc_req_generic*, void *))callback, cbarg);	\
+  } while (0)
+
+int evrpc_register_rpc(struct evrpc_base *, struct evrpc *,
+    void (*)(struct evrpc_req_generic*, void *), void *);
+
+/**
+ * Unregisters an already registered RPC
+ *
+ * @param base the evrpc_base object from which to unregister an RPC
+ * @param name the name of the rpc to unregister
+ * @return -1 on error or 0 when successful.
+ * @see EVRPC_REGISTER()
+ */
+#define EVRPC_UNREGISTER(base, name) evrpc_unregister_rpc(base, #name)
+
+int evrpc_unregister_rpc(struct evrpc_base *base, const char *name);
+
+/*
+ * Client-side RPC support
+ */
+
+struct evrpc_pool;
+struct evhttp_connection;
+
+/** 
+ * provides information about the completed RPC request.
+ */
+struct evrpc_status {
+#define EVRPC_STATUS_ERR_NONE		0
+#define EVRPC_STATUS_ERR_TIMEOUT	1
+#define EVRPC_STATUS_ERR_BADPAYLOAD	2
+#define EVRPC_STATUS_ERR_UNSTARTED	3
+#define EVRPC_STATUS_ERR_HOOKABORTED	4
+	int error;
+
+	/* for looking at headers or other information */
+	struct evhttp_request *http_req;
+};
+
+struct evrpc_request_wrapper {
+	TAILQ_ENTRY(evrpc_request_wrapper) next;
+
+        /* pool on which this rpc request is being made */
+        struct evrpc_pool *pool;
+
+        /* connection on which the request is being sent */
+	struct evhttp_connection *evcon;
+
+	/* event for implementing request timeouts */
+	struct event ev_timeout;
+
+	/* the name of the rpc */
+	char *name;
+
+	/* callback */
+	void (*cb)(struct evrpc_status*, void *request, void *reply, void *arg);
+	void *cb_arg;
+
+	void *request;
+	void *reply;
+
+	/* unmarshals the buffer into the proper request structure */
+	void (*request_marshal)(struct evbuffer *, void *);
+
+	/* removes all stored state in the reply */
+	void (*reply_clear)(void *);
+
+	/* marshals the reply into a buffer */
+	int (*reply_unmarshal)(void *, struct evbuffer*);
+};
+
+/** launches an RPC and sends it to the server
+ *
+ * EVRPC_MAKE_REQUEST() is used by the client to send an RPC to the server.
+ *
+ * @param name the name of the RPC
+ * @param pool the evrpc_pool that contains the connection objects over which
+ *   the request should be sent.
+ * @param request a pointer to the RPC request structure - it contains the
+ *   data to be sent to the server.
+ * @param reply a pointer to the RPC reply structure.  It is going to be filled
+ *   if the request was answered successfully
+ * @param cb the callback to invoke when the RPC request has been answered
+ * @param cbarg an additional argument to be passed to the client
+ * @return 0 on success, -1 on failure
+ */
+#define EVRPC_MAKE_REQUEST(name, pool, request, reply, cb, cbarg)	\
+	evrpc_send_request_##name(pool, request, reply, cb, cbarg)
+
+int evrpc_make_request(struct evrpc_request_wrapper *);
+
+/** creates an rpc connection pool
+ * 
+ * a pool has a number of connections associated with it.
+ * rpc requests are always made via a pool.
+ *
+ * @param base a pointer to an struct event_based object; can be left NULL
+ *   in singled-threaded applications
+ * @return a newly allocated struct evrpc_pool object
+ * @see evrpc_pool_free()
+ */
+struct evrpc_pool *evrpc_pool_new(struct event_base *base);
+/** frees an rpc connection pool
+ *
+ * @param pool a pointer to an evrpc_pool allocated via evrpc_pool_new()
+ * @see evrpc_pool_new()
+ */
+void evrpc_pool_free(struct evrpc_pool *pool);
+/*
+ * adds a connection over which rpc can be dispatched.  the connection
+ * object must have been newly created.
+ */
+void evrpc_pool_add_connection(struct evrpc_pool *, 
+    struct evhttp_connection *);
+
+/**
+ * Sets the timeout in secs after which a request has to complete.  The
+ * RPC is completely aborted if it does not complete by then.  Setting
+ * the timeout to 0 means that it never timeouts and can be used to
+ * implement callback type RPCs.
+ *
+ * Any connection already in the pool will be updated with the new
+ * timeout.  Connections added to the pool after set_timeout has be
+ * called receive the pool timeout only if no timeout has been set
+ * for the connection itself.
+ *
+ * @param pool a pointer to a struct evrpc_pool object
+ * @param timeout_in_secs the number of seconds after which a request should
+ *   timeout and a failure be returned to the callback.
+ */
+void evrpc_pool_set_timeout(struct evrpc_pool *pool, int timeout_in_secs);
+
+/**
+ * Hooks for changing the input and output of RPCs; this can be used to
+ * implement compression, authentication, encryption, ...
+ */
+
+enum EVRPC_HOOK_TYPE {
+	EVRPC_INPUT,		/**< apply the function to an input hook */
+	EVRPC_OUTPUT		/**< apply the function to an output hook */
+};
+
+#ifndef WIN32
+/** Deprecated alias for EVRPC_INPUT.  Not available on windows, where it
+ * conflicts with platform headers. */
+#define INPUT EVRPC_INPUT
+/** Deprecated alias for EVRPC_OUTPUT.  Not available on windows, where it
+ * conflicts with platform headers. */
+#define OUTPUT EVRPC_OUTPUT
+#endif
+
+/** adds a processing hook to either an rpc base or rpc pool
+ *
+ * If a hook returns -1, the processing is aborted.
+ *
+ * The add functions return handles that can be used for removing hooks.
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param cb the callback to call when the hook is activated
+ * @param cb_arg an additional argument for the callback
+ * @return a handle to the hook so it can be removed later
+ * @see evrpc_remove_hook()
+ */
+void *evrpc_add_hook(void *vbase,
+    enum EVRPC_HOOK_TYPE hook_type,
+    int (*cb)(struct evhttp_request *, struct evbuffer *, void *),
+    void *cb_arg);
+
+/** removes a previously added hook
+ *
+ * @param vbase a pointer to either struct evrpc_base or struct evrpc_pool
+ * @param hook_type either INPUT or OUTPUT
+ * @param handle a handle returned by evrpc_add_hook()
+ * @return 1 on success or 0 on failure
+ * @see evrpc_add_hook()
+ */
+int evrpc_remove_hook(void *vbase,
+    enum EVRPC_HOOK_TYPE hook_type,
+    void *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVRPC_H_ */
Index: contrib/libevent/evsignal.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/evsignal.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 evsignal.h
--- contrib/libevent/evsignal.h	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/evsignal.h	12 Nov 2007 02:37:32 -0000
@@ -27,6 +27,8 @@
 #ifndef _EVSIGNAL_H_
 #define _EVSIGNAL_H_
 
+typedef void (*ev_sighandler_t)(int);
+
 struct evsignal_info {
 	struct event_list signalqueue;
 	struct event ev_signal;
@@ -34,6 +36,12 @@
 	int ev_signal_added;
 	volatile sig_atomic_t evsignal_caught;
 	sig_atomic_t evsigcaught[NSIG];
+#ifdef HAVE_SIGACTION
+	struct sigaction **sh_old;
+#else
+	ev_sighandler_t **sh_old;
+#endif
+	int sh_old_max;
 };
 void evsignal_init(struct event_base *);
 void evsignal_process(struct event_base *);
Index: contrib/libevent/evutil.c
===================================================================
RCS file: contrib/libevent/evutil.c
diff -N contrib/libevent/evutil.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/evutil.c	25 Jun 2008 21:33:07 -0000
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@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 HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <errno.h>
+#if defined WIN32 && !defined(HAVE_GETTIMEOFDAY_H)
+#include <sys/timeb.h>
+#endif
+#include <stdarg.h>
+#include <stdio.h>
+
+#include "evutil.h"
+#include "log.h"
+
+int
+evutil_socketpair(int family, int type, int protocol, int fd[2])
+{
+#ifndef WIN32
+	return socketpair(family, type, protocol, fd);
+#else
+	/* This code is originally from Tor.  Used with permission. */
+
+	/* This socketpair does not work when localhost is down. So
+	 * it's really not the same thing at all. But it's close enough
+	 * for now, and really, when localhost is down sometimes, we
+	 * have other problems too.
+	 */
+	int listener = -1;
+	int connector = -1;
+	int acceptor = -1;
+	struct sockaddr_in listen_addr;
+	struct sockaddr_in connect_addr;
+	int size;
+	int saved_errno = -1;
+
+	if (protocol
+#ifdef AF_UNIX
+		|| family != AF_UNIX
+#endif
+		) {
+		EVUTIL_SET_SOCKET_ERROR(WSAEAFNOSUPPORT);
+		return -1;
+	}
+	if (!fd) {
+		EVUTIL_SET_SOCKET_ERROR(WSAEINVAL);
+		return -1;
+	}
+
+	listener = socket(AF_INET, type, 0);
+	if (listener < 0)
+		return -1;
+	memset(&listen_addr, 0, sizeof(listen_addr));
+	listen_addr.sin_family = AF_INET;
+	listen_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	listen_addr.sin_port = 0;	/* kernel chooses port.	 */
+	if (bind(listener, (struct sockaddr *) &listen_addr, sizeof (listen_addr))
+		== -1)
+		goto tidy_up_and_fail;
+	if (listen(listener, 1) == -1)
+		goto tidy_up_and_fail;
+
+	connector = socket(AF_INET, type, 0);
+	if (connector < 0)
+		goto tidy_up_and_fail;
+	/* We want to find out the port number to connect to.  */
+	size = sizeof(connect_addr);
+	if (getsockname(listener, (struct sockaddr *) &connect_addr, &size) == -1)
+		goto tidy_up_and_fail;
+	if (size != sizeof (connect_addr))
+		goto abort_tidy_up_and_fail;
+	if (connect(connector, (struct sockaddr *) &connect_addr,
+				sizeof(connect_addr)) == -1)
+		goto tidy_up_and_fail;
+
+	size = sizeof(listen_addr);
+	acceptor = accept(listener, (struct sockaddr *) &listen_addr, &size);
+	if (acceptor < 0)
+		goto tidy_up_and_fail;
+	if (size != sizeof(listen_addr))
+		goto abort_tidy_up_and_fail;
+	EVUTIL_CLOSESOCKET(listener);
+	/* Now check we are talking to ourself by matching port and host on the
+	   two sockets.	 */
+	if (getsockname(connector, (struct sockaddr *) &connect_addr, &size) == -1)
+		goto tidy_up_and_fail;
+	if (size != sizeof (connect_addr)
+		|| listen_addr.sin_family != connect_addr.sin_family
+		|| listen_addr.sin_addr.s_addr != connect_addr.sin_addr.s_addr
+		|| listen_addr.sin_port != connect_addr.sin_port)
+		goto abort_tidy_up_and_fail;
+	fd[0] = connector;
+	fd[1] = acceptor;
+
+	return 0;
+
+ abort_tidy_up_and_fail:
+	saved_errno = WSAECONNABORTED;
+ tidy_up_and_fail:
+	if (saved_errno < 0)
+		saved_errno = WSAGetLastError();
+	if (listener != -1)
+		EVUTIL_CLOSESOCKET(listener);
+	if (connector != -1)
+		EVUTIL_CLOSESOCKET(connector);
+	if (acceptor != -1)
+		EVUTIL_CLOSESOCKET(acceptor);
+
+	EVUTIL_SET_SOCKET_ERROR(saved_errno);
+	return -1;
+#endif
+}
+
+int
+evutil_make_socket_nonblocking(int fd)
+{
+#ifdef WIN32
+	{
+		unsigned long nonblocking = 1;
+		ioctlsocket(fd, FIONBIO, (unsigned long*) &nonblocking);
+	}
+#else
+	if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) {
+		event_warn("fcntl(O_NONBLOCK)");
+		return -1;
+}	
+#endif
+	return 0;
+}
+
+ev_int64_t
+evutil_strtoll(const char *s, char **endptr, int base)
+{
+#ifdef HAVE_STRTOLL
+	return (ev_int64_t)strtoll(s, endptr, base);
+#elif SIZEOF_LONG == 8
+	return (ev_int64_t)strtol(s, endptr, base);
+#elif defined(WIN32) && defined(_MSC_VER) && _MSC_VER < 1300
+	/* XXXX on old versions of MS APIs, we only support base
+	 * 10. */
+	ev_int64_t r;
+	if (base != 10)
+		return 0;
+	r = (ev_int64_t) _atoi64(s);
+	while (isspace(*s))
+		++s;
+	while (isdigit(*s))
+		++s;
+	if (endptr)
+		*endptr = (char*) s;
+	return r;
+#elif defined(WIN32)
+	return (ev_int64_t) _strtoi64(s, endptr, base);
+#else
+#error "I don't know how to parse 64-bit integers."
+#endif
+}
+
+#ifndef _EVENT_HAVE_GETTIMEOFDAY
+int
+evutil_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	struct _timeb tb;
+
+	if(tv == NULL)
+		return -1;
+
+	_ftime(&tb);
+	tv->tv_sec = (long) tb.time;
+	tv->tv_usec = ((int) tb.millitm) * 1000;
+	return 0;
+}
+#endif
+
+int
+evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+{
+	int r;
+	va_list ap;
+	va_start(ap, format);
+	r = evutil_vsnprintf(buf, buflen, format, ap);
+	va_end(ap);
+	return r;
+}
+
+int
+evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
+{
+#ifdef _MSC_VER
+	int r = _vsnprintf(buf, buflen, format, ap);
+	buf[buflen-1] = '\0';
+	if (r >= 0)
+		return r;
+	else
+		return _vscprintf(format, ap);
+#else
+	int r = vsnprintf(buf, buflen, format, ap);
+	buf[buflen-1] = '\0';
+	return r;
+#endif
+}
Index: contrib/libevent/evutil.h
===================================================================
RCS file: contrib/libevent/evutil.h
diff -N contrib/libevent/evutil.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/evutil.h	25 Jun 2008 15:30:20 -0000
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@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 _EVUTIL_H_
+#define _EVUTIL_H_
+
+/** @file evutil.h
+
+  Common convenience functions for cross-platform portability and
+  related socket manipulations.
+
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <event-config.h>
+#ifdef _EVENT_HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef _EVENT_HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(_EVENT_HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef _EVENT_HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef _EVENT_HAVE_UINT64_T
+#define ev_uint64_t uint64_t
+#define ev_int64_t int64_t
+#elif defined(WIN32)
+#define ev_uint64_t unsigned __int64
+#define ev_int64_t signed __int64
+#elif _EVENT_SIZEOF_LONG_LONG == 8
+#define ev_uint64_t unsigned long long
+#define ev_int64_t long long
+#elif _EVENT_SIZEOF_LONG == 8
+#define ev_uint64_t unsigned long
+#define ev_int64_t long
+#else
+#error "No way to define ev_uint64_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT32_T
+#define ev_uint32_t uint32_t
+#elif defined(WIN32)
+#define ev_uint32_t unsigned int
+#elif _EVENT_SIZEOF_LONG == 4
+#define ev_uint32_t unsigned long
+#elif _EVENT_SIZEOF_INT == 4
+#define ev_uint32_t unsigned int
+#else
+#error "No way to define ev_uint32_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT16_T
+#define ev_uint16_t uint16_t
+#elif defined(WIN32)
+#define ev_uint16_t unsigned short
+#elif _EVENT_SIZEOF_INT == 2
+#define ev_uint16_t unsigned int
+#elif _EVENT_SIZEOF_SHORT == 2
+#define ev_uint16_t unsigned short
+#else
+#error "No way to define ev_uint16_t"
+#endif
+
+#ifdef _EVENT_HAVE_UINT8_T
+#define ev_uint8_t uint8_t
+#else
+#define ev_uint8_t unsigned char
+#endif
+
+int evutil_socketpair(int d, int type, int protocol, int sv[2]);
+int evutil_make_socket_nonblocking(int sock);
+#ifdef WIN32
+#define EVUTIL_CLOSESOCKET(s) closesocket(s)
+#else
+#define EVUTIL_CLOSESOCKET(s) close(s)
+#endif
+
+#ifdef WIN32
+#define EVUTIL_SOCKET_ERROR() WSAGetLastError()
+#define EVUTIL_SET_SOCKET_ERROR(errcode)		\
+	do { WSASetLastError(errcode); } while (0)
+#else
+#define EVUTIL_SOCKET_ERROR() (errno)
+#define EVUTIL_SET_SOCKET_ERROR(errcode)		\
+		do { errno = (errcode); } while (0)
+#endif
+
+/*
+ * Manipulation functions for struct timeval
+ */
+#ifdef _EVENT_HAVE_TIMERADD
+#define evutil_timeradd(tvp, uvp, vvp) timeradd((tvp), (uvp), (vvp))
+#define evutil_timersub(tvp, uvp, vvp) timersub((tvp), (uvp), (vvp))
+#else
+#define evutil_timeradd(tvp, uvp, vvp)							\
+	do {														\
+		(vvp)->tv_sec = (tvp)->tv_sec + (uvp)->tv_sec;			\
+		(vvp)->tv_usec = (tvp)->tv_usec + (uvp)->tv_usec;       \
+		if ((vvp)->tv_usec >= 1000000) {						\
+			(vvp)->tv_sec++;									\
+			(vvp)->tv_usec -= 1000000;							\
+		}														\
+	} while (0)
+#define	evutil_timersub(tvp, uvp, vvp)						\
+	do {													\
+		(vvp)->tv_sec = (tvp)->tv_sec - (uvp)->tv_sec;		\
+		(vvp)->tv_usec = (tvp)->tv_usec - (uvp)->tv_usec;	\
+		if ((vvp)->tv_usec < 0) {							\
+			(vvp)->tv_sec--;								\
+			(vvp)->tv_usec += 1000000;						\
+		}													\
+	} while (0)
+#endif /* !_EVENT_HAVE_HAVE_TIMERADD */
+
+#ifdef _EVENT_HAVE_TIMERCLEAR
+#define evutil_timerclear(tvp) timerclear(tvp)
+#else
+#define	evutil_timerclear(tvp)	(tvp)->tv_sec = (tvp)->tv_usec = 0
+#endif
+
+#define	evutil_timercmp(tvp, uvp, cmp)							\
+	(((tvp)->tv_sec == (uvp)->tv_sec) ?							\
+	 ((tvp)->tv_usec cmp (uvp)->tv_usec) :						\
+	 ((tvp)->tv_sec cmp (uvp)->tv_sec))
+
+#ifdef _EVENT_HAVE_TIMERISSET
+#define evutil_timerisset(tvp) timerisset(tvp)
+#else
+#define	evutil_timerisset(tvp)	((tvp)->tv_sec || (tvp)->tv_usec)
+#endif
+
+
+/* big-int related functions */
+ev_int64_t evutil_strtoll(const char *s, char **endptr, int base);
+
+
+#ifdef _EVENT_HAVE_GETTIMEOFDAY
+#define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
+#else
+int evutil_gettimeofday(struct timeval *tv, struct timezone *tz);
+#endif
+
+int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+#ifdef __GNUC__
+	__attribute__((format(printf, 3, 4)))
+#endif
+	;
+int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _EVUTIL_H_ */
Index: contrib/libevent/http-internal.h
===================================================================
RCS file: contrib/libevent/http-internal.h
diff -N contrib/libevent/http-internal.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/http-internal.h	4 May 2008 22:22:05 -0000
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2001 Niels Provos <provos@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
+
+enum evhttp_connection_error {
+	EVCON_HTTP_TIMEOUT,
+	EVCON_HTTP_EOF,
+	EVCON_HTTP_INVALID_HEADER
+};
+
+struct evbuffer;
+struct addrinfo;
+struct evhttp_request;
+
+/* A stupid connection object - maybe make this a bufferevent later */
+
+enum evhttp_connection_state {
+	EVCON_DISCONNECTED,	/* not currently connected not trying either */
+	EVCON_CONNECTING,	/* tries to currently connect */
+	EVCON_CONNECTED		/* connection is established */
+};
+
+struct event_base;
+
+struct evhttp_connection {
+	/* we use tailq only if they were created for an http server */
+	TAILQ_ENTRY(evhttp_connection) (next);
+
+	int fd;
+	struct event ev;
+	struct event close_ev;
+	struct evbuffer *input_buffer;
+	struct evbuffer *output_buffer;
+	
+	char *bind_address;		/* address to use for binding the src */
+
+	char *address;			/* address to connect to */
+	u_short port;
+
+	int flags;
+#define EVHTTP_CON_INCOMING	0x0001	/* only one request on it ever */
+#define EVHTTP_CON_OUTGOING	0x0002  /* multiple requests possible */
+#define EVHTTP_CON_CLOSEDETECT  0x0004  /* detecting if persistent close */
+
+	int timeout;			/* timeout in seconds for events */
+	int retry_cnt;			/* retry count */
+	int retry_max;			/* maximum number of retries */
+	
+	enum evhttp_connection_state state;
+
+	/* for server connections, the http server they are connected with */
+	struct evhttp *http_server;
+
+	TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
+	
+						   void (*cb)(struct evhttp_connection *, void *);
+	void *cb_arg;
+	
+	void (*closecb)(struct evhttp_connection *, void *);
+	void *closecb_arg;
+
+	struct event_base *base;
+};
+
+struct evhttp_cb {
+	TAILQ_ENTRY(evhttp_cb) next;
+
+	char *what;
+
+	void (*cb)(struct evhttp_request *req, void *);
+	void *cbarg;
+};
+
+/* both the http server as well as the rpc system need to queue connections */
+TAILQ_HEAD(evconq, evhttp_connection);
+
+/* each bound socket is stored in one of these */
+struct evhttp_bound_socket {
+	TAILQ_ENTRY(evhttp_bound_socket) (next);
+
+	struct event  bind_ev;
+};
+
+struct evhttp {
+	TAILQ_HEAD(boundq, evhttp_bound_socket) sockets;
+
+	TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
+        struct evconq connections;
+
+        int timeout;
+
+	void (*gencb)(struct evhttp_request *req, void *);
+	void *gencbarg;
+
+	struct event_base *base;
+};
+
+/* resets the connection; can be reused for more requests */
+void evhttp_connection_reset(struct evhttp_connection *);
+
+/* connects if necessary */
+int evhttp_connection_connect(struct evhttp_connection *);
+
+/* notifies the current request that it failed; resets connection */
+void evhttp_connection_fail(struct evhttp_connection *,
+    enum evhttp_connection_error error);
+
+void evhttp_get_request(struct evhttp *, int, struct sockaddr *, socklen_t);
+
+int evhttp_hostportfile(char *, char **, u_short *, char **);
+
+int evhttp_parse_lines(struct evhttp_request *, struct evbuffer*);
+
+void evhttp_start_read(struct evhttp_connection *);
+void evhttp_read_header(int, short, void *);
+void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
+
+void evhttp_write_buffer(struct evhttp_connection *,
+    void (*)(struct evhttp_connection *, 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 *);
+
+#endif /* _HTTP_H */
Index: contrib/libevent/http.c
===================================================================
RCS file: contrib/libevent/http.c
diff -N contrib/libevent/http.c
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/http.c	30 Jun 2008 21:08:53 -0000
@@ -0,0 +1,2612 @@
+/*
+ * Copyright (c) 2002-2006 Niels Provos <provos@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 HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_IOCCOM_H
+#include <sys/ioccom.h>
+#endif
+
+#ifndef WIN32
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#endif
+
+#include <sys/queue.h>
+
+#ifndef WIN32
+#include <netinet/in.h>
+#include <netdb.h>
+#endif
+
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef WIN32
+#include <syslog.h>
+#endif
+#include <signal.h>
+#include <time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#undef timeout_pending
+#undef timeout_initialized
+
+#include "strlcpy-internal.h"
+#include "event.h"
+#include "evhttp.h"
+#include "evutil.h"
+#include "log.h"
+#include "http-internal.h"
+
+#ifdef WIN32
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define strdup _strdup
+#endif
+
+#ifndef HAVE_GETNAMEINFO
+#define NI_MAXSERV 32
+#define NI_MAXHOST 1025
+
+#define NI_NUMERICHOST 1
+#define NI_NUMERICSERV 2
+
+int
+fake_getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 
+	size_t hostlen, char *serv, size_t servlen, int flags)
+{
+        struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+        
+        if (serv != NULL) {
+				char tmpserv[16];
+				evutil_snprintf(tmpserv, sizeof(tmpserv),
+					"%d", ntohs(sin->sin_port));
+                if (strlcpy(serv, tmpserv, servlen) >= servlen)
+                        return (-1);
+        }
+
+        if (host != NULL) {
+                if (flags & NI_NUMERICHOST) {
+                        if (strlcpy(host, inet_ntoa(sin->sin_addr),
+                            hostlen) >= hostlen)
+                                return (-1);
+                        else
+                                return (0);
+                } else {
+						struct hostent *hp;
+                        hp = gethostbyaddr((char *)&sin->sin_addr, 
+                            sizeof(struct in_addr), AF_INET);
+                        if (hp == NULL)
+                                return (-2);
+                        
+                        if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
+                                return (-1);
+                        else
+                                return (0);
+                }
+        }
+        return (0);
+}
+
+#endif
+
+#ifndef HAVE_GETADDRINFO
+struct addrinfo {
+	int ai_family;
+	int ai_socktype;
+	int ai_protocol;
+	size_t ai_addrlen;
+	struct sockaddr *ai_addr;
+	struct addrinfo *ai_next;
+};
+static int
+fake_getaddrinfo(const char *hostname, struct addrinfo *ai)
+{
+	struct hostent *he = NULL;
+	struct sockaddr_in *sa;
+	if (hostname) {
+		he = gethostbyname(hostname);
+		if (!he)
+			return (-1);
+	}
+	ai->ai_family = he ? he->h_addrtype : AF_INET;
+	ai->ai_socktype = SOCK_STREAM;
+	ai->ai_protocol = 0;
+	ai->ai_addrlen = sizeof(struct sockaddr_in);
+	if (NULL == (ai->ai_addr = malloc(ai->ai_addrlen)))
+		return (-1);
+	sa = (struct sockaddr_in*)ai->ai_addr;
+	memset(sa, 0, ai->ai_addrlen);
+	if (he) {
+		sa->sin_family = he->h_addrtype;
+		memcpy(&sa->sin_addr, he->h_addr_list[0], he->h_length);
+	} else {
+		sa->sin_family = AF_INET;
+		sa->sin_addr.s_addr = INADDR_ANY;
+	}
+	ai->ai_next = NULL;
+	return (0);
+}
+static void
+fake_freeaddrinfo(struct addrinfo *ai)
+{
+	free(ai->ai_addr);
+}
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#endif
+
+/* wrapper for setting the base from the http server */
+#define EVHTTP_BASE_SET(x, y) do { \
+	if ((x)->base != NULL) event_base_set((x)->base, y);	\
+} while (0) 
+
+extern int debug;
+
+static int socket_connect(int fd, const char *address, unsigned short port);
+static int bind_socket_ai(struct addrinfo *, int reuse);
+static int bind_socket(const char *, u_short, int reuse);
+static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
+static int evhttp_associate_new_request_with_connection(
+	struct evhttp_connection *evcon);
+static void evhttp_connection_start_detectclose(
+	struct evhttp_connection *evcon);
+static void evhttp_connection_stop_detectclose(
+	struct evhttp_connection *evcon);
+static void evhttp_request_dispatch(struct evhttp_connection* evcon);
+
+void evhttp_read(int, short, void *);
+void evhttp_write(int, short, void *);
+
+#ifndef HAVE_STRSEP
+/* strsep replacement for platforms that lack it.  Only works if
+ * del is one character long. */
+static char *
+strsep(char **s, const char *del)
+{
+	char *d, *tok;
+	assert(strlen(del) == 1);
+	if (!s || !*s)
+		return NULL;
+	tok = *s;
+	d = strstr(tok, del);
+	if (d) {
+		*d = '\0';
+		*s = d + 1;
+	} else
+		*s = NULL;
+	return tok;
+}
+#endif
+
+static const char *
+html_replace(char ch, char *buf)
+{
+	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, old_size = strlen(html);
+	char *escaped_html, *p;
+	char scratch_space[2];
+	
+	for (i = 0; i < old_size; ++i)
+          new_size += strlen(html_replace(html[i], scratch_space));
+
+	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 < old_size; ++i) {
+		const char *replaced = html_replace(html[i], scratch_space);
+		/* this is length checked */
+		strcpy(p, replaced);
+		p += strlen(replaced);
+	}
+
+	*p = '\0';
+
+	return (escaped_html);
+}
+
+static 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);
+}
+
+static void
+evhttp_add_event(struct event *ev, int timeout, int default_timeout)
+{
+	if (timeout != 0) {
+		struct timeval tv;
+		
+		evutil_timerclear(&tv);
+		tv.tv_sec = timeout != -1 ? timeout : default_timeout;
+		event_add(ev, &tv);
+	} else {
+		event_add(ev, NULL);
+	}
+}
+
+void
+evhttp_write_buffer(struct evhttp_connection *evcon,
+    void (*cb)(struct evhttp_connection *, void *), void *arg)
+{
+	event_debug(("%s: preparing to write buffer\n", __func__));
+
+	/* Set call back */
+	evcon->cb = cb;
+	evcon->cb_arg = arg;
+
+	/* check if the event is already pending */
+	if (event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL))
+		event_del(&evcon->ev);
+
+	event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_write, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_WRITE_TIMEOUT);
+}
+
+/*
+ * Create the headers need for an HTTP request
+ */
+static void
+evhttp_make_header_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req)
+{
+	char line[1024];
+	const char *method;
+	
+	evhttp_remove_header(req->output_headers, "Accept-Encoding");
+	evhttp_remove_header(req->output_headers, "Proxy-Connection");
+
+	/* Generate request line */
+	method = evhttp_method(req->type);
+	evutil_snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n",
+	    method, req->uri, req->major, req->minor);
+	evbuffer_add(evcon->output_buffer, 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];
+		evutil_snprintf(size, sizeof(size), "%ld",
+			 (long)EVBUFFER_LENGTH(req->output_buffer));
+		evhttp_add_header(req->output_headers, "Content-Length", size);
+	}
+}
+
+static int
+evhttp_is_connection_close(int flags, struct evkeyvalq* headers)
+{
+	if (flags & EVHTTP_PROXY_REQUEST) {
+		/* proxy connection */
+		const char *connection = evhttp_find_header(headers, "Proxy-Connection");
+		return (connection == NULL || strcasecmp(connection, "keep-alive") != 0);
+	} else {
+		const char *connection = evhttp_find_header(headers, "Connection");
+		return (connection != NULL && strcasecmp(connection, "close") == 0);
+	}
+}
+
+static int
+evhttp_is_connection_keepalive(struct evkeyvalq* headers)
+{
+	const char *connection = evhttp_find_header(headers, "Connection");
+	return (connection != NULL 
+	    && strncasecmp(connection, "keep-alive", 10) == 0);
+}
+
+static void
+evhttp_maybe_add_date_header(struct evkeyvalq *headers)
+{
+	if (evhttp_find_header(headers, "Date") == NULL) {
+		char date[50];
+#ifndef WIN32
+		struct tm cur;
+#endif
+		struct tm *cur_p;
+		time_t t = time(NULL);
+#ifdef WIN32
+		cur_p = gmtime(&t);
+#else
+		gmtime_r(&t, &cur);
+		cur_p = &cur;
+#endif
+		if (strftime(date, sizeof(date),
+			"%a, %d %b %Y %H:%M:%S GMT", cur_p) != 0) {
+			evhttp_add_header(headers, "Date", date);
+		}
+	}
+}
+
+static void
+evhttp_maybe_add_content_length_header(struct evkeyvalq *headers,
+    long content_length)
+{
+	if (evhttp_find_header(headers, "Transfer-Encoding") == NULL &&
+	    evhttp_find_header(headers,	"Content-Length") == NULL) {
+		char len[12];
+		evutil_snprintf(len, sizeof(len), "%ld", content_length);
+		evhttp_add_header(headers, "Content-Length", len);
+	}
+}
+
+/*
+ * Create the headers needed for an HTTP reply
+ */
+
+static void
+evhttp_make_header_response(struct evhttp_connection *evcon,
+    struct evhttp_request *req)
+{
+	int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
+	char line[1024];
+	evutil_snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
+	    req->major, req->minor, req->response_code,
+	    req->response_code_line);
+	evbuffer_add(evcon->output_buffer, line, strlen(line));
+
+	if (req->major == 1) {
+		if (req->minor == 1)
+			evhttp_maybe_add_date_header(req->output_headers);
+
+		/*
+		 * if the protocol is 1.0; and the connection was keep-alive
+		 * we need to add a keep-alive header, too.
+		 */
+		if (req->minor == 0 && is_keepalive)
+			evhttp_add_header(req->output_headers,
+			    "Connection", "keep-alive");
+
+		if (req->minor == 1 || is_keepalive) {
+			/* 
+			 * we need to add the content length if the
+			 * user did not give it, this is required for
+			 * persistent connections to work.
+			 */
+			evhttp_maybe_add_content_length_header(
+				req->output_headers,
+				(long)EVBUFFER_LENGTH(req->output_buffer));
+		}
+	}
+
+	/* Potentially add headers for unidentified content. */
+	if (EVBUFFER_LENGTH(req->output_buffer)) {
+		if (evhttp_find_header(req->output_headers,
+			"Content-Type") == NULL) {
+			evhttp_add_header(req->output_headers,
+			    "Content-Type", "text/html; charset=ISO-8859-1");
+		}
+	}
+
+	/* if the request asked for a close, we send a close, too */
+	if (evhttp_is_connection_close(req->flags, req->input_headers)) {
+		evhttp_remove_header(req->output_headers, "Connection");
+		if (!(req->flags & EVHTTP_PROXY_REQUEST))
+		    evhttp_add_header(req->output_headers, "Connection", "close");
+		evhttp_remove_header(req->output_headers, "Proxy-Connection");
+	}
+}
+
+void
+evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	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(evcon, req);
+	} else {
+		evhttp_make_header_response(evcon, req);
+	}
+
+	TAILQ_FOREACH(header, req->output_headers, next) {
+		evutil_snprintf(line, sizeof(line), "%s: %s\r\n",
+		    header->key, header->value);
+		evbuffer_add(evcon->output_buffer, line, strlen(line));
+	}
+	evbuffer_add(evcon->output_buffer, "\r\n", 2);
+
+	if (EVBUFFER_LENGTH(req->output_buffer) > 0) {
+		/*
+		 * For a request, we add the POST data, for a reply, this
+		 * is the regular data.
+		 */
+		evbuffer_add_buffer(evcon->output_buffer, req->output_buffer);
+	}
+}
+
+/* Separated host, port and file from URI */
+
+int
+evhttp_hostportfile(char *url, char **phost, u_short *pport, char **pfile)
+{
+	/* XXX not threadsafe. */
+	static char host[1024];
+	static char file[1024];
+	char *p;
+	const char *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 = "";
+		evutil_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);
+}
+
+static int
+evhttp_connection_incoming_fail(struct evhttp_request *req,
+    enum evhttp_connection_error error)
+{
+	switch (error) {
+	case EVCON_HTTP_TIMEOUT:
+	case EVCON_HTTP_EOF:
+		/* 
+		 * these are cases in which we probably should just
+		 * close the connection and not send a reply.  this
+		 * case may happen when a browser keeps a persistent
+		 * connection open and we timeout on the read.
+		 */
+		return (-1);
+	case EVCON_HTTP_INVALID_HEADER:
+	default:	/* xxx: probably should just error on default */
+		/* the callback looks at the uri to determine errors */
+		if (req->uri) {
+			free(req->uri);
+			req->uri = NULL;
+		}
+
+		/* 
+		 * the callback needs to send a reply, once the reply has
+		 * been send, the connection should get freed.
+		 */
+		(*req->cb)(req, req->cb_arg);
+	}
+	
+	return (0);
+}
+
+void
+evhttp_connection_fail(struct evhttp_connection *evcon,
+    enum evhttp_connection_error error)
+{
+	struct evhttp_request* req = TAILQ_FIRST(&evcon->requests);
+	void (*cb)(struct evhttp_request *, void *);
+	void *cb_arg;
+	assert(req != NULL);
+	
+	if (evcon->flags & EVHTTP_CON_INCOMING) {
+		/* 
+		 * for incoming requests, there are two different
+		 * failure cases.  it's either a network level error
+		 * or an http layer error. for problems on the network
+		 * layer like timeouts we just drop the connections.
+		 * For HTTP problems, we might have to send back a
+		 * reply before the connection can be freed.
+		 */
+		if (evhttp_connection_incoming_fail(req, error) == -1)
+			evhttp_connection_free(evcon);
+		return;
+	}
+
+	/* save the callback for later; the cb might free our object */
+	cb = req->cb;
+	cb_arg = req->cb_arg;
+
+	TAILQ_REMOVE(&evcon->requests, req, next);
+	evhttp_request_free(req);
+
+	/* xxx: maybe we should fail all requests??? */
+
+	/* reset the connection */
+	evhttp_connection_reset(evcon);
+	
+	/* We are trying the next request that was queued on us */
+	if (TAILQ_FIRST(&evcon->requests) != NULL)
+		evhttp_connection_connect(evcon);
+
+	/* inform the user */
+	if (cb != NULL)
+		(*cb)(NULL, cb_arg);
+}
+
+void
+evhttp_write(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	int n;
+
+	if (what == EV_TIMEOUT) {
+		evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+		return;
+	}
+
+	n = evbuffer_write(evcon->output_buffer, fd);
+	if (n == -1) {
+		event_debug(("%s: evbuffer_write", __func__));
+		evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		return;
+	}
+
+	if (n == 0) {
+		event_debug(("%s: write nothing", __func__));
+		evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		return;
+	}
+
+	if (EVBUFFER_LENGTH(evcon->output_buffer) != 0) {
+		evhttp_add_event(&evcon->ev, 
+		    evcon->timeout, HTTP_WRITE_TIMEOUT);
+		return;
+	}
+
+	/* Activate our call back */
+	if (evcon->cb != NULL)
+		(*evcon->cb)(evcon, evcon->cb_arg);
+}
+
+static void
+evhttp_connection_done(struct evhttp_connection *evcon)
+{
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
+
+	/*
+	 * if this is an incoming connection, we need to leave the request
+	 * on the connection, so that we can reply to it.
+	 */
+	if (con_outgoing) {
+	        int need_close;
+		TAILQ_REMOVE(&evcon->requests, req, next);
+		req->evcon = NULL;
+
+		need_close = 
+		    evhttp_is_connection_close(req->flags, req->input_headers) ||
+		    evhttp_is_connection_close(req->flags, req->output_headers);
+
+		/* check if we got asked to close the connection */
+		if (need_close)
+			evhttp_connection_reset(evcon);
+
+		if (TAILQ_FIRST(&evcon->requests) != NULL) {
+			/*
+			 * We have more requests; reset the connection
+			 * and deal with the next request.  xxx: no
+			 * persistent connection right now
+			 */
+			if (evcon->state != EVCON_CONNECTED)
+				evhttp_connection_connect(evcon);
+			else
+				evhttp_request_dispatch(evcon);
+		} else if (!need_close) {
+			/*
+			 * The connection is going to be persistent, but we
+			 * need to detect if the other side closes it.
+			 */
+			evhttp_connection_start_detectclose(evcon);
+		}
+	}
+
+	/* notify the user of the request */
+	(*req->cb)(req, req->cb_arg);
+
+	/* if this was an outgoing request, we own and it's done. so free it */
+	if (con_outgoing) {
+		evhttp_request_free(req);
+	}
+}
+
+/*
+ * Handles reading from a chunked request.
+ * return 1: all data has been read
+ * return 0: more data is expected
+ * return -1: data is corrupted
+ */
+
+static int
+evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
+{
+	int len;
+
+	while ((len = EVBUFFER_LENGTH(buf)) > 0) {
+		if (req->ntoread < 0) {
+			/* Read chunk size */
+			char *p = evbuffer_readline(buf);
+			char *endp;
+			int error;
+			if (p == NULL)
+				break;
+			/* the last chunk is on a new line? */
+			if (strlen(p) == 0) {
+				free(p);
+				continue;
+			}
+			req->ntoread = evutil_strtoll(p, &endp, 16);
+			error = *p == '\0' || (*endp != '\0' && *endp != ' ');
+			free(p);
+			if (error) {
+				/* could not get chunk size */
+				return (-1);
+			}
+			if (req->ntoread == 0) {
+				/* Last chunk */
+				return (1);
+			}
+			continue;
+		}
+
+		/* don't have enough to complete a chunk; wait for more */
+		if (len < req->ntoread)
+			return (0);
+
+		/* Completed chunk */
+		evbuffer_add(req->input_buffer,
+		    EVBUFFER_DATA(buf), req->ntoread);
+		evbuffer_drain(buf, req->ntoread);
+		req->ntoread = -1;
+		if (req->chunk_cb != NULL) {
+			(*req->chunk_cb)(req, req->cb_arg);
+			evbuffer_drain(req->input_buffer,
+			    EVBUFFER_LENGTH(req->input_buffer));
+		}
+	}
+
+	return (0);
+}
+
+static void
+evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	struct evbuffer *buf = evcon->input_buffer;
+	
+	if (req->chunked) {
+		int res = evhttp_handle_chunked_read(req, buf);
+		if (res == 1) {
+			/* finished last chunk */
+			evhttp_connection_done(evcon);
+			return;
+		} else if (res == -1) {
+			/* corrupted data */
+			evhttp_connection_fail(evcon,
+			    EVCON_HTTP_INVALID_HEADER);
+			return;
+		}
+	} else if (req->ntoread < 0) {
+		/* Read until connection close. */
+		evbuffer_add_buffer(req->input_buffer, buf);
+	} else if (EVBUFFER_LENGTH(buf) >= req->ntoread) {
+		/* Completed content length */
+		evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf),
+		    req->ntoread);
+		evbuffer_drain(buf, req->ntoread);
+		req->ntoread = 0;
+		evhttp_connection_done(evcon);
+		return;
+	}
+	/* Read more! */
+	event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
+}
+
+/*
+ * 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_connection *evcon = arg;
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	struct evbuffer *buf = evcon->input_buffer;
+	int n, len;
+
+	if (what == EV_TIMEOUT) {
+		evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+		return;
+	}
+	n = evbuffer_read(buf, fd, -1);
+	len = EVBUFFER_LENGTH(buf);
+	event_debug(("%s: got %d on %d\n", __func__, n, fd));
+	
+	if (n == -1) {
+		event_debug(("%s: evbuffer_read", __func__));
+		evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		return;
+	} else if (n == 0) {
+		/* Connection closed */
+		evhttp_connection_done(evcon);
+		return;
+	}
+	evhttp_read_body(evcon, req);
+}
+
+static void
+evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
+{
+	/* This is after writing the request to the server */
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	assert(req != NULL);
+
+	/* We are done writing our header and are now expecting the response */
+	req->kind = EVHTTP_RESPONSE;
+
+	evhttp_start_read(evcon);
+}
+
+/*
+ * Clean up a connection object
+ */
+
+void
+evhttp_connection_free(struct evhttp_connection *evcon)
+{
+	struct evhttp_request *req;
+
+	/* notify interested parties that this connection is going down */
+	if (evcon->fd != -1) {
+		if (evcon->state == EVCON_CONNECTED && evcon->closecb != NULL)
+			(*evcon->closecb)(evcon, evcon->closecb_arg);
+	}
+
+	/* remove all requests that might be queued on this connection */
+	while ((req = TAILQ_FIRST(&evcon->requests)) != NULL) {
+		TAILQ_REMOVE(&evcon->requests, req, next);
+		evhttp_request_free(req);
+	}
+
+	if (evcon->http_server != NULL) {
+		struct evhttp *http = evcon->http_server;
+		TAILQ_REMOVE(&http->connections, evcon, next);
+	}
+
+	if (event_initialized(&evcon->close_ev))
+		event_del(&evcon->close_ev);
+
+	if (event_initialized(&evcon->ev))
+		event_del(&evcon->ev);
+	
+	if (evcon->fd != -1)
+		EVUTIL_CLOSESOCKET(evcon->fd);
+
+	if (evcon->bind_address != NULL)
+		free(evcon->bind_address);
+
+	if (evcon->address != NULL)
+		free(evcon->address);
+
+	if (evcon->input_buffer != NULL)
+		evbuffer_free(evcon->input_buffer);
+
+	if (evcon->output_buffer != NULL)
+		evbuffer_free(evcon->output_buffer);
+
+	free(evcon);
+}
+
+void
+evhttp_connection_set_local_address(struct evhttp_connection *evcon,
+    const char *address)
+{
+	assert(evcon->state == EVCON_DISCONNECTED);
+	if (evcon->bind_address)
+		free(evcon->bind_address);
+	if ((evcon->bind_address = strdup(address)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+}
+
+
+static void
+evhttp_request_dispatch(struct evhttp_connection* evcon)
+{
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	
+	/* this should not usually happy but it's possible */
+	if (req == NULL)
+		return;
+
+	/* delete possible close detection events */
+	evhttp_connection_stop_detectclose(evcon);
+	
+	/* we assume that the connection is connected already */
+	assert(evcon->state == EVCON_CONNECTED);
+
+	/* Create the header from the store arguments */
+	evhttp_make_header(evcon, req);
+
+	evhttp_write_buffer(evcon, evhttp_write_connectioncb, NULL);
+}
+
+/* Reset our connection state */
+void
+evhttp_connection_reset(struct evhttp_connection *evcon)
+{
+	if (event_initialized(&evcon->ev))
+		event_del(&evcon->ev);
+
+	if (evcon->fd != -1) {
+		/* inform interested parties about connection close */
+		if (evcon->state == EVCON_CONNECTED && evcon->closecb != NULL)
+			(*evcon->closecb)(evcon, evcon->closecb_arg);
+
+		EVUTIL_CLOSESOCKET(evcon->fd);
+		evcon->fd = -1;
+	}
+	evcon->state = EVCON_DISCONNECTED;
+
+	/* remove unneeded flags */
+	evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
+}
+
+static void
+evhttp_detect_close_cb(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	evhttp_connection_reset(evcon);
+}
+
+static void
+evhttp_connection_start_detectclose(struct evhttp_connection *evcon)
+{
+	evcon->flags |= EVHTTP_CON_CLOSEDETECT;
+
+	if (event_initialized(&evcon->close_ev))
+		event_del(&evcon->close_ev);
+	event_set(&evcon->close_ev, evcon->fd, EV_READ,
+	    evhttp_detect_close_cb, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->close_ev);
+	event_add(&evcon->close_ev, NULL);
+}
+
+static void
+evhttp_connection_stop_detectclose(struct evhttp_connection *evcon)
+{
+	evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
+	event_del(&evcon->close_ev);
+}
+
+static void
+evhttp_connection_retry(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+
+	evcon->state = EVCON_DISCONNECTED;
+	evhttp_connection_connect(evcon);
+}
+
+/*
+ * Call back for asynchronous connection attempt.
+ */
+
+static 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_debug(("%s: connection timeout for \"%s:%d\" on %d",
+			__func__, evcon->address, evcon->port, evcon->fd));
+		goto cleanup;
+	}
+
+	/* Check if the connection completed */
+	if (getsockopt(evcon->fd, SOL_SOCKET, SO_ERROR, (void*)&error,
+		       &errsz) == -1) {
+		event_debug(("%s: getsockopt for \"%s:%d\" on %d",
+			__func__, evcon->address, evcon->port, evcon->fd));
+		goto cleanup;
+	}
+
+	if (error) {
+		event_debug(("%s: connect failed for \"%s:%d\" on %d: %s",
+		    __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));
+
+	/* Reset the retry count as we were successful in connecting */
+	evcon->retry_cnt = 0;
+	evcon->state = EVCON_CONNECTED;
+
+	/* try to start requests that have queued up on this connection */
+	evhttp_request_dispatch(evcon);
+	return;
+
+ cleanup:
+	if (evcon->retry_max < 0 || evcon->retry_cnt < evcon->retry_max) {
+		evtimer_set(&evcon->ev, evhttp_connection_retry, evcon);
+		EVHTTP_BASE_SET(evcon, &evcon->ev);
+		evhttp_add_event(&evcon->ev, MIN(3600, 2 << evcon->retry_cnt),
+		    HTTP_CONNECT_TIMEOUT);
+		evcon->retry_cnt++;
+		return;
+	}
+	evhttp_connection_reset(evcon);
+
+	/* for now, we just signal all requests by executing their callbacks */
+	while (TAILQ_FIRST(&evcon->requests) != NULL) {
+		struct evhttp_request *request = TAILQ_FIRST(&evcon->requests);
+		TAILQ_REMOVE(&evcon->requests, request, next);
+		request->evcon = NULL;
+
+		/* we might want to set an error here */
+		request->cb(request, request->cb_arg);
+		evhttp_request_free(request);
+	}
+}
+
+/*
+ * Check if we got a valid response code.
+ */
+
+static int
+evhttp_valid_response_code(int code)
+{
+	if (code == 0)
+		return (0);
+
+	return (1);
+}
+
+/* Parses the status line of a web server */
+
+static 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_debug(("%s: bad protocol \"%s\"",
+			__func__, protocol));
+		return (-1);
+	}
+
+	req->response_code = atoi(number);
+	if (!evhttp_valid_response_code(req->response_code)) {
+		event_debug(("%s: bad response code \"%s\"",
+			__func__, number));
+		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 */
+
+static 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_debug(("%s: bad method %s on request %p from %s",
+			__func__, method, req, req->remote_host));
+		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_debug(("%s: bad version %s on request %p from %s",
+			__func__, version, req, req->remote_host));
+		return (-1);
+	}
+
+	if ((req->uri = strdup(uri)) == NULL) {
+		event_debug(("%s: evhttp_decode_uri", __func__));
+		return (-1);
+	}
+
+	/* determine if it's a proxy request */
+	if (strlen(req->uri) > 0 && req->uri[0] != '/')
+		req->flags |= EVHTTP_PROXY_REQUEST;
+
+	return (0);
+}
+
+const char *
+evhttp_find_header(const 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 = NULL;
+
+	event_debug(("%s: key: %s val: %s\n", __func__, key, value));
+
+	if (strchr(value, '\r') != NULL || strchr(value, '\n') != NULL ||
+	    strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+		/* drop illegal headers */
+		event_debug(("%s: dropping illegal header\n", __func__));
+		return (-1);
+	}
+
+	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)
+{
+	char *line;
+	int done = 0;
+
+	struct evkeyvalq* headers = req->input_headers;
+	while ((line = evbuffer_readline(buffer)) != NULL) {
+		char *skey, *svalue;
+
+		if (*line == '\0') { /* Last header - Done */
+			done = 1;
+			free (line);
+			break;
+		}
+
+		/* Processing of header lines */
+		if (req->got_firstline == 0) {
+			switch (req->kind) {
+			case EVHTTP_REQUEST:
+				if (evhttp_parse_request_line(req, line) == -1)
+					goto error;
+				break;
+			case EVHTTP_RESPONSE:
+				if (evhttp_parse_response_line(req, line) == -1)
+					goto error;
+				break;
+			default:
+				goto error;
+			}
+			req->got_firstline = 1;
+		} else {
+			/* Regular header */
+			svalue = line;
+			skey = strsep(&svalue, ":");
+			if (svalue == NULL)
+				goto error;
+
+			svalue += strspn(svalue, " ");
+
+			if (evhttp_add_header(headers, skey, svalue) == -1)
+				goto error;
+		}
+
+		free (line);
+	}
+
+	return (done);
+
+ error:
+	free (line);
+	return (-1);
+}
+
+static int
+evhttp_get_body_length(struct evhttp_request *req)
+{
+	struct evkeyvalq *headers = req->input_headers;
+	const char *content_length;
+	const char *connection;
+
+	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.",
+		    __func__, connection);
+		return (-1);
+	} else if (content_length == NULL) {
+		req->ntoread = -1;
+	} else {
+		char *endp;
+		req->ntoread = evutil_strtoll(content_length, &endp, 10);
+		if (*content_length == '\0' || *endp != '\0') {
+			event_warnx("%s: illegal content length: %s",
+			    __func__, content_length);
+			return (-1);
+		}
+	}
+		
+	event_debug(("%s: bytes to read: %d (in buffer %d)\n",
+		__func__, req->ntoread,
+		EVBUFFER_LENGTH(req->evcon->input_buffer)));
+
+	return (0);
+}
+
+static void
+evhttp_get_body(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+	const char *xfer_enc;
+	
+	/* If this is a request without a body, then we are done */
+	if (req->kind == EVHTTP_REQUEST && req->type != EVHTTP_REQ_POST) {
+		evhttp_connection_done(evcon);
+		return;
+	}
+	xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
+	if (xfer_enc != NULL && strcasecmp(xfer_enc, "chunked") == 0) {
+		req->chunked = 1;
+		req->ntoread = -1;
+	} else {
+		if (evhttp_get_body_length(req) == -1) {
+			evhttp_connection_fail(evcon,
+			    EVCON_HTTP_INVALID_HEADER);
+			return;
+		}
+	}
+	evhttp_read_body(evcon, req);
+}
+
+void
+evhttp_read_header(int fd, short what, void *arg)
+{
+	struct evhttp_connection *evcon = arg;
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	int n, res;
+
+	if (what == EV_TIMEOUT) {
+		event_debug(("%s: timeout on %d\n", __func__, fd));
+		evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
+		return;
+	}
+
+	n = evbuffer_read(evcon->input_buffer, fd, -1);
+	if (n == 0) {
+		event_debug(("%s: no more data on %d", __func__, fd));
+		evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		return;
+	}
+	if (n == -1) {
+		event_debug(("%s: bad read on %d", __func__, fd));
+		evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+		return;
+	}
+
+	res = evhttp_parse_lines(req, evcon->input_buffer);
+	if (res == -1) {
+		/* Error while reading, terminate */
+		event_debug(("%s: bad header lines on %d\n", __func__, fd));
+		evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+		return;
+	} else if (res == 0) {
+		/* Need more header lines */
+		evhttp_add_event(&evcon->ev, 
+		    evcon->timeout, HTTP_READ_TIMEOUT);
+		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__, fd));
+		evhttp_get_body(evcon, req);
+		break;
+
+	case EVHTTP_RESPONSE:
+		if (req->response_code == HTTP_NOCONTENT ||
+		    req->response_code == HTTP_NOTMODIFIED ||
+		    (req->response_code >= 100 && req->response_code < 200)) {
+			event_debug(("%s: skipping body for code %d\n",
+					__func__, req->response_code));
+			evhttp_connection_done(evcon);
+		} else {
+			event_debug(("%s: start of read body for %s on %d\n",
+				__func__, req->remote_host, fd));
+			evhttp_get_body(evcon, req);
+		}
+		break;
+
+	default:
+		event_warnx("%s: bad header on %d", __func__, fd);
+		evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+		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_connection_new(const char *address, unsigned short port)
+{
+	struct evhttp_connection *evcon = NULL;
+	
+	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;
+
+	evcon->timeout = -1;
+	evcon->retry_cnt = evcon->retry_max = 0;
+
+	if ((evcon->address = strdup(address)) == NULL) {
+		event_warn("%s: strdup failed", __func__);
+		goto error;
+	}
+
+	if ((evcon->input_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new failed", __func__);
+		goto error;
+	}
+
+	if ((evcon->output_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new failed", __func__);
+		goto error;
+	}
+	
+	evcon->state = EVCON_DISCONNECTED;
+	TAILQ_INIT(&evcon->requests);
+
+	return (evcon);
+	
+ error:
+	if (evcon != NULL)
+		evhttp_connection_free(evcon);
+	return (NULL);
+}
+
+void evhttp_connection_set_base(struct evhttp_connection *evcon,
+    struct event_base *base)
+{
+	assert(evcon->base == NULL);
+	assert(evcon->state == EVCON_DISCONNECTED);
+	evcon->base = base;
+}
+
+void
+evhttp_connection_set_timeout(struct evhttp_connection *evcon,
+    int timeout_in_secs)
+{
+	evcon->timeout = timeout_in_secs;
+}
+
+void
+evhttp_connection_set_retries(struct evhttp_connection *evcon,
+    int retry_max)
+{
+	evcon->retry_max = retry_max;
+}
+
+void
+evhttp_connection_set_closecb(struct evhttp_connection *evcon,
+    void (*cb)(struct evhttp_connection *, void *), void *cbarg)
+{
+	evcon->closecb = cb;
+	evcon->closecb_arg = cbarg;
+}
+
+void
+evhttp_connection_get_peer(struct evhttp_connection *evcon,
+    char **address, u_short *port)
+{
+	*address = evcon->address;
+	*port = evcon->port;
+}
+
+int
+evhttp_connection_connect(struct evhttp_connection *evcon)
+{
+	if (evcon->state == EVCON_CONNECTING)
+		return (0);
+	
+	evhttp_connection_reset(evcon);
+
+	assert(!(evcon->flags & EVHTTP_CON_INCOMING));
+	evcon->flags |= EVHTTP_CON_OUTGOING;
+	
+	evcon->fd = bind_socket(evcon->bind_address, 0 /*port*/, 0 /*reuse*/);
+	if (evcon->fd == -1) {
+		event_debug(("%s: failed to bind to \"%s\"",
+			__func__, evcon->bind_address));
+		return (-1);
+	}
+
+	if (socket_connect(evcon->fd, evcon->address, evcon->port) == -1) {
+		EVUTIL_CLOSESOCKET(evcon->fd); evcon->fd = -1;
+		return (-1);
+	}
+
+	/* Set up a callback for successful connection setup */
+	event_set(&evcon->ev, evcon->fd, EV_WRITE, evhttp_connectioncb, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_CONNECT_TIMEOUT);
+
+	evcon->state = EVCON_CONNECTING;
+	
+	return (0);
+}
+
+/*
+ * Starts an HTTP request on the provided evhttp_connection object.
+ * If the connection object is not connected to the web server already,
+ * this will start the connection.
+ */
+
+int
+evhttp_make_request(struct evhttp_connection *evcon,
+    struct evhttp_request *req,
+    enum evhttp_cmd_type type, const char *uri)
+{
+	/* We are making a request */
+	req->kind = EVHTTP_REQUEST;
+	req->type = type;
+	if (req->uri != NULL)
+		free(req->uri);
+	if ((req->uri = strdup(uri)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+
+	/* Set the protocol version if it is not supplied */
+	if (!req->major && !req->minor) {
+		req->major = 1;
+		req->minor = 1;
+	}
+	
+	assert(req->evcon == NULL);
+	req->evcon = evcon;
+	assert(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
+	
+	TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+
+	/* If the connection object is not connected; make it so */
+	if (evcon->state != EVCON_CONNECTED)
+		return (evhttp_connection_connect(evcon));
+
+	/*
+	 * If it's connected already and we are the first in the queue,
+	 * then we can dispatch this request immediately.  Otherwise, it
+	 * will be dispatched once the pending requests are completed.
+	 */
+	if (TAILQ_FIRST(&evcon->requests) == req)
+		evhttp_request_dispatch(evcon);
+
+	return (0);
+}
+
+/*
+ * Reads data from file descriptor into request structure
+ * Request structure needs to be set up correctly.
+ */
+
+void
+evhttp_start_read(struct evhttp_connection *evcon)
+{
+	/* Set up an event to read the headers */
+	if (event_initialized(&evcon->ev))
+		event_del(&evcon->ev);
+	event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read_header, evcon);
+	EVHTTP_BASE_SET(evcon, &evcon->ev);
+	
+	evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_READ_TIMEOUT);
+}
+
+static void
+evhttp_send_done(struct evhttp_connection *evcon, void *arg)
+{
+	int need_close;
+	struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
+	TAILQ_REMOVE(&evcon->requests, req, next);
+
+	/* delete possible close detection events */
+	evhttp_connection_stop_detectclose(evcon);
+	
+	need_close =
+	    (req->minor == 0 &&
+		!evhttp_is_connection_keepalive(req->input_headers))||
+	    evhttp_is_connection_close(req->flags, req->input_headers) ||
+	    evhttp_is_connection_close(req->flags, req->output_headers);
+
+	assert(req->flags & EVHTTP_REQ_OWN_CONNECTION);
+	evhttp_request_free(req);
+
+	if (need_close) {
+		evhttp_connection_free(evcon);
+		return;
+	} 
+
+	/* we have a persistent connection; try to accept another request. */
+	if (evhttp_associate_new_request_with_connection(evcon) == -1)
+		evhttp_connection_free(evcon);
+}
+
+/*
+ * Returns an error page.
+ */
+
+void
+evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
+{
+#define ERR_FORMAT "<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();
+
+	/* close the connection on error */
+	evhttp_add_header(req->output_headers, "Connection", "close");
+
+	evhttp_response_code(req, error, reason);
+
+	evbuffer_add_printf(buf, ERR_FORMAT, error, reason);
+
+	evhttp_send_page(req, buf);
+
+	evbuffer_free(buf);
+#undef ERR_FORMAT
+}
+
+/* Requires that headers and response code are already set up */
+
+static inline void
+evhttp_send(struct evhttp_request *req, struct evbuffer *databuf)
+{
+	struct evhttp_connection *evcon = req->evcon;
+
+	assert(TAILQ_FIRST(&evcon->requests) == req);
+
+	/* xxx: not sure if we really should expose the data buffer this way */
+	if (databuf != NULL)
+		evbuffer_add_buffer(req->output_buffer, databuf);
+	
+	/* Adds headers to the response */
+	evhttp_make_header(evcon, req);
+
+	evhttp_write_buffer(evcon, evhttp_send_done, NULL);
+}
+
+void
+evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
+    struct evbuffer *databuf)
+{
+	/* set up to watch for client close */
+	evhttp_connection_start_detectclose(req->evcon);
+	evhttp_response_code(req, code, reason);
+	
+	evhttp_send(req, databuf);
+}
+
+void
+evhttp_send_reply_start(struct evhttp_request *req, int code,
+    const char *reason)
+{
+	/* set up to watch for client close */
+	evhttp_connection_start_detectclose(req->evcon);
+	evhttp_response_code(req, code, reason);
+	if (req->major == 1 && req->minor == 1) {
+		/* use chunked encoding for HTTP/1.1 */
+		evhttp_add_header(req->output_headers, "Transfer-Encoding",
+		    "chunked");
+		req->chunked = 1;
+	}
+	evhttp_make_header(req->evcon, req);
+	evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_chunk(struct evhttp_request *req, struct evbuffer *databuf)
+{
+	if (req->chunked) {
+		evbuffer_add_printf(req->evcon->output_buffer, "%x\r\n",
+				    (unsigned)EVBUFFER_LENGTH(databuf));
+	}
+	evbuffer_add_buffer(req->evcon->output_buffer, databuf);
+	if (req->chunked) {
+		evbuffer_add(req->evcon->output_buffer, "\r\n", 2);
+	}
+	evhttp_write_buffer(req->evcon, NULL, NULL);
+}
+
+void
+evhttp_send_reply_end(struct evhttp_request *req)
+{
+	struct evhttp_connection *evcon = req->evcon;
+
+	if (req->chunked) {
+		evbuffer_add(req->evcon->output_buffer, "0\r\n\r\n", 5);
+		evhttp_write_buffer(req->evcon, evhttp_send_done, NULL);
+		req->chunked = 0;
+	} else if (!event_pending(&evcon->ev, EV_WRITE|EV_TIMEOUT, NULL)) {
+		/* let the connection know that we are done with the request */
+		evhttp_send_done(evcon, NULL);
+	} else {
+		/* make the callback execute after all data has been written */
+		evcon->cb = evhttp_send_done;
+		evcon->cb_arg = NULL;
+	}
+}
+
+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->major || !req->minor) {
+		req->major = 1;
+		req->minor = 1;
+	}
+	
+	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);
+}
+
+static const char uri_chars[256] = {
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 1, 0, 0, 1, 0, 0, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 1, 0, 0,
+	/* 64 */
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 0, 1,
+	0, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1,   1, 1, 1, 0, 0, 0, 1, 0,
+	/* 128 */
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	/* 192 */
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,   0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+/*
+ * Helper functions to encode/decode a URI.
+ * The returned string must be freed by the caller.
+ */
+char *
+evhttp_encode_uri(const char *uri)
+{
+	struct evbuffer *buf = evbuffer_new();
+	char *p;
+
+	for (p = (char *)uri; *p != '\0'; p++) {
+		if (uri_chars[(u_char)(*p)]) {
+			evbuffer_add(buf, p, 1);
+		} else {
+			evbuffer_add_printf(buf, "%%%02X", (u_char)(*p));
+		}
+	}
+	evbuffer_add(buf, "", 1);
+	p = strdup((char *)EVBUFFER_DATA(buf));
+	evbuffer_free(buf);
+	
+	return (p);
+}
+
+char *
+evhttp_decode_uri(const char *uri)
+{
+	char c, *ret;
+	int i, j, in_query = 0;
+	
+	ret = malloc(strlen(uri) + 1);
+	if (ret == NULL)
+		event_err(1, "%s: malloc(%lu)", __func__,
+			  (unsigned long)(strlen(uri) + 1));
+	
+	for (i = j = 0; uri[i] != '\0'; i++) {
+		c = uri[i];
+		if (c == '?') {
+			in_query = 1;
+		} else if (c == '+' && in_query) {
+			c = ' ';
+		} else if (c == '%' && isxdigit((unsigned char)uri[i+1]) &&
+		    isxdigit((unsigned char)uri[i+2])) {
+			char tmp[] = { uri[i+1], uri[i+2], '\0' };
+			c = (char)strtol(tmp, NULL, 16);
+			i += 2;
+		}
+		ret[j++] = c;
+	}
+	ret[j] = '\0';
+	
+	return (ret);
+}
+
+/* 
+ * Helper function to parse out arguments in a query.
+ * The arguments are separated by key and value.
+ * URI should already be decoded.
+ */
+
+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;
+
+		value = evhttp_decode_uri(value);
+		event_debug(("Query Param: %s -> %s\n", key, value));
+		evhttp_add_header(headers, key, value);
+		free(value);
+	}
+
+ error:
+	free(line);
+}
+
+static struct evhttp_cb *
+evhttp_dispatch_callback(struct httpcbq *callbacks, struct evhttp_request *req)
+{
+	struct evhttp_cb *cb;
+	size_t offset = 0;
+
+	/* Test for different URLs */
+	char *p = strchr(req->uri, '?');
+	if (p != NULL)
+		offset = (size_t)(p - req->uri);
+
+	TAILQ_FOREACH(cb, callbacks, next) {
+		int res = 0;
+		if (p == NULL) {
+			res = strcmp(cb->what, req->uri) == 0;
+		} else {
+			res = ((strncmp(cb->what, req->uri, offset) == 0) &&
+					(cb->what[offset] == '\0'));
+		}
+
+		if (res)
+			return (cb);
+	}
+
+	return (NULL);
+}
+
+static void
+evhttp_handle_request(struct evhttp_request *req, void *arg)
+{
+	struct evhttp *http = arg;
+	struct evhttp_cb *cb = NULL;
+
+	if (req->uri == NULL) {
+		evhttp_send_error(req, HTTP_BADREQUEST, "Bad Request");
+		return;
+	}
+
+	if ((cb = evhttp_dispatch_callback(&http->callbacks, req)) != NULL) {
+		(*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 */
+#define ERR_FORMAT "<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, ERR_FORMAT, escaped_html);
+
+		free(escaped_html);
+
+		evhttp_send_page(req, buf);
+
+		evbuffer_free(buf);
+#undef ERR_FORMAT
+	}
+}
+
+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;
+	}
+	if (evutil_make_socket_nonblocking(nfd) < 0)
+		return;
+
+	evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
+}
+
+int
+evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
+{
+	int fd;
+	int res;
+
+	if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
+		return (-1);
+
+	if (listen(fd, 128) == -1) {
+		event_warn("%s: listen", __func__);
+		EVUTIL_CLOSESOCKET(fd);
+		return (-1);
+	}
+
+	res = evhttp_accept_socket(http, fd);
+	
+	if (res != -1)
+		event_debug(("Bound to port %d - Awaiting connections ... ",
+			port));
+
+	return (res);
+}
+
+int
+evhttp_accept_socket(struct evhttp *http, int fd)
+{
+	struct evhttp_bound_socket *bound;
+	struct event *ev;
+	int res;
+
+	bound = malloc(sizeof(struct evhttp_bound_socket));
+	if (bound == NULL)
+		return (-1);
+
+	ev = &bound->bind_ev;
+
+	/* Schedule the socket for accepting */
+	event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
+	EVHTTP_BASE_SET(http, ev);
+
+	res = event_add(ev, NULL);
+
+	if (res == -1) {
+		free(bound);
+		return (-1);
+	}
+
+	TAILQ_INSERT_TAIL(&http->sockets, bound, next);
+
+	return (0);
+}
+
+static struct evhttp*
+evhttp_new_object(void)
+{
+	struct evhttp *http = NULL;
+
+	if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
+		event_warn("%s: calloc", __func__);
+		return (NULL);
+	}
+
+	http->timeout = -1;
+
+	TAILQ_INIT(&http->sockets);
+	TAILQ_INIT(&http->callbacks);
+	TAILQ_INIT(&http->connections);
+
+	return (http);
+}
+
+struct evhttp *
+evhttp_new(struct event_base *base)
+{
+	struct evhttp *http = evhttp_new_object();
+
+	http->base = base;
+
+	return (http);
+}
+
+/*
+ * Start a web server on the specified address and port.
+ */
+
+struct evhttp *
+evhttp_start(const char *address, u_short port)
+{
+	struct evhttp *http = evhttp_new_object();
+
+	if (evhttp_bind_socket(http, address, port) == -1) {
+		free(http);
+		return (NULL);
+	}
+
+	return (http);
+}
+
+void
+evhttp_free(struct evhttp* http)
+{
+	struct evhttp_cb *http_cb;
+	struct evhttp_connection *evcon;
+	struct evhttp_bound_socket *bound;
+	int fd;
+
+	/* Remove the accepting part */
+	while ((bound = TAILQ_FIRST(&http->sockets)) != NULL) {
+		TAILQ_REMOVE(&http->sockets, bound, next);
+
+		fd = bound->bind_ev.ev_fd;
+		event_del(&bound->bind_ev);
+		EVUTIL_CLOSESOCKET(fd);
+
+		free(bound);
+	}
+
+	while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
+		/* evhttp_connection_free removes the connection */
+		evhttp_connection_free(evcon);
+	}
+
+	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_timeout(struct evhttp* http, int timeout_in_secs)
+{
+	http->timeout = timeout_in_secs;
+}
+
+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);
+}
+
+int
+evhttp_del_cb(struct evhttp *http, const char *uri)
+{
+	struct evhttp_cb *http_cb;
+
+	TAILQ_FOREACH(http_cb, &http->callbacks, next) {
+		if (strcmp(http_cb->what, uri) == 0)
+			break;
+	}
+	if (http_cb == NULL)
+		return (-1);
+
+	TAILQ_REMOVE(&http->callbacks, http_cb, next);
+	free(http_cb->what);
+	free(http_cb);
+
+	return (0);
+}
+
+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->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);
+
+	if ((req->input_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new", __func__);
+		goto error;
+	}
+
+	if ((req->output_buffer = evbuffer_new()) == NULL) {
+		event_warn("%s: evbuffer_new", __func__);
+		goto error;
+	}
+
+	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->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);
+
+	evhttp_clear_headers(req->input_headers);
+	free(req->input_headers);
+
+	evhttp_clear_headers(req->output_headers);
+	free(req->output_headers);
+
+	if (req->input_buffer != NULL)
+		evbuffer_free(req->input_buffer);
+
+	if (req->output_buffer != NULL)
+		evbuffer_free(req->output_buffer);
+
+	free(req);
+}
+
+void
+evhttp_request_set_chunked_cb(struct evhttp_request *req,
+    void (*cb)(struct evhttp_request *, void *))
+{
+	req->chunk_cb = cb;
+}
+
+/*
+ * 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.
+ */
+
+static struct evhttp_connection*
+evhttp_get_request_connection(
+	struct evhttp* http,
+	int fd, struct sockaddr *sa, socklen_t salen)
+{
+	struct evhttp_connection *evcon;
+	char *hostname = NULL, *portname = NULL;
+
+	name_from_addr(sa, salen, &hostname, &portname);
+	event_debug(("%s: new request from %s:%s on %d\n",
+			__func__, hostname, portname, fd));
+
+	/* we need a connection object to put the http request on */
+	if ((evcon = evhttp_connection_new(hostname, atoi(portname))) == NULL)
+		return (NULL);
+
+	/* associate the base if we have one*/
+	evhttp_connection_set_base(evcon, http->base);
+
+	evcon->flags |= EVHTTP_CON_INCOMING;
+	evcon->state = EVCON_CONNECTED;
+	
+	evcon->fd = fd;
+
+	return (evcon);
+}
+
+static int
+evhttp_associate_new_request_with_connection(struct evhttp_connection *evcon)
+{
+	struct evhttp *http = evcon->http_server;
+	struct evhttp_request *req;
+	if ((req = evhttp_request_new(evhttp_handle_request, http)) == NULL)
+		return (-1);
+
+	req->evcon = evcon;	/* the request ends up owning the connection */
+	req->flags |= EVHTTP_REQ_OWN_CONNECTION;
+	
+	TAILQ_INSERT_TAIL(&evcon->requests, req, next);
+	
+	req->kind = EVHTTP_REQUEST;
+	
+	if ((req->remote_host = strdup(evcon->address)) == NULL)
+		event_err(1, "%s: strdup", __func__);
+	req->remote_port = evcon->port;
+
+	evhttp_start_read(evcon);
+	
+	return (0);
+}
+
+void
+evhttp_get_request(struct evhttp *http, int fd,
+    struct sockaddr *sa, socklen_t salen)
+{
+	struct evhttp_connection *evcon;
+
+	evcon = evhttp_get_request_connection(http, fd, sa, salen);
+	if (evcon == NULL)
+		return;
+
+	/* the timeout can be used by the server to close idle connections */
+	if (http->timeout != -1)
+		evhttp_connection_set_timeout(evcon, http->timeout);
+
+	/* 
+	 * if we want to accept more than one request on a connection,
+	 * we need to know which http server it belongs to.
+	 */
+	evcon->http_server = http;
+	TAILQ_INSERT_TAIL(&http->connections, evcon, next);
+	
+	if (evhttp_associate_new_request_with_connection(evcon) == -1)
+		evhttp_connection_free(evcon);
+}
+
+
+/*
+ * Network helper functions that we do not want to export to the rest of
+ * the world.
+ */
+#if 0 /* Unused */
+static struct addrinfo *
+addr_from_name(char *address)
+{
+#ifdef HAVE_GETADDRINFO
+        struct addrinfo ai, *aitop;
+        int ai_result;
+
+        memset(&ai, 0, sizeof(ai));
+        ai.ai_family = AF_INET;
+        ai.ai_socktype = SOCK_RAW;
+        ai.ai_flags = 0;
+        if ((ai_result = getaddrinfo(address, NULL, &ai, &aitop)) != 0) {
+                if ( ai_result == EAI_SYSTEM )
+                        event_warn("getaddrinfo");
+                else
+                        event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
+        }
+
+	return (aitop);
+#else
+	assert(0);
+	return NULL; /* XXXXX Use gethostbyname, if this function is ever used. */
+#endif
+}
+#endif
+
+static void
+name_from_addr(struct sockaddr *sa, socklen_t salen,
+    char **phost, char **pport)
+{
+	char ntop[NI_MAXHOST];
+	char strport[NI_MAXSERV];
+	int ni_result;
+
+#ifdef HAVE_GETNAMEINFO
+	ni_result = getnameinfo(sa, salen,
+		ntop, sizeof(ntop), strport, sizeof(strport),
+		NI_NUMERICHOST|NI_NUMERICSERV);
+	
+	if (ni_result != 0) {
+		if (ni_result == EAI_SYSTEM)
+			event_err(1, "getnameinfo failed");
+		else
+			event_errx(1, "getnameinfo failed: %s", gai_strerror(ni_result));
+		return;
+	}
+#else
+	ni_result = fake_getnameinfo(sa, salen,
+		ntop, sizeof(ntop), strport, sizeof(strport),
+		NI_NUMERICHOST|NI_NUMERICSERV);
+	if (ni_result != 0)
+			return;
+#endif
+	*phost = ntop;
+	*pport = strport;
+}
+
+/* Either connect or bind */
+
+static int
+bind_socket_ai(struct addrinfo *ai, int reuse)
+{
+        int fd, on = 1, r;
+	int serrno;
+
+        /* Create listen socket */
+        fd = socket(AF_INET, SOCK_STREAM, 0);
+        if (fd == -1) {
+                event_warn("socket");
+                return (-1);
+        }
+
+        if (evutil_make_socket_nonblocking(fd) < 0)
+                goto out;
+
+#ifndef WIN32
+        if (fcntl(fd, F_SETFD, 1) == -1) {
+                event_warn("fcntl(F_SETFD)");
+                goto out;
+        }
+#endif
+
+        setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
+	if (reuse) {
+		setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+		    (void *)&on, sizeof(on));
+	}
+
+	r = bind(fd, ai->ai_addr, ai->ai_addrlen);
+	if (r == -1)
+		goto out;
+
+	return (fd);
+
+ out:
+	serrno = EVUTIL_SOCKET_ERROR();
+	EVUTIL_CLOSESOCKET(fd);
+	EVUTIL_SET_SOCKET_ERROR(serrno);
+	return (-1);
+}
+
+static struct addrinfo *
+make_addrinfo(const char *address, u_short port)
+{
+        struct addrinfo *aitop = NULL;
+
+#ifdef HAVE_GETADDRINFO
+        struct addrinfo ai;
+        char strport[NI_MAXSERV];
+        int ai_result;
+
+        memset(&ai, 0, sizeof(ai));
+        ai.ai_family = AF_INET;
+        ai.ai_socktype = SOCK_STREAM;
+        ai.ai_flags = AI_PASSIVE;  /* turn NULL host name into INADDR_ANY */
+        evutil_snprintf(strport, sizeof(strport), "%d", port);
+        if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
+                if ( ai_result == EAI_SYSTEM )
+                        event_warn("getaddrinfo");
+                else
+                        event_warnx("getaddrinfo: %s", gai_strerror(ai_result));
+		return (NULL);
+        }
+#else
+	static int cur;
+	static struct addrinfo ai[2]; /* We will be returning the address of some of this memory so it has to last even after this call. */
+	if (++cur == 2) cur = 0;   /* allow calling this function twice */
+
+	if (fake_getaddrinfo(address, &ai[cur]) < 0) {
+		event_warn("fake_getaddrinfo");
+		return (NULL);
+	}
+	aitop = &ai[cur];
+	((struct sockaddr_in *) aitop->ai_addr)->sin_port = htons(port);
+#endif
+
+	return (aitop);
+}
+
+static int
+bind_socket(const char *address, u_short port, int reuse)
+{
+	int fd;
+	struct addrinfo *aitop = make_addrinfo(address, port);
+
+	if (aitop == NULL)
+		return (-1);
+
+	fd = bind_socket_ai(aitop, reuse);
+
+#ifdef HAVE_GETADDRINFO
+	freeaddrinfo(aitop);
+#else
+	fake_freeaddrinfo(aitop);
+#endif
+
+	return (fd);
+}
+
+static int
+socket_connect(int fd, const char *address, unsigned short port)
+{
+	struct addrinfo *ai = make_addrinfo(address, port);
+	int res = -1;
+
+	if (ai == NULL) {
+		event_debug(("%s: make_addrinfo: \"%s:%d\"",
+			__func__, address, port));
+		return (-1);
+	}
+
+	if (connect(fd, ai->ai_addr, ai->ai_addrlen) == -1) {
+#ifdef WIN32
+		int tmp_error = WSAGetLastError();
+		if (tmp_error != WSAEWOULDBLOCK && tmp_error != WSAEINVAL &&
+		    tmp_error != WSAEINPROGRESS) {
+			goto out;
+		}
+#else
+		if (errno != EINPROGRESS) {
+			goto out;
+		}
+#endif
+	}
+
+	/* everything is fine */
+	res = 0;
+
+out:
+#ifdef HAVE_GETADDRINFO
+	freeaddrinfo(ai);
+#else
+	fake_freeaddrinfo(ai);
+#endif
+
+	return (res);
+}
Index: contrib/libevent/kqueue.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/kqueue.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 kqueue.c
--- contrib/libevent/kqueue.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/kqueue.c	29 Mar 2008 01:46:14 -0000
@@ -49,16 +49,18 @@
 #endif
 
 /* Some platforms apparently define the udata field of struct kevent as
- * ntptr_t, whereas others define it as void*.  There doesn't seem to be an
+ * intptr_t, whereas others define it as void*.  There doesn't seem to be an
  * easy way to tell them apart via autoconf, so we need to use OS macros. */
 #if defined(HAVE_INTTYPES_H) && !defined(__OpenBSD__) && !defined(__FreeBSD__) && !defined(__darwin__) && !defined(__APPLE__)
-#define PTR_TO_UDATA(x) ((intptr_t)(x))
+#define PTR_TO_UDATA(x)	((intptr_t)(x))
 #else
-#define PTR_TO_UDATA(x) (x)
+#define PTR_TO_UDATA(x)	(x)
 #endif
 
 #include "event.h"
+#include "event-internal.h"
 #include "log.h"
+#include "event-internal.h"
 
 #define EVLIST_X_KQINKERNEL	0x1000
 
@@ -70,27 +72,27 @@
 	struct kevent *events;
 	int nevents;
 	int kq;
+	pid_t pid;
 };
 
-void *kq_init	(struct event_base *);
-int kq_add	(void *, struct event *);
-int kq_del	(void *, struct event *);
-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 (struct event_base *, void *);
+static void *kq_init	(struct event_base *);
+static int kq_add	(void *, struct event *);
+static int kq_del	(void *, struct event *);
+static int kq_dispatch	(struct event_base *, void *, struct timeval *);
+static int kq_insert	(struct kqop *, struct kevent *);
+static void kq_dealloc (struct event_base *, void *);
 
 const struct eventop kqops = {
 	"kqueue",
 	kq_init,
 	kq_add,
 	kq_del,
-	kq_recalc,
 	kq_dispatch,
-	kq_dealloc
+	kq_dealloc,
+	1 /* need reinit */
 };
 
-void *
+static void *
 kq_init(struct event_base *base)
 {
 	int kq;
@@ -113,6 +115,8 @@
 
 	kqueueop->kq = kq;
 
+	kqueueop->pid = getpid();
+
 	/* Initalize fields */
 	kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
 	if (kqueueop->changes == NULL) {
@@ -151,13 +155,7 @@
 	return (kqueueop);
 }
 
-int
-kq_recalc(struct event_base *base, void *arg, int max)
-{
-	return (0);
-}
-
-int
+static int
 kq_insert(struct kqop *kqop, struct kevent *kev)
 {
 	int nevents = kqop->nevents;
@@ -208,7 +206,7 @@
 	/* Do nothing here */
 }
 
-int
+static int
 kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
 	struct kqop *kqop = arg;
@@ -275,7 +273,7 @@
 			continue;
 
 		if (!(ev->ev_events & EV_PERSIST))
-			event_del(ev);
+			ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
 
 		event_active(ev, which,
 		    ev->ev_events & EV_SIGNAL ? events[i].data : 1);
@@ -285,7 +283,7 @@
 }
 
 
-int
+static int
 kq_add(void *arg, struct event *ev)
 {
 	struct kqop *kqop = arg;
@@ -293,6 +291,7 @@
 
 	if (ev->ev_events & EV_SIGNAL) {
 		int nsignal = EVENT_SIGNAL(ev);
+                struct timespec timeout = { 0, 0 };
 
  		memset(&kev, 0, sizeof(kev));
 		kev.ident = nsignal;
@@ -301,11 +300,14 @@
 		if (!(ev->ev_events & EV_PERSIST))
 			kev.flags |= EV_ONESHOT;
 		kev.udata = PTR_TO_UDATA(ev);
-		
-		if (kq_insert(kqop, &kev) == -1)
-			return (-1);
 
-		if (signal(nsignal, kq_sighandler) == SIG_ERR)
+		/* Be ready for the signal if it is sent any time between
+		 * now and the next call to kq_dispatch. */
+                if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+                	return (-1);
+
+		if (_evsignal_set_handler(ev->ev_base, nsignal,
+					  kq_sighandler) == -1)
 			return (-1);
 
 		ev->ev_flags |= EVLIST_X_KQINKERNEL;
@@ -349,7 +351,7 @@
 	return (0);
 }
 
-int
+static int
 kq_del(void *arg, struct event *ev)
 {
 	struct kqop *kqop = arg;
@@ -369,7 +371,7 @@
 		if (kq_insert(kqop, &kev) == -1)
 			return (-1);
 
-		if (signal(nsignal, SIG_DFL) == SIG_ERR)
+		if (_evsignal_restore_handler(ev->ev_base, nsignal) == -1)
 			return (-1);
 
 		ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
@@ -403,7 +405,7 @@
 	return (0);
 }
 
-void
+static void
 kq_dealloc(struct event_base *base, void *arg)
 {
 	struct kqop *kqop = arg;
@@ -412,7 +414,7 @@
 		free(kqop->changes);
 	if (kqop->events)
 		free(kqop->events);
-	if (kqop->kq)
+	if (kqop->kq >= 0 && kqop->pid == getpid())
 		close(kqop->kq);
 	memset(kqop, 0, sizeof(struct kqop));
 	free(kqop);
Index: contrib/libevent/log.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/log.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 log.c
--- contrib/libevent/log.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/log.c	25 Jun 2008 15:45:15 -0000
@@ -45,10 +45,8 @@
 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #undef WIN32_LEAN_AND_MEAN
-#include "misc.h"
 #endif
 #include <sys/types.h>
-#include <sys/tree.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #else
@@ -62,42 +60,12 @@
 #include "event.h"
 
 #include "log.h"
+#include "evutil.h"
 
 static void _warn_helper(int severity, int log_errno, const char *fmt,
                          va_list ap);
 static void event_log(int severity, const char *msg);
 
-static int
-event_vsnprintf(char *str, size_t size, const char *format, va_list args)
-{
-	int r;
-	if (size == 0)
-		return -1;
-#ifdef WIN32
-	r = _vsnprintf(str, size, format, args);
-#else
-	r = vsnprintf(str, size, format, args);
-#endif
-	str[size-1] = '\0';
-	if (r < 0 || ((size_t)r) >= size) {
-		/* different platforms behave differently on overflow;
-		 * handle both kinds. */
-		return -1;
-	}
-	return r;
-}
-
-static int
-event_snprintf(char *str, size_t size, const char *format, ...)
-{
-    va_list ap;
-    int r;
-    va_start(ap, format);
-    r = event_vsnprintf(str, size, format, ap);
-    va_end(ap);
-    return r;
-}
-
 void
 event_err(int eval, const char *fmt, ...)
 {
@@ -167,14 +135,14 @@
 	size_t len;
 
 	if (fmt != NULL)
-		event_vsnprintf(buf, sizeof(buf), fmt, ap);
+		evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
 	else
 		buf[0] = '\0';
 
 	if (log_errno >= 0) {
 		len = strlen(buf);
 		if (len < sizeof(buf) - 3) {
-			event_snprintf(buf + len, sizeof(buf) - len, ": %s",
+			evutil_snprintf(buf + len, sizeof(buf) - len, ": %s",
 			    strerror(log_errno));
 		}
 	}
Index: contrib/libevent/log.h
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/log.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 log.h
--- contrib/libevent/log.h	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/log.h	19 Dec 2007 04:50:46 -0000
@@ -27,12 +27,18 @@
 #ifndef _LOG_H_
 #define _LOG_H_
 
-void event_err(int eval, const char *fmt, ...);
-void event_warn(const char *fmt, ...);
-void event_errx(int eval, const char *fmt, ...);
-void event_warnx(const char *fmt, ...);
-void event_msgx(const char *fmt, ...);
-void _event_debugx(const char *fmt, ...);
+#ifdef __GNUC__
+#define EV_CHECK_FMT(a,b) __attribute__((format(printf, a, b)))
+#else
+#define EV_CHECK_FMT(a,b)
+#endif
+
+void event_err(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warn(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_errx(int eval, const char *fmt, ...) EV_CHECK_FMT(2,3);
+void event_warnx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void event_msgx(const char *fmt, ...) EV_CHECK_FMT(1,2);
+void _event_debugx(const char *fmt, ...) EV_CHECK_FMT(1,2);
 
 #ifdef USE_DEBUG
 #define event_debug(x) _event_debugx x
@@ -40,4 +46,6 @@
 #define event_debug(x) do {;} while (0)
 #endif
 
+#undef EV_CHECK_FMT
+
 #endif
Index: contrib/libevent/min_heap.h
===================================================================
RCS file: contrib/libevent/min_heap.h
diff -N contrib/libevent/min_heap.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/min_heap.h	12 Jun 2008 14:43:53 -0000
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@gmail.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.
+ */
+#ifndef _MIN_HEAP_H_
+#define _MIN_HEAP_H_
+
+#include "event.h"
+#include "evutil.h"
+
+typedef struct min_heap
+{
+    struct event** p;
+    unsigned n, a;
+} min_heap_t;
+
+static inline void           min_heap_ctor(min_heap_t* s);
+static inline void           min_heap_dtor(min_heap_t* s);
+static inline void           min_heap_elem_init(struct event* e);
+static inline int            min_heap_elem_greater(struct event *a, struct event *b);
+static inline int            min_heap_empty(min_heap_t* s);
+static inline unsigned       min_heap_size(min_heap_t* s);
+static inline struct event*  min_heap_top(min_heap_t* s);
+static inline int            min_heap_reserve(min_heap_t* s, unsigned n);
+static inline int            min_heap_push(min_heap_t* s, struct event* e);
+static inline struct event*  min_heap_pop(min_heap_t* s);
+static inline int            min_heap_erase(min_heap_t* s, struct event* e);
+static inline void           min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e);
+static inline void           min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e);
+
+int min_heap_elem_greater(struct event *a, struct event *b)
+{
+    return evutil_timercmp(&a->ev_timeout, &b->ev_timeout, >);
+}
+
+void min_heap_ctor(min_heap_t* s) { s->p = 0; s->n = 0; s->a = 0; }
+void min_heap_dtor(min_heap_t* s) { free(s->p); }
+void min_heap_elem_init(struct event* e) { e->min_heap_idx = -1; }
+int min_heap_empty(min_heap_t* s) { return 0u == s->n; }
+unsigned min_heap_size(min_heap_t* s) { return s->n; }
+struct event* min_heap_top(min_heap_t* s) { return s->n ? *s->p : 0; }
+
+int min_heap_push(min_heap_t* s, struct event* e)
+{
+    if(min_heap_reserve(s, s->n + 1))
+        return -1;
+    min_heap_shift_up_(s, s->n++, e);
+    return 0;
+}
+
+struct event* min_heap_pop(min_heap_t* s)
+{
+    if(s->n)
+    {
+        struct event* e = *s->p;
+        min_heap_shift_down_(s, 0u, s->p[--s->n]);
+        e->min_heap_idx = -1;
+        return e;
+    }
+    return 0;
+}
+
+int min_heap_erase(min_heap_t* s, struct event* e)
+{
+    if(((unsigned int)-1) != e->min_heap_idx)
+    {
+        min_heap_shift_down_(s, e->min_heap_idx, s->p[--s->n]);
+        e->min_heap_idx = -1;
+        return 0;
+    }
+    return -1;
+}
+
+int min_heap_reserve(min_heap_t* s, unsigned n)
+{
+    if(s->a < n)
+    {
+        struct event** p;
+        unsigned a = s->a ? s->a * 2 : 8;
+        if(a < n)
+            a = n;
+        if(!(p = (struct event**)realloc(s->p, a * sizeof *p)))
+            return -1;
+        s->p = p;
+        s->a = a;
+    }
+    return 0;
+}
+
+void min_heap_shift_up_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+    unsigned parent = (hole_index - 1) / 2;
+    while(hole_index && min_heap_elem_greater(s->p[parent], e))
+    {
+        (s->p[hole_index] = s->p[parent])->min_heap_idx = hole_index;
+        hole_index = parent;
+        parent = (hole_index - 1) / 2;
+    }
+    (s->p[hole_index] = e)->min_heap_idx = hole_index;
+}
+
+void min_heap_shift_down_(min_heap_t* s, unsigned hole_index, struct event* e)
+{
+    unsigned min_child = 2 * (hole_index + 1);
+    while(min_child <= s->n)
+	{
+        min_child -= min_child == s->n || min_heap_elem_greater(s->p[min_child], s->p[min_child - 1]);
+        if(!(min_heap_elem_greater(e, s->p[min_child])))
+            break;
+        (s->p[hole_index] = s->p[min_child])->min_heap_idx = hole_index;
+        hole_index = min_child;
+        min_child = 2 * (hole_index + 1);
+	}
+    min_heap_shift_up_(s, hole_index,  e);
+}
+
+#endif /* _MIN_HEAP_H_ */
Index: contrib/libevent/poll.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/poll.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 poll.c
--- contrib/libevent/poll.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/poll.c	29 Mar 2008 01:46:14 -0000
@@ -37,7 +37,6 @@
 #include <sys/_time.h>
 #endif
 #include <sys/queue.h>
-#include <sys/tree.h>
 #include <poll.h>
 #include <signal.h>
 #include <stdio.h>
@@ -66,24 +65,23 @@
 			      * "no entry." */
 };
 
-void *poll_init	(struct event_base *);
-int poll_add		(void *, struct event *);
-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	(struct event_base *, void *);
+static void *poll_init	(struct event_base *);
+static int poll_add		(void *, struct event *);
+static int poll_del		(void *, struct event *);
+static int poll_dispatch	(struct event_base *, void *, struct timeval *);
+static void poll_dealloc	(struct event_base *, void *);
 
 const struct eventop pollops = {
 	"poll",
 	poll_init,
 	poll_add,
 	poll_del,
-	poll_recalc,
 	poll_dispatch,
-	poll_dealloc
+	poll_dealloc,
+    0
 };
 
-void *
+static void *
 poll_init(struct event_base *base)
 {
 	struct pollop *pollop;
@@ -100,17 +98,6 @@
 	return (pollop);
 }
 
-/*
- * Called with the highest fd that we know about.  If it is 0, completely
- * recalculate everything.
- */
-
-int
-poll_recalc(struct event_base *base, void *arg, int max)
-{
-	return (0);
-}
-
 #ifdef CHECK_INVARIANTS
 static void
 poll_check_ok(struct pollop *pop)
@@ -145,7 +132,7 @@
 #define poll_check_ok(pop)
 #endif
 
-int
+static int
 poll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
 	int res, i, msec = -1, nfds;
@@ -199,13 +186,9 @@
 			continue;
 
 		if (r_ev && (res & r_ev->ev_events)) {
-			if (!(r_ev->ev_events & EV_PERSIST))
-				event_del(r_ev);
 			event_active(r_ev, res & r_ev->ev_events, 1);
 		}
 		if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
-			if (!(w_ev->ev_events & EV_PERSIST))
-				event_del(w_ev);
 			event_active(w_ev, res & w_ev->ev_events, 1);
 		}
 	}
@@ -213,7 +196,7 @@
 	return (0);
 }
 
-int
+static int
 poll_add(void *arg, struct event *ev)
 {
 	struct pollop *pop = arg;
@@ -318,7 +301,7 @@
  * Nothing to be done here.
  */
 
-int
+static int
 poll_del(void *arg, struct event *ev)
 {
 	struct pollop *pop = arg;
@@ -371,7 +354,7 @@
 	return (0);
 }
 
-void
+static void
 poll_dealloc(struct event_base *base, void *arg)
 {
 	struct pollop *pop = arg;
Index: contrib/libevent/select.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/select.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 select.c
--- contrib/libevent/select.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/select.c	29 Mar 2008 01:46:15 -0000
@@ -40,7 +40,6 @@
 #include <sys/select.h>
 #endif
 #include <sys/queue.h>
-#include <sys/tree.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -71,26 +70,25 @@
 	struct event **event_w_by_fd;
 };
 
-void *select_init	(struct event_base *);
-int select_add		(void *, struct event *);
-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     (struct event_base *, void *);
+static void *select_init	(struct event_base *);
+static int select_add		(void *, struct event *);
+static int select_del		(void *, struct event *);
+static int select_dispatch	(struct event_base *, void *, struct timeval *);
+static void select_dealloc     (struct event_base *, void *);
 
 const struct eventop selectops = {
 	"select",
 	select_init,
 	select_add,
 	select_del,
-	select_recalc,
 	select_dispatch,
-	select_dealloc
+	select_dealloc,
+	0
 };
 
 static int select_resize(struct selectop *sop, int fdsz);
 
-void *
+static void *
 select_init(struct event_base *base)
 {
 	struct selectop *sop;
@@ -136,22 +134,7 @@
 #define check_selectop(sop) do { (void) sop; } while (0)
 #endif
 
-/*
- * Called with the highest fd that we know about.  If it is 0, completely
- * recalculate everything.
- */
-
-int
-select_recalc(struct event_base *base, void *arg, int max)
-{
-	struct selectop *sop = arg;
-
-	check_selectop(sop);
-
-	return (0);
-}
-
-int
+static int
 select_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
 	int res, i;
@@ -196,13 +179,9 @@
 			res |= EV_WRITE;
 		}
 		if (r_ev && (res & r_ev->ev_events)) {
-			if (!(r_ev->ev_events & EV_PERSIST))
-				event_del(r_ev);
 			event_active(r_ev, res & r_ev->ev_events, 1);
 		}
 		if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
-			if (!(w_ev->ev_events & EV_PERSIST))
-				event_del(w_ev);
 			event_active(w_ev, res & w_ev->ev_events, 1);
 		}
 	}
@@ -271,7 +250,7 @@
 }
 
 
-int
+static int
 select_add(void *arg, struct event *ev)
 {
 	struct selectop *sop = arg;
@@ -321,7 +300,7 @@
  * Nothing to be done here.
  */
 
-int
+static int
 select_del(void *arg, struct event *ev)
 {
 	struct selectop *sop = arg;
@@ -349,7 +328,7 @@
 	return (0);
 }
 
-void
+static void
 select_dealloc(struct event_base *base, void *arg)
 {
 	struct selectop *sop = arg;
Index: contrib/libevent/signal.c
===================================================================
RCS file: /home/dcvs/src/contrib/libevent/signal.c,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 signal.c
--- contrib/libevent/signal.c	30 Jan 2008 12:35:18 -0000	1.1.1.1
+++ contrib/libevent/signal.c	14 May 2008 04:07:41 -0000
@@ -30,20 +30,27 @@
 #include "config.h"
 #endif
 
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#endif
 #include <sys/types.h>
-#include <sys/tree.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
-#else
-#include <sys/_time.h>
 #endif
 #include <sys/queue.h>
+#ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
+#endif
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
+#endif
 #include <errno.h>
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
@@ -53,6 +60,7 @@
 #include "event.h"
 #include "event-internal.h"
 #include "evsignal.h"
+#include "evutil.h"
 #include "log.h"
 
 struct event_base *evsignal_base = NULL;
@@ -64,13 +72,15 @@
 evsignal_cb(int fd, short what, void *arg)
 {
 	static char signals[100];
-	struct event *ev = arg;
+#ifdef WIN32
+	SSIZE_T n;
+#else
 	ssize_t n;
+#endif
 
-	n = read(fd, signals, sizeof(signals));
+	n = recv(fd, signals, sizeof(signals), 0);
 	if (n == -1)
 		event_err(1, "%s: read", __func__);
-	event_add(ev, NULL);
 }
 
 #ifdef HAVE_SETFD
@@ -90,55 +100,146 @@
 	 * pair to wake up our event loop.  The event loop then scans for
 	 * signals that got delivered.
 	 */
-	if (socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1)
+	if (evutil_socketpair(AF_UNIX, SOCK_STREAM, 0, base->sig.ev_signal_pair) == -1)
 		event_err(1, "%s: socketpair", __func__);
 
 	FD_CLOSEONEXEC(base->sig.ev_signal_pair[0]);
 	FD_CLOSEONEXEC(base->sig.ev_signal_pair[1]);
+	base->sig.sh_old = NULL;
+	base->sig.sh_old_max = 0;
 	base->sig.evsignal_caught = 0;
 	memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);
 
-	fcntl(base->sig.ev_signal_pair[0], F_SETFL, O_NONBLOCK);
+        evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
 
-	event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1], EV_READ,
-	    evsignal_cb, &base->sig.ev_signal);
+	event_set(&base->sig.ev_signal, base->sig.ev_signal_pair[1],
+		EV_READ | EV_PERSIST, evsignal_cb, &base->sig.ev_signal);
 	base->sig.ev_signal.ev_base = base;
 	base->sig.ev_signal.ev_flags |= EVLIST_INTERNAL;
 }
 
+/* Helper: set the signal handler for evsignal to handler in base, so that
+ * we can restore the original handler when we clear the current one. */
+int
+_evsignal_set_handler(struct event_base *base,
+		      int evsignal, void (*handler)(int))
+{
+#ifdef HAVE_SIGACTION
+	struct sigaction sa;
+#else
+	ev_sighandler_t sh;
+#endif
+	struct evsignal_info *sig = &base->sig;
+	void *p;
+
+	/*
+	 * resize saved signal handler array up to the highest signal number.
+	 * a dynamic array is used to keep footprint on the low side.
+	 */
+	if (evsignal >= sig->sh_old_max) {
+		event_debug(("%s: evsignal (%d) >= sh_old_max (%d), resizing",
+			    __func__, evsignal, sig->sh_old_max));
+		sig->sh_old_max = evsignal + 1;
+		p = realloc(sig->sh_old, sig->sh_old_max * sizeof *sig->sh_old);
+		if (p == NULL) {
+			event_warn("realloc");
+			return (-1);
+		}
+		sig->sh_old = p;
+	}
+
+	/* allocate space for previous handler out of dynamic array */
+	sig->sh_old[evsignal] = malloc(sizeof *sig->sh_old[evsignal]);
+	if (sig->sh_old[evsignal] == NULL) {
+		event_warn("malloc");
+		return (-1);
+	}
+
+	/* save previous handler and setup new handler */
+#ifdef HAVE_SIGACTION
+	memset(&sa, 0, sizeof(sa));
+	sa.sa_handler = handler;
+	sa.sa_flags |= SA_RESTART;
+	sigfillset(&sa.sa_mask);
+
+	if (sigaction(evsignal, &sa, sig->sh_old[evsignal]) == -1) {
+		event_warn("sigaction");
+		free(sig->sh_old[evsignal]);
+		return (-1);
+	}
+#else
+	if ((sh = signal(evsignal, handler)) == SIG_ERR) {
+		event_warn("signal");
+		free(sig->sh_old[evsignal]);
+		return (-1);
+	}
+	*sig->sh_old[evsignal] = sh;
+#endif
+
+	return (0);
+}
+
 int
 evsignal_add(struct event *ev)
 {
 	int evsignal;
-	struct sigaction sa;
 	struct event_base *base = ev->ev_base;
+	struct evsignal_info *sig = &ev->ev_base->sig;
 
 	if (ev->ev_events & (EV_READ|EV_WRITE))
 		event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
 	evsignal = EVENT_SIGNAL(ev);
 
-	memset(&sa, 0, sizeof(sa));
-	sa.sa_handler = evsignal_handler;
-	sigfillset(&sa.sa_mask);
-	sa.sa_flags |= SA_RESTART;
+	event_debug(("%s: %p: changing signal handler", __func__, ev));
+	if (_evsignal_set_handler(base, evsignal, evsignal_handler) == -1)
+		return (-1);
+
 	/* catch signals if they happen quickly */
 	evsignal_base = base;
 
-	if (sigaction(evsignal, &sa, NULL) == -1)
-		return (-1);
-
-	if (!base->sig.ev_signal_added) {
-		base->sig.ev_signal_added = 1;
-		event_add(&base->sig.ev_signal, NULL);
+	if (!sig->ev_signal_added) {
+		sig->ev_signal_added = 1;
+		event_add(&sig->ev_signal, NULL);
 	}
 
 	return (0);
 }
 
 int
+_evsignal_restore_handler(struct event_base *base, int evsignal)
+{
+	int ret = 0;
+	struct evsignal_info *sig = &base->sig;
+#ifdef HAVE_SIGACTION
+	struct sigaction *sh;
+#else
+	ev_sighandler_t *sh;
+#endif
+
+	/* restore previous handler */
+	sh = sig->sh_old[evsignal];
+	sig->sh_old[evsignal] = NULL;
+#ifdef HAVE_SIGACTION
+	if (sigaction(evsignal, sh, NULL) == -1) {
+		event_warn("sigaction");
+		ret = -1;
+	}
+#else
+	if (signal(evsignal, *sh) == SIG_ERR) {
+		event_warn("signal");
+		ret = -1;
+	}
+#endif
+	free(sh);
+
+	return ret;
+}
+
+int
 evsignal_del(struct event *ev)
 {
-	return (sigaction(EVENT_SIGNAL(ev),(struct sigaction *)SIG_DFL, NULL));
+	event_debug(("%s: %p: restoring signal handler", __func__, ev));
+	return _evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev));
 }
 
 static void
@@ -148,7 +249,7 @@
 
 	if(evsignal_base == NULL) {
 		event_warn(
-			"%s: received signal %s, but have no base configured",
+			"%s: received signal %d, but have no base configured",
 			__func__, sig);
 		return;
 	}
@@ -156,8 +257,12 @@
 	evsignal_base->sig.evsigcaught[sig]++;
 	evsignal_base->sig.evsignal_caught = 1;
 
+#ifndef HAVE_SIGACTION
+	signal(sig, evsignal_handler);
+#endif
+
 	/* Wake up our notification mechanism */
-	write(evsignal_base->sig.ev_signal_pair[0], "a", 1);
+	send(evsignal_base->sig.ev_signal_pair[0], "a", 1, 0);
 	errno = save_errno;
 }
 
@@ -188,8 +293,12 @@
 	}
 	assert(TAILQ_EMPTY(&base->sig.signalqueue));
 
-	close(base->sig.ev_signal_pair[0]);
+	EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
 	base->sig.ev_signal_pair[0] = -1;
-	close(base->sig.ev_signal_pair[1]);
+	EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[1]);
 	base->sig.ev_signal_pair[1] = -1;
+	base->sig.sh_old_max = 0;
+
+	/* per index frees are handled in evsignal_del() */
+	free(base->sig.sh_old);
 }
Index: contrib/libevent/strlcpy-internal.h
===================================================================
RCS file: contrib/libevent/strlcpy-internal.h
diff -N contrib/libevent/strlcpy-internal.h
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ contrib/libevent/strlcpy-internal.h	30 Jun 2008 21:09:37 -0000
@@ -0,0 +1,23 @@
+#ifndef _STRLCPY_INTERNAL_H_
+#define _STRLCPY_INTERNAL_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef HAVE_STRLCPY
+#include <string.h>
+size_t _event_strlcpy(char *dst, const char *src, size_t siz);
+#define strlcpy _event_strlcpy
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
