List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:April 28 2008 5:52pm
Subject:bk commit into 6.0 tree (davi:1.2632)
View as plain text  
Below is the list of changes that have just been committed into a local
6.0 repository of davi.  When davi does a push these changes
will be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2008-04-28 14:52:20-03:00, davi@stripped +31 -0
  Bring changes from libevent-1.4.3-stable

  config/ac-macros/libevent.m4@stripped, 2008-04-28 14:52:14-03:00, davi@stripped +1 -341
    Move libevent checks to libevent_configure.m4

  config/ac-macros/libevent_configure.m4@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +285 -0
    Move libevent check from libevent.m4
    Bring changes from the libevent release.

  config/ac-macros/libevent_configure.m4@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +0 -0

  extra/libevent/Makefile.am@stripped, 2008-04-28 14:52:14-03:00, davi@stripped +21 -5
    Only compile the core parts required by the server.
    Generate event-config.h as required by libevent.

  extra/libevent/README@stripped, 2008-04-28 14:52:14-03:00, davi@stripped +5 -1
    Bring changes from the libevent release.

  extra/libevent/buffer.c@stripped, 2008-04-28 14:52:14-03:00, davi@stripped +18 -23
    Bring changes from the libevent release.

  extra/libevent/devpoll.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +13 -15
    Bring changes from the libevent release.

  extra/libevent/epoll.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +23 -34
    Bring changes from the libevent release.

  extra/libevent/evbuffer.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +7 -2
    Bring changes from the libevent release.

  extra/libevent/evdns.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +106 -72
    Bring changes from the libevent release.

  extra/libevent/evdns.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +258 -97
    Bring changes from the libevent release.

  extra/libevent/event-internal.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +36 -1
    Bring changes from the libevent release.

  extra/libevent/event.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +147 -87
    Bring changes from the libevent release.

  extra/libevent/event.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +841 -54
    Bring changes from the libevent release.

  extra/libevent/event_tagging.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +144 -73
    Bring changes from the libevent release.

  extra/libevent/evhttp.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +149 -30
    Bring changes from the libevent release.

  extra/libevent/evport.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +63 -81
    Bring changes from the libevent release.

  extra/libevent/evrpc-internal.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +87 -0
    Bring changes from the libevent release.

  extra/libevent/evrpc-internal.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +0 -0

  extra/libevent/evrpc.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +658 -0
    Bring changes from the libevent release.

  extra/libevent/evrpc.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +0 -0

  extra/libevent/evrpc.h@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +477 -0
    Bring changes from the libevent release.

  extra/libevent/evrpc.h@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +0 -0

  extra/libevent/evsignal.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +8 -0
    Bring changes from the libevent release.

  extra/libevent/evutil.c@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +198 -0
    Bring changes from the libevent release.

  extra/libevent/evutil.c@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +0 -0

  extra/libevent/evutil.h@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +174 -0
    Bring changes from the libevent release.

  extra/libevent/evutil.h@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +0 -0

  extra/libevent/http-internal.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +15 -4
    Bring changes from the libevent release.

  extra/libevent/http.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +336 -192
    Bring changes from the libevent release.

  extra/libevent/kqueue.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +33 -31
    Bring changes from the libevent release.

  extra/libevent/log.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +0 -1
    Bring changes from the libevent release.

  extra/libevent/log.h@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +14 -6
    Bring changes from the libevent release.

  extra/libevent/min_heap.h@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +138 -0
    Bring changes from the libevent release.

  extra/libevent/min_heap.h@stripped, 2008-04-28 14:52:16-03:00, davi@stripped +0 -0

  extra/libevent/poll.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +12 -29
    Bring changes from the libevent release.

  extra/libevent/select.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +12 -33
    Bring changes from the libevent release.

  extra/libevent/signal.c@stripped, 2008-04-28 14:52:15-03:00, davi@stripped +135 -26
    Bring changes from the libevent release.

diff -Nrup a/config/ac-macros/libevent.m4 b/config/ac-macros/libevent.m4
--- a/config/ac-macros/libevent.m4	2008-04-17 16:07:58 -03:00
+++ b/config/ac-macros/libevent.m4	2008-04-28 14:52:14 -03:00
@@ -22,347 +22,7 @@ AC_DEFUN([MYSQL_USE_BUNDLED_LIBEVENT], [
   AC_DEFINE([HAVE_LIBEVENT], [1], [If we want to use libevent and have connection pooling])
   AC_MSG_RESULT([using bundled libevent])
 
-  dnl Things that libevent needs
-  AC_CHECK_HEADERS(inttypes.h stdint.h poll.h signal.h sys/epoll.h sys/time.h \
-                   sys/queue.h sys/event.h sys/devpoll.h netinet/in6.h)
-
-if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
-	AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
-	AC_EGREP_CPP(yes,
-[
-#include <sys/queue.h>
-#ifdef TAILQ_FOREACH
- yes
-#endif
-],	[AC_MSG_RESULT(yes)
-	 AC_DEFINE(HAVE_TAILQFOREACH, 1,
-		[Define if TAILQ_FOREACH is defined in <sys/queue.h>])],
-	AC_MSG_RESULT(no)
-	)
-fi
-
-if test "x$ac_cv_header_sys_time_h" = "xyes"; then
-	AC_MSG_CHECKING(for timeradd in sys/time.h)
-	AC_EGREP_CPP(yes,
-[
-#include <sys/time.h>
-#ifdef timeradd
- yes
-#endif
-],	[ AC_DEFINE(HAVE_TIMERADD, 1,
-		[Define if timeradd is defined in <sys/time.h>])
-	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
-)
-fi
-
-if test "x$ac_cv_header_sys_time_h" = "xyes"; then
-	AC_MSG_CHECKING(for timercmp in sys/time.h)
-	AC_EGREP_CPP(yes,
-[
-#include <sys/time.h>
-#ifdef timercmp
- yes
-#endif
-],	[ AC_DEFINE(HAVE_TIMERCMP, 1,
-		[Define if timercmp is defined in <sys/time.h>])
-	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
-)
-fi
-
-if test "x$ac_cv_header_sys_time_h" = "xyes"; then
-	AC_MSG_CHECKING(for timerclear in sys/time.h)
-	AC_EGREP_CPP(yes,
-[
-#include <sys/time.h>
-#ifdef timerclear
- yes
-#endif
-],	[ AC_DEFINE(HAVE_TIMERCLEAR, 1,
-		[Define if timerclear is defined in <sys/time.h>])
-	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
-)
-fi
-
-if test "x$ac_cv_header_sys_time_h" = "xyes"; then
-	AC_MSG_CHECKING(for timerisset in sys/time.h)
-	AC_EGREP_CPP(yes,
-[
-#include <sys/time.h>
-#ifdef timerisset
- yes
-#endif
-],	[ AC_DEFINE(HAVE_TIMERISSET, 1,
-		[Define if timerisset is defined in <sys/time.h>])
-	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
-)
-fi
-
-dnl Checks for library functions.
-AC_CHECK_FUNCS(vasprintf strsep getaddrinfo getnameinfo inet_ntop)
-
-if test "x$ac_cv_func_clock_gettime" = "xyes"; then
-   AC_DEFINE(DNS_USE_CPU_CLOCK_FOR_ID, 1, [Define if clock_gettime is available in libc])
-else
-   AC_DEFINE(DNS_USE_GETTIMEOFDAY_FOR_ID, 1, [Define is no secure id variant is available])
-fi
-
-AC_MSG_CHECKING(for F_SETFD in fcntl.h)
-AC_EGREP_CPP(yes,
-[
-#define _GNU_SOURCE
-#include <fcntl.h>
-#ifdef F_SETFD
-yes
-#endif
-],	[ AC_DEFINE(HAVE_SETFD, 1,
-	      [Define if F_SETFD is defined in <fcntl.h>])
-	  AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no))
-
-needsignal=no
-if test "x$ac_cv_func_select" = "xyes" ; then
-	 AC_LIBOBJ(select)
-	 needsignal=yes
-fi
-
-if test "x$ac_cv_func_poll" = "xyes" ; then
-	 AC_LIBOBJ(poll)
-	 needsignal=yes
-fi
-
-haveepoll=no
-AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], )
-if test "x$haveepoll" = "xyes" ; then
-	AC_DEFINE(HAVE_EPOLL, 1,
-		[Define if your system supports the epoll system calls])
-	AC_LIBOBJ(epoll)
-	needsignal=yes
-fi
-
-havedevpoll=no
-if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then
-	AC_DEFINE(HAVE_DEVPOLL, 1,
-		    [Define if /dev/poll is available])
-        AC_LIBOBJ(devpoll)
-fi
-
-havekqueue=no
-if test "x$ac_cv_header_sys_event_h" = "xyes"; then
-	AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
-	if test "x$havekqueue" = "xyes" ; then
-		AC_MSG_CHECKING(for working kqueue)
-		AC_TRY_RUN(
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/event.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-int
-main(int argc, char **argv)
-{
-	int kq;
-	int n;
-	int fd[[2]];
-	struct kevent ev;
-	struct timespec ts;
-	char buf[[8000]];
-
-	if (pipe(fd) == -1)
-		exit(1);
-	if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
-		exit(1);
-
-	while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
-		;
-
-        if ((kq = kqueue()) == -1)
-		exit(1);
-
-	ev.ident = fd[[1]];
-	ev.filter = EVFILT_WRITE;
-	ev.flags = EV_ADD | EV_ENABLE;
-	n = kevent(kq, &ev, 1, NULL, 0, NULL);
-	if (n == -1)
-		exit(1);
-	
-	read(fd[[0]], buf, sizeof(buf));
-
-	ts.tv_sec = 0;
-	ts.tv_nsec = 0;
-	n = kevent(kq, NULL, 0, &ev, 1, &ts);
-	if (n == -1 || n == 0)
-		exit(1);
-
-	exit(0);
-}, [AC_MSG_RESULT(yes)
-    AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
-		[Define if kqueue works correctly with pipes])
-    AC_LIBOBJ(kqueue)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
-	fi
-fi
-
-haveepollsyscall=no
-if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
-	if test "x$haveepoll" = "xno" ; then
-		AC_MSG_CHECKING(for epoll system call)
-		AC_TRY_RUN(
-#include <stdint.h>
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/syscall.h>
-#include <sys/epoll.h>
-#include <unistd.h>
-
-int
-epoll_create(int size)
-{
-	return (syscall(__NR_epoll_create, size));
-}
-
-int
-main(int argc, char **argv)
-{
-	int epfd;
-
-	epfd = epoll_create(256);
-	exit (epfd == -1 ? 1 : 0);
-}, [AC_MSG_RESULT(yes)
-    AC_DEFINE(HAVE_EPOLL, 1,
-	[Define if your system supports the epoll system calls])
-    needsignal=yes
-    AC_LIBOBJ(epoll_sub)
-    AC_LIBOBJ(epoll)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
-	fi
-fi
-
-haveeventports=no
-AC_CHECK_FUNCS(port_create, [haveeventports=yes], )
-if test "x$haveeventports" = "xyes" ; then
-	AC_DEFINE(HAVE_EVENT_PORTS, 1,
-		[Define if your system supports event ports])
-	AC_LIBOBJ(evport)
-	needsignal=yes
-fi
-if test "x$needsignal" = "xyes" ; then
-	AC_LIBOBJ(signal)
-fi
-
-AC_TYPE_PID_T
-AC_TYPE_SIZE_T
-AC_CHECK_TYPE(uint64_t, unsigned long long)
-AC_CHECK_TYPE(uint32_t, unsigned int)
-AC_CHECK_TYPE(uint16_t, unsigned short)
-AC_CHECK_TYPE(uint8_t, unsigned char)
-AC_CHECK_TYPES([struct in6_addr], , ,
-[#ifdef WIN32
-#include <winsock2.h>
-#else
-#include <sys/types.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#endif
-#ifdef HAVE_NETINET_IN6_H
-#include <netinet/in6.h>
-#endif])
-
-AC_MSG_CHECKING([for socklen_t])
-AC_TRY_COMPILE([
- #include <sys/types.h>
- #include <sys/socket.h>],
-  [socklen_t x;],
-  AC_MSG_RESULT([yes]),
-  [AC_MSG_RESULT([no])
-  AC_DEFINE(socklen_t, unsigned int,
-	[Define to unsigned int if you dont have it])]
-)
-
-AC_MSG_CHECKING([whether our compiler supports __func__])
-AC_TRY_COMPILE([],
- [ const char *cp = __func__; ],
- AC_MSG_RESULT([yes]),
- AC_MSG_RESULT([no])
- AC_MSG_CHECKING([whether our compiler supports __FUNCTION__])
- AC_TRY_COMPILE([],
-   [ const char *cp = __FUNCTION__; ],
-   AC_MSG_RESULT([yes])
-   AC_DEFINE(__func__, __FUNCTION__,
-         [Define to appropriate substitue if compiler doesnt have __func__]),
-   AC_MSG_RESULT([no])
-   AC_DEFINE(__func__, __FILE__,
-         [Define to appropriate substitue if compiler doesnt have __func__])))
-
-AH_VERBATIM([HAVE_TIMERADD], [
-/* Define if timeradd is defined in <sys/time.h> */
-#undef HAVE_TIMERADD
-#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 */
-])
-
-AH_VERBATIM([HAVE_TIMERCLEAR], [
-#undef HAVE_TIMERCLEAR
-#ifndef HAVE_TIMERCLEAR
-#define	timerclear(tvp)	(tvp)->tv_sec = (tvp)->tv_usec = 0
-#endif
-])
-
-AH_VERBATIM([HAVE_TIMERCMP], [
-#undef HAVE_TIMERCMP
-#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
-])
-
-AH_VERBATIM([HAVE_TIMERISSET], [
-#undef HAVE_TIMERISSET
-#ifndef HAVE_TIMERISSET
-#undef timerisset
-#define	timerisset(tvp)	((tvp)->tv_sec || (tvp)->tv_usec)
-#endif
-])
-
-AH_VERBATIM([HAVE_TAILQFOREACH], [
-/* Define if TAILQ_FOREACH is defined in <sys/queue.h> */
-#undef HAVE_TAILQFOREACH
-#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 */
-])
+  sinclude(config/ac-macros/libevent_configure.m4)
 ])
 
 
diff -Nrup a/config/ac-macros/libevent_configure.m4 b/config/ac-macros/libevent_configure.m4
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/config/ac-macros/libevent_configure.m4	2008-04-28 14:52:16 -03:00
@@ -0,0 +1,285 @@
+dnl Checks for libraries.
+AC_CHECK_LIB(socket, socket)
+AC_CHECK_LIB(resolv, inet_aton)
+AC_CHECK_LIB(rt, clock_gettime)
+AC_CHECK_LIB(nsl, inet_ntoa)
+
+dnl Checks for header files.
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h stdarg.h inttypes.h stdint.h poll.h signal.h unistd.h sys/epoll.h sys/time.h sys/queue.h sys/event.h sys/param.h sys/ioctl.h sys/select.h sys/devpoll.h port.h netinet/in6.h sys/socket.h)
+if test "x$ac_cv_header_sys_queue_h" = "xyes"; then
+	AC_MSG_CHECKING(for TAILQ_FOREACH in sys/queue.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/queue.h>
+#ifdef TAILQ_FOREACH
+ yes
+#endif
+],	[AC_MSG_RESULT(yes)
+	 AC_DEFINE(HAVE_TAILQFOREACH, 1,
+		[Define if TAILQ_FOREACH is defined in <sys/queue.h>])],
+	AC_MSG_RESULT(no)
+	)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timeradd in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timeradd
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERADD, 1,
+		[Define if timeradd is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timercmp in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timercmp
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERCMP, 1,
+		[Define if timercmp is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timerclear in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerclear
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERCLEAR, 1,
+		[Define if timerclear is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+if test "x$ac_cv_header_sys_time_h" = "xyes"; then
+	AC_MSG_CHECKING(for timerisset in sys/time.h)
+	AC_EGREP_CPP(yes,
+[
+#include <sys/time.h>
+#ifdef timerisset
+ yes
+#endif
+],	[ AC_DEFINE(HAVE_TIMERISSET, 1,
+		[Define if timerisset is defined in <sys/time.h>])
+	  AC_MSG_RESULT(yes)] ,AC_MSG_RESULT(no)
+)
+fi
+
+dnl Checks for typedefs, structures, and compiler characteristics.
+AC_C_CONST
+AC_C_INLINE
+AC_HEADER_TIME
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS(gettimeofday vasprintf fcntl clock_gettime strtok_r strsep getaddrinfo getnameinfo strlcpy inet_ntop signal sigaction strtoll)
+
+AC_CHECK_SIZEOF(long)
+
+if test "x$ac_cv_func_clock_gettime" = "xyes"; then
+   AC_DEFINE(DNS_USE_CPU_CLOCK_FOR_ID, 1, [Define if clock_gettime is available in libc])
+else
+   AC_DEFINE(DNS_USE_GETTIMEOFDAY_FOR_ID, 1, [Define is no secure id variant is available])
+fi
+
+AC_MSG_CHECKING(for F_SETFD in fcntl.h)
+AC_EGREP_CPP(yes,
+[
+#define _GNU_SOURCE
+#include <fcntl.h>
+#ifdef F_SETFD
+yes
+#endif
+],	[ AC_DEFINE(HAVE_SETFD, 1,
+	      [Define if F_SETFD is defined in <fcntl.h>])
+	  AC_MSG_RESULT(yes) ], AC_MSG_RESULT(no))
+
+needsignal=no
+haveselect=no
+AC_CHECK_FUNCS(select, [haveselect=yes], )
+if test "x$haveselect" = "xyes" ; then
+	AC_LIBOBJ(select)
+	needsignal=yes
+fi
+
+havepoll=no
+AC_CHECK_FUNCS(poll, [havepoll=yes], )
+if test "x$havepoll" = "xyes" ; then
+	AC_LIBOBJ(poll)
+	needsignal=yes
+fi
+
+haveepoll=no
+AC_CHECK_FUNCS(epoll_ctl, [haveepoll=yes], )
+if test "x$haveepoll" = "xyes" ; then
+	AC_DEFINE(HAVE_EPOLL, 1,
+		[Define if your system supports the epoll system calls])
+	AC_LIBOBJ(epoll)
+	needsignal=yes
+fi
+
+havedevpoll=no
+if test "x$ac_cv_header_sys_devpoll_h" = "xyes"; then
+	AC_DEFINE(HAVE_DEVPOLL, 1,
+		    [Define if /dev/poll is available])
+        AC_LIBOBJ(devpoll)
+fi
+
+havekqueue=no
+if test "x$ac_cv_header_sys_event_h" = "xyes"; then
+	AC_CHECK_FUNCS(kqueue, [havekqueue=yes], )
+	if test "x$havekqueue" = "xyes" ; then
+		AC_MSG_CHECKING(for working kqueue)
+		AC_TRY_RUN(
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/event.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int
+main(int argc, char **argv)
+{
+	int kq;
+	int n;
+	int fd[[2]];
+	struct kevent ev;
+	struct timespec ts;
+	char buf[[8000]];
+
+	if (pipe(fd) == -1)
+		exit(1);
+	if (fcntl(fd[[1]], F_SETFL, O_NONBLOCK) == -1)
+		exit(1);
+
+	while ((n = write(fd[[1]], buf, sizeof(buf))) == sizeof(buf))
+		;
+
+        if ((kq = kqueue()) == -1)
+		exit(1);
+
+	ev.ident = fd[[1]];
+	ev.filter = EVFILT_WRITE;
+	ev.flags = EV_ADD | EV_ENABLE;
+	n = kevent(kq, &ev, 1, NULL, 0, NULL);
+	if (n == -1)
+		exit(1);
+	
+	read(fd[[0]], buf, sizeof(buf));
+
+	ts.tv_sec = 0;
+	ts.tv_nsec = 0;
+	n = kevent(kq, NULL, 0, &ev, 1, &ts);
+	if (n == -1 || n == 0)
+		exit(1);
+
+	exit(0);
+}, [AC_MSG_RESULT(yes)
+    AC_DEFINE(HAVE_WORKING_KQUEUE, 1,
+		[Define if kqueue works correctly with pipes])
+    AC_LIBOBJ(kqueue)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+	fi
+fi
+
+haveepollsyscall=no
+if test "x$ac_cv_header_sys_epoll_h" = "xyes"; then
+	if test "x$haveepoll" = "xno" ; then
+		AC_MSG_CHECKING(for epoll system call)
+		AC_TRY_RUN(
+#include <stdint.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/syscall.h>
+#include <sys/epoll.h>
+#include <unistd.h>
+
+int
+epoll_create(int size)
+{
+	return (syscall(__NR_epoll_create, size));
+}
+
+int
+main(int argc, char **argv)
+{
+	int epfd;
+
+	epfd = epoll_create(256);
+	exit (epfd == -1 ? 1 : 0);
+}, [AC_MSG_RESULT(yes)
+    AC_DEFINE(HAVE_EPOLL, 1,
+	[Define if your system supports the epoll system calls])
+    needsignal=yes
+    AC_LIBOBJ(epoll_sub)
+    AC_LIBOBJ(epoll)], AC_MSG_RESULT(no), AC_MSG_RESULT(no))
+	fi
+fi
+
+haveeventports=no
+AC_CHECK_FUNCS(port_create, [haveeventports=yes], )
+if test "x$haveeventports" = "xyes" ; then
+	AC_DEFINE(HAVE_EVENT_PORTS, 1,
+		[Define if your system supports event ports])
+	AC_LIBOBJ(evport)
+	needsignal=yes
+fi
+if test "x$bwin32" = "xtrue"; then
+	needsignal=yes
+fi
+if test "x$bwin32" = "xtrue"; then
+	needsignal=yes
+fi
+if test "x$needsignal" = "xyes" ; then
+	AC_LIBOBJ(signal)
+fi
+
+AC_TYPE_PID_T
+AC_TYPE_SIZE_T
+AC_CHECK_TYPES([uint64_t, uint32_t, uint16_t, uint8_t], , ,
+[#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#elif defined(HAVE_INTTYPES_H)
+#include <inttypes.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif])
+AC_CHECK_SIZEOF(long long)
+AC_CHECK_SIZEOF(long)   
+AC_CHECK_SIZEOF(int)
+AC_CHECK_SIZEOF(short)
+AC_CHECK_TYPES([struct in6_addr], , ,
+[#ifdef WIN32
+#include <winsock2.h>
+#else
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN6_H
+#include <netinet/in6.h>
+#endif])
+
+AC_MSG_CHECKING([for socklen_t])
+AC_TRY_COMPILE([
+ #include <sys/types.h>
+ #include <sys/socket.h>],
+  [socklen_t x;],
+  AC_MSG_RESULT([yes]),
+  [AC_MSG_RESULT([no])
+  AC_DEFINE(socklen_t, unsigned int,
+	[Define to unsigned int if you dont have it])]
+)
diff -Nrup a/extra/libevent/Makefile.am b/extra/libevent/Makefile.am
--- a/extra/libevent/Makefile.am	2007-11-15 19:06:15 -02:00
+++ b/extra/libevent/Makefile.am	2008-04-28 14:52:14 -03:00
@@ -2,14 +2,30 @@ AUTOMAKE_OPTIONS = foreign no-dependenci
 
 EXTRA_DIST = README compat/sys
 
+DISTCLEANFILES = event-config.h
+
 noinst_LIBRARIES = libevent.a
 
-libevent_a_SOURCES = event.c buffer.c evbuffer.c log.c event_tagging.c \
-	http.c evhttp.h http-internal.h evdns.c evdns.h strlcpy.c \
-	strlcpy-internal.h strlcpy-internal.h event-internal.h \
+libevent_a_SOURCES = event.c buffer.c evbuffer.c log.c evutil.c \
         select.c poll.c epoll.c epoll_sub.c devpoll.c kqueue.c \
-	evport.c evsignal.h signal.c
+	evport.c signal.c
+
+include_HEADERS = event.h evutil.h event-config.h
+
+BUILT_SOURCES = event-config.h
+
+event-config.h: $(top_srcdir)/include/config.h
+	echo '/* event-config.h' > $@
+	echo ' * Generated by autoconf; post-processed by libevent.' >> $@
+	echo ' * Do not edit this file.' >> $@
+	echo ' * Do not rely on macros in this file existing in later versions.'>> $@
+	echo ' */' >> $@
+	echo '#ifndef _EVENT_CONFIG_H_' >> $@
+	echo '#define _EVENT_CONFIG_H_' >> $@
 
-include_HEADERS = event.h evhttp.h evdns.h log.h
+	sed -e 's/#define /#define _EVENT_/' \
+	    -e 's/#undef /#undef _EVENT_/' \
+	    -e 's/#ifndef /#ifndef _EVENT_/' < $(top_srcdir)/include/config.h >> $@
+	echo "#endif" >> $@
 
 INCLUDES = -Icompat -I$(top_srcdir)/include
diff -Nrup a/extra/libevent/README b/extra/libevent/README
--- a/extra/libevent/README	2007-11-01 16:37:49 -02:00
+++ b/extra/libevent/README	2008-04-28 14:52:14 -03:00
@@ -2,6 +2,10 @@ To build libevent, type
 
 $ ./configure && make
 
+     (If you got libevent from the subversion repository, you will
+      first need to run the included "autogen.sh" script in order to
+      generate the configure script.)
+
 Install as root via
 
 # make install
@@ -15,7 +19,7 @@ Before, reporting any problems, please r
 To enable the low-level tracing build the library as:
 
 CFLAGS=-DUSE_DEBUG ./configure [...]
- 
+
 Acknowledgements:
 -----------------
 
diff -Nrup a/extra/libevent/buffer.c b/extra/libevent/buffer.c
--- a/extra/libevent/buffer.c	2007-11-01 16:37:49 -02:00
+++ b/extra/libevent/buffer.c	2008-04-28 14:52:14 -03:00
@@ -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 @@ evbuffer_read(struct evbuffer *buf, int 
 	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 @@ evbuffer_read(struct evbuffer *buf, int 
 
 #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 @@ int
 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);
diff -Nrup a/extra/libevent/devpoll.c b/extra/libevent/devpoll.c
--- a/extra/libevent/devpoll.c	2007-11-15 19:06:15 -02:00
+++ b/extra/libevent/devpoll.c	2008-04-28 14:52:15 -03:00
@@ -38,7 +38,6 @@
 #include <sys/_time.h>
 #endif
 #include <sys/queue.h>
-#include <sys/tree.h>
 #include <sys/devpoll.h>
 #include <signal.h>
 #include <stdio.h>
@@ -72,21 +71,20 @@ struct devpollop {
 	int nchanges;
 };
 
-void *devpoll_init	(struct event_base *);
-int devpoll_add	(void *, struct event *);
-int devpoll_del	(void *, struct event *);
-int devpoll_recalc	(struct event_base *, void *, int);
-int devpoll_dispatch	(struct event_base *, void *, struct timeval *);
-void devpoll_dealloc	(struct event_base *, void *);
+static void *devpoll_init	(struct event_base *);
+static int devpoll_add	(void *, struct event *);
+static int devpoll_del	(void *, struct event *);
+static int devpoll_dispatch	(struct event_base *, void *, struct timeval *);
+static void devpoll_dealloc	(struct event_base *, void *);
 
 struct eventop devpollops = {
 	"devpoll",
 	devpoll_init,
 	devpoll_add,
 	devpoll_del,
-	devpoll_recalc,
 	devpoll_dispatch,
-	devpoll_dealloc
+	devpoll_dealloc,
+	1 /* need reinit */
 };
 
 #define NEVENT	32000
@@ -127,7 +125,7 @@ devpoll_queue(struct devpollop *devpollo
 	return(0);
 }
 
-void *
+static void *
 devpoll_init(struct event_base *base)
 {
 	int dpfd, nfiles = NEVENT;
@@ -186,7 +184,7 @@ devpoll_init(struct event_base *base)
 	return (devpollop);
 }
 
-int
+static int
 devpoll_recalc(struct event_base *base, void *arg, int max)
 {
 	struct devpollop *devpollop = arg;
@@ -213,7 +211,7 @@ devpoll_recalc(struct event_base *base, 
 	return (0);
 }
 
-int
+static int
 devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
 	struct devpollop *devpollop = arg;
@@ -290,7 +288,7 @@ devpoll_dispatch(struct event_base *base
 }
 
 
-int
+static int
 devpoll_add(void *arg, struct event *ev)
 {
 	struct devpollop *devpollop = arg;
@@ -344,7 +342,7 @@ devpoll_add(void *arg, struct event *ev)
 	return (0);
 }
 
-int
+static int
 devpoll_del(void *arg, struct event *ev)
 {
 	struct devpollop *devpollop = arg;
@@ -401,7 +399,7 @@ devpoll_del(void *arg, struct event *ev)
 	return (0);
 }
 
-void
+static void
 devpoll_dealloc(struct event_base *base, void *arg)
 {
 	struct devpollop *devpollop = arg;
diff -Nrup a/extra/libevent/epoll.c b/extra/libevent/epoll.c
--- a/extra/libevent/epoll.c	2007-11-15 19:06:15 -02:00
+++ b/extra/libevent/epoll.c	2008-04-28 14:52:15 -03:00
@@ -32,7 +32,6 @@
 
 #include <stdint.h>
 #include <sys/types.h>
-#include <sys/tree.h>
 #include <sys/resource.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
@@ -72,21 +71,20 @@ struct epollop {
 	int epfd;
 };
 
-void *epoll_init	(struct event_base *);
-int epoll_add	(void *, struct event *);
-int epoll_del	(void *, struct event *);
-int epoll_recalc	(struct event_base *, void *, int);
-int epoll_dispatch	(struct event_base *, void *, struct timeval *);
-void epoll_dealloc	(struct event_base *, void *);
+static void *epoll_init	(struct event_base *);
+static int epoll_add	(void *, struct event *);
+static int epoll_del	(void *, struct event *);
+static int epoll_dispatch	(struct event_base *, void *, struct timeval *);
+static void epoll_dealloc	(struct event_base *, void *);
 
 struct eventop epollops = {
 	"epoll",
 	epoll_init,
 	epoll_add,
 	epoll_del,
-	epoll_recalc,
 	epoll_dispatch,
-	epoll_dealloc
+	epoll_dealloc,
+	1 /* need reinit */
 };
 
 #ifdef HAVE_SETFD
@@ -100,7 +98,7 @@ struct eventop epollops = {
 
 #define NEVENT	32000
 
-void *
+static void *
 epoll_init(struct event_base *base)
 {
 	int epfd, nfiles = NEVENT;
@@ -156,7 +154,7 @@ epoll_init(struct event_base *base)
 	return (epollop);
 }
 
-int
+static int
 epoll_recalc(struct event_base *base, void *arg, int max)
 {
 	struct epollop *epollop = arg;
@@ -183,7 +181,7 @@ epoll_recalc(struct event_base *base, vo
 	return (0);
 }
 
-int
+static int
 epoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
 	struct epollop *epollop = arg;
@@ -211,36 +209,27 @@ epoll_dispatch(struct event_base *base, 
 	event_debug(("%s: epoll_wait reports %d", __func__, res));
 
 	for (i = 0; i < res; i++) {
-		int which = 0;
 		int what = events[i].events;
 		struct event *evread = NULL, *evwrite = NULL;
 
 		evep = (struct evepoll *)events[i].data.ptr;
-   
-                if (what & EPOLLHUP)
-                        what |= EPOLLIN | EPOLLOUT;
-                else if (what & EPOLLERR)
-                        what |= EPOLLIN | EPOLLOUT;
 
-		if (what & EPOLLIN) {
+		if (what & (EPOLLHUP|EPOLLERR)) {
 			evread = evep->evread;
-			which |= EV_READ;
-		}
-
-		if (what & EPOLLOUT) {
 			evwrite = evep->evwrite;
-			which |= EV_WRITE;
+		} else {
+			if (what & EPOLLIN) {
+				evread = evep->evread;
+			}
+
+			if (what & EPOLLOUT) {
+				evwrite = evep->evwrite;
+			}
 		}
 
-		if (!which)
+		if (!(evread||evwrite))
 			continue;
 
-		if (evread != NULL && !(evread->ev_events & EV_PERSIST))
-			event_del(evread);
-		if (evwrite != NULL && evwrite != evread &&
-		    !(evwrite->ev_events & EV_PERSIST))
-			event_del(evwrite);
-
 		if (evread != NULL)
 			event_active(evread, EV_READ, 1);
 		if (evwrite != NULL)
@@ -251,7 +240,7 @@ epoll_dispatch(struct event_base *base, 
 }
 
 
-int
+static int
 epoll_add(void *arg, struct event *ev)
 {
 	struct epollop *epollop = arg;
@@ -299,7 +288,7 @@ epoll_add(void *arg, struct event *ev)
 	return (0);
 }
 
-int
+static int
 epoll_del(void *arg, struct event *ev)
 {
 	struct epollop *epollop = arg;
@@ -350,7 +339,7 @@ epoll_del(void *arg, struct event *ev)
 	return (0);
 }
 
-void
+static void
 epoll_dealloc(struct event_base *base, void *arg)
 {
 	struct epollop *epollop = arg;
diff -Nrup a/extra/libevent/evbuffer.c b/extra/libevent/evbuffer.c
--- a/extra/libevent/evbuffer.c	2007-11-01 16:37:49 -02:00
+++ b/extra/libevent/evbuffer.c	2008-04-28 14:52:15 -03:00
@@ -43,6 +43,11 @@
 #include <stdarg.h>
 #endif
 
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
+#include "evutil.h"
 #include "event.h"
 
 /* prototypes */
@@ -56,7 +61,7 @@ bufferevent_add(struct event *ev, int ti
 	struct timeval tv, *ptv = NULL;
 
 	if (timeout) {
-		timerclear(&tv);
+		evutil_timerclear(&tv);
 		tv.tv_sec = timeout;
 		ptv = &tv;
 	}
@@ -288,7 +293,7 @@ bufferevent_free(struct bufferevent *buf
  */
 
 int
-bufferevent_write(struct bufferevent *bufev, void *data, size_t size)
+bufferevent_write(struct bufferevent *bufev, const void *data, size_t size)
 {
 	int res;
 
diff -Nrup a/extra/libevent/evdns.c b/extra/libevent/evdns.c
--- a/extra/libevent/evdns.c	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/evdns.c	2008-04-28 14:52:15 -03:00
@@ -43,16 +43,20 @@
 #include "misc.h"
 #endif
 
-/* #define NDEBUG */
+#ifdef DNS_USE_FTIME_FOR_ID
+#include <sys/timeb.h>
+#endif
 
 #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 +82,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 +92,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 +102,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 +119,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 +126,32 @@ typedef int socklen_t;
 #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
 
-#define MAX_ADDRS 4  /* maximum number of addresses from a single packet */
+#ifdef WIN32
+#define snprintf _snprintf
+#define open _open
+#define read _read
+#define close _close
+#define strdup _strdup
+#endif
+
+#define MAX_ADDRS 32  /* maximum number of addresses from a single packet */
 /* which we bother recording */
 
 #define TYPE_A         EVDNS_TYPE_A
@@ -319,7 +331,7 @@ static int search_request_new(int type, 
 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 +364,7 @@ error_is_eagain(int err)
 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 +375,15 @@ inet_aton(const char *c, struct in_addr 
 	}
 	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 +396,6 @@ debug_ntoa(u32 address)
   		      (int)(u8)((a    )&0xff));
 	return buf;
 }
-#endif
 
 static evdns_debug_log_fn_type evdns_log_fn = NULL;
 
@@ -852,7 +861,7 @@ reply_parse(u8 *packet, int length) {
 		 */
 		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 +962,7 @@ request_parse(u8 *packet, int length, st
 	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 +991,7 @@ request_parse(u8 *packet, int length, st
 		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 +1000,13 @@ request_parse(u8 *packet, int length, st
 
 	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 +1027,65 @@ err:
 #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;
+	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;
+		  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 +1511,7 @@ evdns_server_request_add_reply(struct ev
 		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 +1626,7 @@ evdns_server_request_format_response(str
 			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 +1645,7 @@ evdns_server_request_format_response(str
 			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 +1655,7 @@ evdns_server_request_format_response(str
 				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 +1702,8 @@ evdns_server_request_respond(struct evdn
 	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 +2020,8 @@ evdns_clear_nameservers_and_suspend(void
 	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 +2090,7 @@ _evdns_nameserver_add_impl(unsigned long
 
 	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 +2300,8 @@ int evdns_resolve_reverse(struct in_addr
 }
 
 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 +2314,8 @@ int evdns_resolve_reverse_ipv6(struct in
 		*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 +2529,7 @@ search_try_next(struct request *const re
 			/* 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 +2951,7 @@ load_nameservers_from_registry(void)
 #undef TRY
 }
 
-int
+static int
 evdns_config_windows_nameservers(void)
 {
 	if (load_nameservers_with_getnetworkparams() == 0)
@@ -2931,7 +2965,7 @@ evdns_init(void)
 {
 	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 +3063,20 @@ evdns_server_callback(struct evdns_serve
 	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 +3119,7 @@ main(int c, char **v) {
 		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;
diff -Nrup a/extra/libevent/evdns.h b/extra/libevent/evdns.h
--- a/extra/libevent/evdns.h	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/evdns.h	2008-04-28 14:52:15 -03:00
@@ -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 @@ extern "C" {
 #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 @@ extern "C" {
  */
 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_request {
 };
 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 @@ typedef void (*evdns_request_callback_fn
 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);
@@ -363,5 +520,9 @@ int evdns_server_request_respond(struct 
 int evdns_server_request_drop(struct evdns_server_request *req);
 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 */
diff -Nrup a/extra/libevent/event-internal.h b/extra/libevent/event-internal.h
--- a/extra/libevent/event-internal.h	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/event-internal.h	2008-04-28 14:52:15 -03:00
@@ -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 @@ struct event_base {
 	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,8 +65,29 @@ struct event_base {
 	struct event_list eventqueue;
 	struct timeval event_tv;
 
-	RB_HEAD(event_tree, event) timetree;
+	struct min_heap timeheap;
 };
+
+/* 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
 }
diff -Nrup a/extra/libevent/event.c b/extra/libevent/event.c
--- a/extra/libevent/event.c	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/event.c	2008-04-28 14:52:15 -03:00
@@ -35,7 +35,6 @@
 #include "misc.h"
 #endif
 #include <sys/types.h>
-#include <sys/tree.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #else 
@@ -55,6 +54,7 @@
 
 #include "event.h"
 #include "event-internal.h"
+#include "evutil.h"
 #include "log.h"
 
 #ifdef HAVE_EVENT_PORTS
@@ -66,9 +66,6 @@ extern const struct eventop selectops;
 #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 +93,6 @@ const struct eventop *eventops[] = {
 #ifdef HAVE_DEVPOLL
 	&devpollops,
 #endif
-#ifdef HAVE_RTSIG
-	&rtsigops,
-#endif
 #ifdef HAVE_POLL
 	&pollops,
 #endif
@@ -131,20 +125,6 @@ static int	timeout_next(struct event_bas
 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)
 {
@@ -175,19 +155,25 @@ gettime(struct timeval *tp)
 	return (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;
@@ -195,7 +181,7 @@ event_init(void)
 	detect_monotonic();
 	gettime(&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 +204,48 @@ event_init(void)
 	/* 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 +256,34 @@ event_base_free(struct event_base *base)
 	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);
+	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 +342,6 @@ event_process_active(struct event_base *
 	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 +352,10 @@ event_process_active(struct event_base *
 	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 +364,7 @@ event_process_active(struct event_base *
 			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 +386,13 @@ event_base_dispatch(struct event_base *e
   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)
 {
@@ -374,6 +416,25 @@ event_base_loopexit(struct event_base *e
 }
 
 /* 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 +451,21 @@ event_base_loop(struct event_base *base,
 	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 +488,7 @@ event_base_loop(struct event_base *base,
 			 * 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 */
@@ -439,7 +499,6 @@ event_base_loop(struct event_base *base,
 
 		res = evsel->dispatch(base, evbase, tv_p);
 
-
 		if (res == -1)
 			return (-1);
 
@@ -506,7 +565,7 @@ event_base_once(struct event_base *base,
 
 	if (events == EV_TIMEOUT) {
 		if (tv == NULL) {
-			timerclear(&etv);
+			evutil_timerclear(&etv);
 			tv = &etv;
 		}
 
@@ -548,6 +607,8 @@ event_set(struct event *ev, int fd, shor
 	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;
@@ -608,10 +669,10 @@ event_pending(struct event *ev, short ev
 	/* 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);
+		evutil_timersub(&ev->ev_timeout, &now, &res);
 		/* correctly remap to real time */
 		gettimeofday(&now, NULL);
-		timeradd(&now, &res, tv);
+		evutil_timeradd(&now, &res, tv);
 	}
 
 	return (flags & event);
@@ -639,6 +700,9 @@ event_add(struct event *ev, struct timev
 
 		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
@@ -657,7 +721,7 @@ event_add(struct event *ev, struct timev
 		}
 
 		gettime(&now);
-		timeradd(&now, tv, &ev->ev_timeout);
+		evutil_timeradd(&now, tv, &ev->ev_timeout);
 
 		event_debug((
 			 "event_add: timeout in %d seconds, call %p",
@@ -668,14 +732,18 @@ event_add(struct event *ev, struct timev
 
 	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,7 +814,7 @@ timeout_next(struct event_base *base, st
 	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);
@@ -755,12 +823,12 @@ timeout_next(struct event_base *base, st
 	if (gettime(&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,7 +846,8 @@ timeout_next(struct event_base *base, st
 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)
@@ -786,37 +855,41 @@ timeout_correct(struct event_base *base,
 
 	/* Check if time is running backwards */
 	gettime(tv);
-	if (timercmp(tv, &base->event_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;
+
+	if (min_heap_empty(&base->timeheap))
+		return;
 
 	gettime(&now);
 
-	for (ev = RB_MIN(event_tree, &base->timetree); ev; ev = next) {
-		if (timercmp(&ev->ev_timeout, &now, >))
+	while ((ev = min_heap_top(&base->timeheap))) {
+		if (evutil_timercmp(&ev->ev_timeout, &now, >))
 			break;
-		next = RB_NEXT(event_tree, &base->timetree, ev);
-
-		event_queue_remove(base, ev, EVLIST_TIMEOUT);
 
 		/* delete this event from the I/O queues */
 		event_del(ev);
@@ -830,23 +903,17 @@ timeout_process(struct event_base *base)
 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_ACTIVE:
-		if (docount)
-			base->event_count_active--;
+		base->event_count_active--;
 		TAILQ_REMOVE(base->activequeues[ev->ev_pri],
 		    ev, ev_active_next);
 		break;
@@ -854,7 +921,7 @@ event_queue_remove(struct event_base *ba
 		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);
@@ -867,8 +934,6 @@ event_queue_remove(struct event_base *ba
 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,17 +943,13 @@ event_queue_insert(struct event_base *ba
 			   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_ACTIVE:
-		if (docount)
-			base->event_count_active++;
+		base->event_count_active++;
 		TAILQ_INSERT_TAIL(base->activequeues[ev->ev_pri],
 		    ev,ev_active_next);
 		break;
@@ -896,8 +957,7 @@ event_queue_insert(struct event_base *ba
 		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:
diff -Nrup a/extra/libevent/event.h b/extra/libevent/event.h
--- a/extra/libevent/event.h	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/event.h	2008-04-28 14:52:15 -03:00
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2004 Niels Provos <provos@stripped>
+ * Copyright (c) 2000-2007 Niels Provos <provos@stripped>
  * 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 {								\
 	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 @@ struct evkeyvalq;
 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 */
+
+/**
+  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(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 *, 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,207 @@ int event_base_loopexit(struct event_bas
 #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 *);
+
+/**
+  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 *, 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 *, int, short, void (*)(int, short, void *), void *, struct timeval *);
 
+
+/**
+  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 *, struct timeval *);
+
+
+/**
+  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);
 
+
+/**
+  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 *, short, struct timeval *);
 
+
+/**
+  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 {
@@ -259,40 +765,311 @@ struct bufferevent {
 	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);
+
+
+/**
+  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);
 
+
 #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 0 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 0 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 +1077,47 @@ void evbuffer_setcb(struct evbuffer *, v
 
 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
diff -Nrup a/extra/libevent/event_tagging.c b/extra/libevent/event_tagging.c
--- a/extra/libevent/event_tagging.c	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/event_tagging.c	2008-04-28 14:52:15 -03:00
@@ -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,10 +88,10 @@ evtag_init()
  */
 
 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));
 	while (number) {
@@ -105,40 +114,105 @@ encode_int(struct evbuffer *evbuf, uint3
 }
 
 /*
+ * 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 @@ evtag_marshal_timeval(struct evbuffer *e
 }
 
 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 @@ decode_int_internal(uint32_t *pnumber, s
 }
 
 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 @@ evtag_payload_length(struct evbuffer *ev
 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 @@ evtag_consume(struct evbuffer *evbuf)
 /* 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 @@ evtag_unmarshal(struct evbuffer *src, ui
 
 	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 @@ evtag_unmarshal_int(struct evbuffer *evb
 
 	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 @@ evtag_unmarshal_fixed(struct evbuffer *s
 }
 
 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 @@ evtag_unmarshal_string(struct evbuffer *
 }
 
 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;
 
diff -Nrup a/extra/libevent/evhttp.h b/extra/libevent/evhttp.h
--- a/extra/libevent/evhttp.h	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/evhttp.h	2008-04-28 14:52:15 -03:00
@@ -40,7 +40,8 @@ extern "C" {
 #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
@@ -64,58 +65,124 @@ struct evhttp;
 struct evhttp_request;
 struct evkeyvalq;
 
-/* Start an HTTP server on the specified address and port */
-struct evhttp *evhttp_start(const char *address, u_short port);
+/** 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);
 
-/*
- * Free the previously create HTTP server.  Works only if no requests are
- * currently being served.
+/**
+ * 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);
+
+/**
+ * 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 */
+/** 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 */
+/** 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 */
+/** 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 */
 
-void evhttp_send_error(struct evhttp_request *, int, const char *);
-void evhttp_send_reply(struct evhttp_request *, int, const char *,
-    struct evbuffer *);
+/**
+ * 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 *);
-	
-/* Interfaces for making requests */
+
+/**
+ * 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_REQ_OWN_CONNECTION	0x0001
 #define EVHTTP_PROXY_REQUEST		0x0002
-	
+
 	struct evkeyvalq *input_headers;
 	struct evkeyvalq *output_headers;
 
@@ -130,13 +197,13 @@ struct evhttp_request {
 
 	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 */
-	int ntoread;
+	ev_int64_t ntoread;
 	int chunked;
 
 	struct evbuffer *output_buffer;	/* outgoing post or data */
@@ -145,7 +212,7 @@ struct evhttp_request {
 	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.
@@ -153,7 +220,7 @@ struct evhttp_request {
 	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.
@@ -161,14 +228,14 @@ struct evhttp_request {
 struct evhttp_request *evhttp_request_new(
 	void (*cb)(struct evhttp_request *, void *), void *arg);
 
-/* enable delivery of chunks to requestor */
+/** 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. */
+/** 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.
@@ -176,26 +243,37 @@ void evhttp_request_free(struct evhttp_r
 struct evhttp_connection *evhttp_connection_new(
 	const char *address, unsigned short port);
 
-/* Frees an http connection */
+/** Frees an http connection */
 void evhttp_connection_free(struct evhttp_connection *evcon);
 
-/* Sets the timeout for events related to this connection */
+/** 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 */
+/** 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. */
+/** Set a callback for connection close. */
 void evhttp_connection_set_closecb(struct evhttp_connection *evcon,
     void (*)(struct evhttp_connection *, void *), void *);
 
-/* Get the remote address and port associated with this connection. */
+/**
+ * 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 */
+/** 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);
@@ -210,10 +288,51 @@ int evhttp_add_header(struct evkeyvalq *
 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
diff -Nrup a/extra/libevent/evport.c b/extra/libevent/evport.c
--- a/extra/libevent/evport.c	2007-11-15 19:06:15 -02:00
+++ b/extra/libevent/evport.c	2008-04-28 14:52:15 -03:00
@@ -12,20 +12,20 @@
  * 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.
+ * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``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 SUN MICROSYSTEMS, INC. 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. 
  */
 
 /*
- * Copyright (c) 2006 Sun Microsystems. All rights reserved.
+ * Copyright (c) 2007 Sun Microsystems. All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -47,8 +47,7 @@
  * necessary when large fd's come in. reassociate() takes care of maintaining
  * the proper file-descriptor/event-port associations.
  *
- * As in the select(2) implementation, signals are handled by evsignal, and
- * evport_recalc does almost nothing.
+ * As in the select(2) implementation, signals are handled by evsignal.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -57,14 +56,9 @@
 
 #ifdef HAVE_EVENT_PORTS
 
-#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
-#else
-#include <sys/_time.h>
-#endif
 #include <assert.h>
 #include <sys/queue.h>
-#include <sys/tree.h>
 #include <errno.h>
 #include <poll.h>
 #include <port.h>
@@ -120,13 +114,12 @@ struct evport_data {
 	int		ed_nevents;	/* number of allocated fdi's 	 */
 	struct fd_info *ed_fds;		/* allocated fdi table 		 */
 	/* fdi's that we need to reassoc */
-	struct fd_info *ed_pending[EVENTS_PER_GETN];
+	int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */
 };
 
 static void*	evport_init	(struct event_base *);
 static int 	evport_add	(void *, struct event *);
 static int 	evport_del	(void *, struct event *);
-static int 	evport_recalc	(struct event_base *, void *, int);
 static int 	evport_dispatch	(struct event_base *, void *, struct timeval *);
 static void	evport_dealloc	(struct event_base *, void *);
 
@@ -135,9 +128,9 @@ const struct eventop evportops = {
 	evport_init,
 	evport_add,
 	evport_del,
-	evport_recalc,
 	evport_dispatch,
-	evport_dealloc
+	evport_dealloc,
+	1 /* need reinit */
 };
 
 /*
@@ -148,6 +141,7 @@ static void*
 evport_init(struct event_base *base)
 {
 	struct evport_data *evpd;
+	int i;
 	/*
 	 * Disable event ports when this environment variable is set 
 	 */
@@ -172,7 +166,8 @@ evport_init(struct event_base *base)
 		return (NULL);
 	}
 	evpd->ed_nevents = DEFAULT_NFDS;
-	memset(&evpd->ed_pending, 0, EVENTS_PER_GETN * sizeof(struct fd_info*));
+	for (i = 0; i < EVENTS_PER_GETN; i++)
+		evpd->ed_pending[i] = -1;
 
 	evsignal_init(base);
 
@@ -242,10 +237,8 @@ static int
 grow(struct evport_data *epdp, int factor)
 {
 	struct fd_info *tmp;
-	struct fd_info *old = epdp->ed_fds;
 	int oldsize = epdp->ed_nevents;
 	int newsize = factor * oldsize;
-	int ii;
 	assert(factor > 1);
 
 	check_evportop(epdp);
@@ -256,15 +249,6 @@ grow(struct evport_data *epdp, int facto
 	epdp->ed_fds = tmp;
 	memset((char*) (epdp->ed_fds + oldsize), 0, 
 	    (newsize - oldsize)*sizeof(struct fd_info));
-
-	/* The ev_pending array contains pointers into the released array. */
-	for (ii = 0; ii < EVENTS_PER_GETN; ++ii) {
-		if (epdp->ed_pending[ii] != 0) {
-			int offset = epdp->ed_pending[ii] - old;
-			epdp->ed_pending[ii] = epdp->ed_fds + offset;
-		}
-	}
-        
 	epdp->ed_nevents = newsize;
 
 	check_evportop(epdp);
@@ -283,14 +267,9 @@ reassociate(struct evport_data *epdp, st
 	int sysevents = FDI_TO_SYSEVENTS(fdip);
 
 	if (sysevents != 0) {
-		if ((-1 == port_associate(epdp->ed_port, PORT_SOURCE_FD,
-		    fd, sysevents, NULL))) {
-			perror("port_associate");
-			return (-1);
-		}
-	} else {
-		if (-1 == port_dissociate(epdp->ed_port, PORT_SOURCE_FD, fd)) {
-			perror("port_dissociate");
+		if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
+				   fd, sysevents, NULL) == -1) {
+			event_warn("port_associate");
 			return (-1);
 		}
 	}
@@ -339,26 +318,29 @@ evport_dispatch(struct event_base *base,
 	 * loop below.
 	 */
 	for (i = 0; i < EVENTS_PER_GETN; ++i) {
-		struct fd_info *fdi = epdp->ed_pending[i];
+		struct fd_info *fdi = NULL;
+		if (epdp->ed_pending[i] != -1) {
+			fdi = &(epdp->ed_fds[epdp->ed_pending[i]]);
+		}
 
 		if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
 			int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd : 
 			    fdi->fdi_wevt->ev_fd;
 			reassociate(epdp, fdi, fd);
-			epdp->ed_pending[i] = NULL;
+			epdp->ed_pending[i] = -1;
 		}
 	}
 
 	if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN, 
 		    (unsigned int *) &nevents, ts_p)) == -1) {
-		if (errno == EINTR) {
+		if (errno == EINTR || errno == EAGAIN) {
 			evsignal_process(base);
 			return (0);
 		} else if (errno == ETIME) {
 			if (nevents == 0)
 				return (0);
 		} else {
-			perror("port_getn");
+			event_warn("port_getn");
 			return (-1);
 		}
 	} else if (base->sig.evsignal_caught) {
@@ -375,6 +357,7 @@ evport_dispatch(struct event_base *base,
 
 		check_evportop(epdp);
 		check_event(pevt);
+		epdp->ed_pending[i] = fd;
 
 		/*
 		 * Figure out what kind of event it was 
@@ -390,36 +373,18 @@ evport_dispatch(struct event_base *base,
 		fdi = &(epdp->ed_fds[fd]);
 
 		/*
-		 * We now check for each of the possible events (READ or WRITE).
-		 * If the event is not persistent, then we delete it. Then, we
-		 * activate the event (which will cause its callback to be
-		 * executed).
+		 * We now check for each of the possible events (READ
+		 * or WRITE).  Then, we activate the event (which will
+		 * cause its callback to be executed).
 		 */
 
 		if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) {
-			if (!(ev->ev_events & EV_PERSIST))
-				event_del(ev);
 			event_active(ev, res, 1);
 		}
 
 		if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) {
-			if (!(ev->ev_events & EV_PERSIST))
-				event_del(ev);
 			event_active(ev, res, 1);
 		}
-
-		/*
-		 * If there are still events (they haven't been deleted), then
-		 * we must reassociate the port, since the event port interface
-		 * dissociates them automatically. 
-		 *
-		 * But we can't do it right away, because the event hasn't
-		 * handled this event yet, so of course there's still data
-		 * waiting!
-		 */
-		if(FDI_HAS_EVENTS(fdi)) {
-			epdp->ed_pending[i] = fdi;
-		}
 	} /* end of all events gotten */
 
 	check_evportop(epdp);
@@ -429,19 +394,6 @@ evport_dispatch(struct event_base *base,
 
 
 /*
- * Copied from the version in select.c
- */
-
-static int
-evport_recalc(struct event_base *base, void *arg, int max)
-{
-	struct evport_data *evpd = arg;
-	check_evportop(evpd);
-	return (0);
-}
-
-
-/*
  * Adds the given event (so that you will be notified when it happens via
  * the callback function).
  */
@@ -493,6 +445,8 @@ evport_del(void *arg, struct event *ev)
 {
 	struct evport_data *evpd = arg;
 	struct fd_info *fdi;
+	int i;
+	int associated = 1;
 
 	check_evportop(evpd);
 
@@ -507,6 +461,12 @@ evport_del(void *arg, struct event *ev)
 		return (-1);
 	}
 
+	for (i = 0; i < EVENTS_PER_GETN; ++i) {
+		if (evpd->ed_pending[i] == ev->ev_fd) {
+			associated = 0;
+			break;
+		}
+	}
 
 	fdi = &evpd->ed_fds[ev->ev_fd];
 	if (ev->ev_events & EV_READ)
@@ -514,7 +474,29 @@ evport_del(void *arg, struct event *ev)
 	if (ev->ev_events & EV_WRITE)
 		fdi->fdi_wevt = NULL;
 
-	return reassociate(evpd, fdi, ev->ev_fd);
+	if (associated) {
+		if (!FDI_HAS_EVENTS(fdi) &&
+		    port_dissociate(evpd->ed_port, PORT_SOURCE_FD,
+		    ev->ev_fd) == -1) {	 
+			/*
+			 * Ignre EBADFD error the fd could have been closed
+			 * before event_del() was called.
+			 */
+			if (errno != EBADFD) {
+				event_warn("port_dissociate");
+				return (-1);
+			}
+		} else {
+			if (FDI_HAS_EVENTS(fdi)) {
+				return (reassociate(evpd, fdi, ev->ev_fd));
+			}
+		}
+	} else {
+		if (fdi->fdi_revt == NULL && fdi->fdi_wevt == NULL) {
+			evpd->ed_pending[i] = -1;
+		}
+	}
+	return 0;
 }
 
 
diff -Nrup a/extra/libevent/evrpc-internal.h b/extra/libevent/evrpc-internal.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/extra/libevent/evrpc-internal.h	2008-04-28 14:52:15 -03:00
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@stripped>
+ * 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_ */
diff -Nrup a/extra/libevent/evrpc.c b/extra/libevent/evrpc.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/extra/libevent/evrpc.c	2008-04-28 14:52:15 -03:00
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2000-2004 Niels Provos <provos@stripped>
+ * 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 <windows.h>
+#include <winsock2.h>
+#undef WIN32_LEAN_AND_MEAN
+#include "misc.h"
+#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, INPUT, hook));
+	}
+	while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
+		assert(evrpc_remove_hook(base, 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 INPUT:
+		head = &base->in_hooks;
+		break;
+	case OUTPUT:
+		head = &base->out_hooks;
+		break;
+	default:
+		assert(hook_type == INPUT || hook_type == 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 INPUT:
+		head = &base->in_hooks;
+		break;
+	case OUTPUT:
+		head = &base->out_hooks;
+		break;
+	default:
+		assert(hook_type == INPUT || hook_type == 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, INPUT, hook));
+	}
+
+	while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
+		assert(evrpc_remove_hook(pool, 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);
+}
diff -Nrup a/extra/libevent/evrpc.h b/extra/libevent/evrpc.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/extra/libevent/evrpc.h	2008-04-28 14:52:16 -03:00
@@ -0,0 +1,477 @@
+/*
+ * Copyright (c) 2006 Niels Provos <provos@stripped>
+ * 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 {
+	INPUT,		/**< apply the function to an input hook */
+	OUTPUT		/**< apply the function to an output hook */
+};
+
+/** 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_ */
diff -Nrup a/extra/libevent/evsignal.h b/extra/libevent/evsignal.h
--- a/extra/libevent/evsignal.h	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/evsignal.h	2008-04-28 14:52:15 -03:00
@@ -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 @@ struct evsignal_info {
 	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 *);
diff -Nrup a/extra/libevent/evutil.c b/extra/libevent/evutil.c
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/extra/libevent/evutil.c	2008-04-28 14:52:16 -03:00
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@stripped>
+ * 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 <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+#include <winsock2.h>
+#include "misc.h"
+#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>
+
+#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
+}
diff -Nrup a/extra/libevent/evutil.h b/extra/libevent/evutil.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/extra/libevent/evutil.h	2008-04-28 14:52:16 -03:00
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2007 Niels Provos <provos@stripped>
+ * 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 __uint64_t
+#define ev_int64_t __int64_t
+#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
+
+#ifdef _EVENT_HAVE_TIMERCMP
+#define evutil_timercmp(tvp, uvp, cmp) timercmp((tvp), (uvp), cmp)
+#else
+#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))
+#endif
+
+#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 __cplusplus
+}
+#endif
+
+#endif /* _EVUTIL_H_ */
diff -Nrup a/extra/libevent/http-internal.h b/extra/libevent/http-internal.h
--- a/extra/libevent/http-internal.h	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/http-internal.h	2008-04-28 14:52:15 -03:00
@@ -35,9 +35,11 @@ enum evhttp_connection_state {
 	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;
+	TAILQ_ENTRY(evhttp_connection) (next);
 
 	int fd;
 	struct event ev;
@@ -45,7 +47,9 @@ struct evhttp_connection {
 	struct evbuffer *input_buffer;
 	struct evbuffer *output_buffer;
 	
-	char *address;
+	char *bind_address;		/* address to use for binding the src */
+
+	char *address;			/* address to connect to */
 	u_short port;
 
 	int flags;
@@ -64,11 +68,13 @@ struct evhttp_connection {
 
 	TAILQ_HEAD(evcon_requestq, evhttp_request) requests;
 	
-	void (*cb)(struct evhttp_connection *, void *);
+						   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 {
@@ -80,16 +86,21 @@ struct evhttp_cb {
 	void *cbarg;
 };
 
+/* both the http server as well as the rpc system need to queue connections */
+TAILQ_HEAD(evconq, evhttp_connection);
+
 struct evhttp {
 	struct event bind_ev;
 
 	TAILQ_HEAD(httpcbq, evhttp_cb) callbacks;
-        TAILQ_HEAD(evconq, evhttp_connection) connections;
+        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 */
diff -Nrup a/extra/libevent/http.c b/extra/libevent/http.c
--- a/extra/libevent/http.c	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/http.c	2008-04-28 14:52:15 -03:00
@@ -25,13 +25,17 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/param.h>
-#include <sys/types.h>
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
+#ifdef HAVE_SYS_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
@@ -46,7 +50,6 @@
 #include <sys/wait.h>
 #endif
 
-#include <sys/tree.h>
 #include <sys/queue.h>
 
 #ifndef WIN32
@@ -54,6 +57,10 @@
 #include <netdb.h>
 #endif
 
+#ifdef WIN32
+#include <winsock2.h>
+#endif
+
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
@@ -65,8 +72,12 @@
 #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
@@ -74,9 +85,17 @@
 #include "strlcpy-internal.h"
 #include "event.h"
 #include "evhttp.h"
+#include "evutil.h"
 #include "log.h"
 #include "http-internal.h"
 
+#ifdef WIN32
+#define snprintf _snprintf
+#define strcasecmp _stricmp
+#define strncasecmp _strnicmp
+#define strdup _strdup
+#endif
+
 #ifndef HAVE_GETADDRINFO
 struct addrinfo {
 	int ai_family;
@@ -89,17 +108,28 @@ struct addrinfo {
 static int
 fake_getaddrinfo(const char *hostname, struct addrinfo *ai)
 {
-	struct hostent *he;
-	he = gethostbyname(hostname);
-	if (!he)
-		return (-1);
-	ai->ai_family = he->h_addrtype;
+	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 = he->h_length;
+	ai->ai_addrlen = sizeof(struct sockaddr_in);
 	if (NULL == (ai->ai_addr = malloc(ai->ai_addrlen)))
 		return (-1);
-	memcpy(ai->ai_addr, &he->h_addr_list[0], ai->ai_addrlen);
+	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);
 }
@@ -114,28 +144,16 @@ fake_freeaddrinfo(struct addrinfo *ai)
 #define MIN(a,b) (((a)<(b))?(a):(b))
 #endif
 
-static int
-event_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;
-}
+/* 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 make_socket_ai(int should_bind, struct addrinfo *);
-static int make_socket(int should_bind, const char *, u_short);
+static int socket_connect(int fd, const char *address, unsigned short port);
+static int bind_socket_ai(struct addrinfo *);
+static int bind_socket(const char *, u_short);
 static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
 static int evhttp_associate_new_request_with_connection(
 	struct evhttp_connection *evcon);
@@ -149,27 +167,29 @@ 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)
-		*s = d + strlen(del);
-	else
+	if (d) {
+		*d = '\0';
+		*s = d + 1;
+	} else
 		*s = NULL;
 	return tok;
 }
 #endif
 
 static const char *
-html_replace(char ch)
+html_replace(char ch, char *buf)
 {
-	static char buf[2];
-	
 	switch (ch) {
 	case '<':
 		return "&lt;";
@@ -204,15 +224,16 @@ 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]));
+          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]);
+		const char *replaced = html_replace(html[i], scratch_space);
 		/* this is length checked */
 		strcpy(p, replaced);
 		p += strlen(replaced);
@@ -223,7 +244,7 @@ evhttp_htmlescape(const char *html)
 	return (escaped_html);
 }
 
-const char *
+static const char *
 evhttp_method(enum evhttp_cmd_type type)
 {
 	const char *method;
@@ -252,7 +273,7 @@ evhttp_add_event(struct event *ev, int t
 	if (timeout != 0) {
 		struct timeval tv;
 		
-		timerclear(&tv);
+		evutil_timerclear(&tv);
 		tv.tv_sec = timeout != -1 ? timeout : default_timeout;
 		event_add(ev, &tv);
 	} else {
@@ -275,17 +296,18 @@ evhttp_write_buffer(struct evhttp_connec
 		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 reply
+ * Create the headers need for an HTTP request
  */
 static void
 evhttp_make_header_request(struct evhttp_connection *evcon,
     struct evhttp_request *req)
 {
-	static char line[1024];
+	char line[1024];
 	const char *method;
 	
 	evhttp_remove_header(req->output_headers, "Accept-Encoding");
@@ -328,58 +350,76 @@ evhttp_is_connection_keepalive(struct ev
 	    && 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];
+		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)
 {
-	static char line[1024];
+	char line[1024];
 	snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
 	    req->major, req->minor, req->response_code,
 	    req->response_code_line);
 	evbuffer_add(evcon->output_buffer, line, strlen(line));
 
-	/* Potentially add headers for unidentified content. */
-	if (EVBUFFER_LENGTH(req->output_buffer)) {
-		if (evhttp_find_header(req->output_headers,
-							   "Date") == NULL) {
-			char date[50];
-			struct tm cur, *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(req->output_headers, "Date", date);
-			}
-		}
-
-		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 (req->major == 1 && req->minor == 1)
+		evhttp_maybe_add_date_header(req->output_headers);
 
+	if (req->major == 1 && 
+	    (req->minor == 1 || 
+		evhttp_is_connection_keepalive(req->input_headers))) {
 		/* 
 		 * 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,
-			"Transfer-Encoding") == NULL &&
-		    evhttp_find_header(req->output_headers,
-			"Content-Length") == NULL) {
-			static char len[12];
-			snprintf(len, sizeof(len), "%ld",
-			    (long)EVBUFFER_LENGTH(req->output_buffer));
+			"Content-Type") == NULL) {
 			evhttp_add_header(req->output_headers,
-			    "Content-Length", len);
+			    "Content-Type", "text/html; charset=ISO-8859-1");
 		}
 	}
 
@@ -395,7 +435,7 @@ evhttp_make_header_response(struct evhtt
 void
 evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
 {
-	static char line[1024];
+	char line[1024];
 	struct evkeyval *header;
 
 	/*
@@ -415,7 +455,7 @@ evhttp_make_header(struct evhttp_connect
 	}
 	evbuffer_add(evcon->output_buffer, "\r\n", 2);
 
-	if (EVBUFFER_LENGTH(req->output_buffer) >= 0) {
+	if (EVBUFFER_LENGTH(req->output_buffer) > 0) {
 		/*
 		 * For a request, we add the POST data, for a reply, this
 		 * is the regular data.
@@ -429,9 +469,11 @@ evhttp_make_header(struct evhttp_connect
 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, *p2;
+	char *p;
+	const char *p2;
 	int len;
 	u_short port;
 
@@ -590,12 +632,12 @@ evhttp_write(int fd, short what, void *a
 		(*evcon->cb)(evcon, evcon->cb_arg);
 }
 
-void
+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.
@@ -666,7 +708,7 @@ evhttp_handle_chunked_read(struct evhttp
 				free(p);
 				continue;
 			}
-			req->ntoread = strtol(p, &endp, 16);
+			req->ntoread = evutil_strtoll(p, &endp, 16);
 			error = *p == '\0' || (*endp != '\0' && *endp != ' ');
 			free(p);
 			if (error) {
@@ -699,7 +741,7 @@ evhttp_handle_chunked_read(struct evhttp
 	return (0);
 }
 
-void
+static void
 evhttp_read_body(struct evhttp_connection *evcon, struct evhttp_request *req)
 {
 	struct evbuffer *buf = evcon->input_buffer;
@@ -730,6 +772,7 @@ evhttp_read_body(struct evhttp_connectio
 	}
 	/* 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);
 }
 
@@ -768,7 +811,7 @@ evhttp_read(int fd, short what, void *ar
 	evhttp_read_body(evcon, req);
 }
 
-void
+static void
 evhttp_write_connectioncb(struct evhttp_connection *evcon, void *arg)
 {
 	/* This is after writing the request to the server */
@@ -814,7 +857,10 @@ evhttp_connection_free(struct evhttp_con
 		event_del(&evcon->ev);
 	
 	if (evcon->fd != -1)
-		close(evcon->fd);
+		EVUTIL_CLOSESOCKET(evcon->fd);
+
+	if (evcon->bind_address != NULL)
+		free(evcon->bind_address);
 
 	if (evcon->address != NULL)
 		free(evcon->address);
@@ -828,6 +874,18 @@ evhttp_connection_free(struct evhttp_con
 	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)
 {
@@ -861,7 +919,7 @@ evhttp_connection_reset(struct evhttp_co
 		if (evcon->state == EVCON_CONNECTED && evcon->closecb != NULL)
 			(*evcon->closecb)(evcon, evcon->closecb_arg);
 
-		close(evcon->fd);
+		EVUTIL_CLOSESOCKET(evcon->fd);
 		evcon->fd = -1;
 	}
 	evcon->state = EVCON_DISCONNECTED;
@@ -886,6 +944,7 @@ evhttp_connection_start_detectclose(stru
 		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);
 }
 
@@ -952,6 +1011,7 @@ evhttp_connectioncb(int fd, short what, 
  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++;
@@ -975,7 +1035,7 @@ evhttp_connectioncb(int fd, short what, 
  * Check if we got a valid response code.
  */
 
-int
+static int
 evhttp_valid_response_code(int code)
 {
 	if (code == 0)
@@ -986,7 +1046,7 @@ evhttp_valid_response_code(int code)
 
 /* Parses the status line of a web server */
 
-int
+static int
 evhttp_parse_response_line(struct evhttp_request *req, char *line)
 {
 	char *protocol;
@@ -1028,7 +1088,7 @@ evhttp_parse_response_line(struct evhttp
 
 /* Parse the first line of a HTTP request */
 
-int
+static int
 evhttp_parse_request_line(struct evhttp_request *req, char *line)
 {
 	char *method;
@@ -1144,10 +1204,12 @@ evhttp_add_header(struct evkeyvalq *head
 {
 	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"));
+		event_debug(("%s: dropping illegal header\n", __func__));
 		return (-1);
 	}
 
@@ -1186,58 +1248,55 @@ evhttp_add_header(struct evkeyvalq *head
 int
 evhttp_parse_lines(struct evhttp_request *req, struct evbuffer* buffer)
 {
-	u_char *endp;
+	char *line;
 	int done = 0;
 
 	struct evkeyvalq* headers = req->input_headers;
-	while ((endp = evbuffer_find(buffer, (u_char *)"\r\n", 2)) != NULL) {
+	while ((line = evbuffer_readline(buffer)) != NULL) {
 		char *skey, *svalue;
 
-		if (strncmp((char *)EVBUFFER_DATA(buffer), "\r\n", 2) == 0) {
-			evbuffer_drain(buffer, 2);
-			/* Last header - Done */
+		if (*line == '\0') { /* Last header - Done */
 			done = 1;
+			free (line);
 			break;
 		}
 
-		*endp = '\0';
-		endp += 2;
-
 		/* Processing of header lines */
 		if (req->got_firstline == 0) {
 			switch (req->kind) {
 			case EVHTTP_REQUEST:
-				if (evhttp_parse_request_line(req,
-					(char *)EVBUFFER_DATA(buffer)) == -1)
-					return (-1);
+				if (evhttp_parse_request_line(req, line) == -1)
+					goto error;
 				break;
 			case EVHTTP_RESPONSE:
-				if (evhttp_parse_response_line(req,
-					(char *)EVBUFFER_DATA(buffer)) == -1)
-					return (-1);
+				if (evhttp_parse_response_line(req, line) == -1)
+					goto error;
 				break;
 			default:
-				return (-1);
+				goto error;
 			}
 			req->got_firstline = 1;
 		} else {
 			/* Regular header */
-			svalue = (char *)EVBUFFER_DATA(buffer);
+			svalue = line;
 			skey = strsep(&svalue, ":");
 			if (svalue == NULL)
-				return (-1);
+				goto error;
 
 			svalue += strspn(svalue, " ");
 
 			if (evhttp_add_header(headers, skey, svalue) == -1)
-				return (-1);
+				goto error;
 		}
 
-		/* Move the uncompleted headers forward */
-		evbuffer_drain(buffer, endp - EVBUFFER_DATA(buffer));
+		free (line);
 	}
 
 	return (done);
+
+ error:
+	free (line);
+	return (-1);
 }
 
 static int
@@ -1263,7 +1322,7 @@ evhttp_get_body_length(struct evhttp_req
 		req->ntoread = -1;
 	} else {
 		char *endp;
-		req->ntoread = strtol(content_length, &endp, 10);
+		req->ntoread = evutil_strtoll(content_length, &endp, 10);
 		if (*content_length == '\0' || *endp != '\0') {
 			event_warnx("%s: illegal content length: %s",
 			    __func__, content_length);
@@ -1423,6 +1482,14 @@ evhttp_connection_new(const char *addres
 	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)
@@ -1464,16 +1531,21 @@ evhttp_connection_connect(struct evhttp_
 	assert(!(evcon->flags & EVHTTP_CON_INCOMING));
 	evcon->flags |= EVHTTP_CON_OUTGOING;
 	
-	/* Do async connection to HTTP server */
-	if ((evcon->fd = make_socket(
-		     0, evcon->address, evcon->port)) == -1) {
-		event_debug(("%s: failed to connect to \"%s:%d\"",
-			__func__, evcon->address, evcon->port));
+	evcon->fd = bind_socket(evcon->bind_address, 0);
+	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;
@@ -1539,11 +1611,12 @@ evhttp_start_read(struct evhttp_connecti
 	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);
 }
 
-void
+static void
 evhttp_send_done(struct evhttp_connection *evcon, void *arg)
 {
 	int need_close;
@@ -1579,12 +1652,12 @@ evhttp_send_done(struct evhttp_connectio
 void
 evhttp_send_error(struct evhttp_request *req, int error, const char *reason)
 {
-	char *fmt = "<HTML><HEAD>\n"
-	    "<TITLE>%d %s</TITLE>\n"
-	    "</HEAD><BODY>\n"
-	    "<H1>Method Not Implemented</H1>\n"
-	    "Invalid method in request<P>\n"
-	    "</BODY></HTML>\n";
+#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();
 
@@ -1593,11 +1666,12 @@ evhttp_send_error(struct evhttp_request 
 
 	evhttp_response_code(req, error, reason);
 
-	evbuffer_add_printf(buf, fmt, 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 */
@@ -1609,7 +1683,7 @@ evhttp_send(struct evhttp_request *req, 
 
 	assert(TAILQ_FIRST(&evcon->requests) == req);
 
-	/* xxx: not sure if we really should expost the data buffer this way */
+	/* xxx: not sure if we really should expose the data buffer this way */
 	if (databuf != NULL)
 		evbuffer_add_buffer(req->output_buffer, databuf);
 	
@@ -1652,9 +1726,12 @@ evhttp_send_reply_chunk(struct evhttp_re
 {
 	if (req->chunked) {
 		evbuffer_add_printf(req->evcon->output_buffer, "%x\r\n",
-		    EVBUFFER_LENGTH(databuf));
+				    (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);
 }
 
@@ -1759,8 +1836,9 @@ evhttp_decode_uri(const char *uri)
 	
 	ret = malloc(strlen(uri) + 1);
 	if (ret == NULL)
-		event_err(1, "%s: malloc(%d)", __func__, strlen(uri) + 1);
-
+		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 == '?') {
@@ -1855,7 +1933,7 @@ evhttp_dispatch_callback(struct httpcbq 
 	return (NULL);
 }
 
-void
+static void
 evhttp_handle_request(struct evhttp_request *req, void *arg)
 {
 	struct evhttp *http = arg;
@@ -1877,25 +1955,26 @@ evhttp_handle_request(struct evhttp_requ
 		return;
 	} else {
 		/* We need to send a 404 here */
-		char *fmt = "<html><head>"
-		    "<title>404 Not Found</title>"
-		    "</head><body>"
-		    "<h1>Not Found</h1>"
-		    "<p>The requested URL %s was not found on this server.</p>"
-		    "</body></html>\n";
+#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, fmt, escaped_html);
+		evbuffer_add_printf(buf, ERR_FORMAT, escaped_html);
 
 		free(escaped_html);
-		
+
 		evhttp_send_page(req, buf);
 
 		evbuffer_free(buf);
+#undef ERR_FORMAT
 	}
 }
 
@@ -1911,28 +1990,30 @@ accept_socket(int fd, short what, void *
 		event_warn("%s: bad accept", __func__);
 		return;
 	}
-        if (event_make_socket_nonblocking(nfd) < 0)
-                return;
+	if (evutil_make_socket_nonblocking(nfd) < 0)
+		return;
 
 	evhttp_get_request(http, nfd, (struct sockaddr *)&ss, addrlen);
 }
 
-static int
-bind_socket(struct evhttp *http, const char *address, u_short port)
+int
+evhttp_bind_socket(struct evhttp *http, const char *address, u_short port)
 {
 	struct event *ev = &http->bind_ev;
 	int fd;
 
-	if ((fd = make_socket(1, address, port)) == -1)
+	if ((fd = bind_socket(address, port)) == -1)
 		return (-1);
 
 	if (listen(fd, 10) == -1) {
 		event_warn("%s: listen", __func__);
+		EVUTIL_CLOSESOCKET(fd);
 		return (-1);
 	}
 
 	/* Schedule the socket for accepting */
 	event_set(ev, fd, EV_READ | EV_PERSIST, accept_socket, http);
+	EVHTTP_BASE_SET(http, ev);
 	event_add(ev, NULL);
 
 	event_debug(("Bound to port %d - Awaiting connections ... ", port));
@@ -1940,14 +2021,10 @@ bind_socket(struct evhttp *http, const c
 	return (0);
 }
 
-/*
- * Start a web server on the specified address and port.
- */
-
-struct evhttp *
-evhttp_start(const char *address, u_short port)
+static struct evhttp*
+evhttp_new_object(void)
 {
-	struct evhttp *http;
+	struct evhttp *http = NULL;
 
 	if ((http = calloc(1, sizeof(struct evhttp))) == NULL) {
 		event_warn("%s: calloc", __func__);
@@ -1959,7 +2036,29 @@ evhttp_start(const char *address, u_shor
 	TAILQ_INIT(&http->callbacks);
 	TAILQ_INIT(&http->connections);
 
-	if (bind_socket(http, address, port) == -1) {
+	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);
 	}
@@ -1976,7 +2075,7 @@ evhttp_free(struct evhttp* http)
 
 	/* Remove the accepting part */
 	event_del(&http->bind_ev);
-	close(fd);
+	EVUTIL_CLOSESOCKET(fd);
 
 	while ((evcon = TAILQ_FIRST(&http->connections)) != NULL) {
 		/* evhttp_connection_free removes the connection */
@@ -2142,6 +2241,7 @@ evhttp_request_uri(struct evhttp_request
 
 static struct evhttp_connection*
 evhttp_get_request_connection(
+	struct evhttp* http,
 	int fd, struct sockaddr *sa, socklen_t salen)
 {
 	struct evhttp_connection *evcon;
@@ -2154,6 +2254,10 @@ evhttp_get_request_connection(
 	/* 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;
 	
@@ -2192,7 +2296,7 @@ evhttp_get_request(struct evhttp *http, 
 {
 	struct evhttp_connection *evcon;
 
-	evcon = evhttp_get_request_connection(fd, sa, salen);
+	evcon = evhttp_get_request_connection(http, fd, sa, salen);
 	if (evcon == NULL)
 		return;
 
@@ -2224,7 +2328,7 @@ addr_from_name(char *address)
         struct addrinfo ai, *aitop;
         int ai_result;
 
-        memset(&ai, 0, sizeof (ai));
+        memset(&ai, 0, sizeof(ai));
         ai.ai_family = AF_INET;
         ai.ai_socktype = SOCK_RAW;
         ai.ai_flags = 0;
@@ -2238,7 +2342,7 @@ addr_from_name(char *address)
 	return (aitop);
 #else
 	assert(0);
-	return NULL; // XXXXX Use gethostbyname, if this function is ever used.
+	return NULL; /* XXXXX Use gethostbyname, if this function is ever used. */
 #endif
 }
 #endif
@@ -2248,6 +2352,7 @@ name_from_addr(struct sockaddr *sa, sock
     char **phost, char **pport)
 {
 #ifdef HAVE_GETNAMEINFO
+	/* XXXX not threadsafe. */
 	static char ntop[NI_MAXHOST];
 	static char strport[NI_MAXSERV];
 	int ni_result;
@@ -2264,16 +2369,15 @@ name_from_addr(struct sockaddr *sa, sock
 	*phost = ntop;
 	*pport = strport;
 #else
-	// XXXX
+	/* XXXX */
 #endif
 }
 
 /* Either connect or bind */
 
 static int
-make_socket_ai(int should_bind, struct addrinfo *ai)
+bind_socket_ai(struct addrinfo *ai)
 {
-        struct linger linger;
         int fd, on = 1, r;
 	int serrno;
 
@@ -2284,7 +2388,7 @@ make_socket_ai(int should_bind, struct a
                 return (-1);
         }
 
-        if (event_make_socket_nonblocking(fd) < 0)
+        if (evutil_make_socket_nonblocking(fd) < 0)
                 goto out;
 
 #ifndef WIN32
@@ -2296,67 +2400,68 @@ make_socket_ai(int should_bind, struct a
 
         setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
         setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
-        linger.l_onoff = 1;
-        linger.l_linger = 5;
-        setsockopt(fd, SOL_SOCKET, SO_LINGER, (void *)&linger, sizeof(linger));
-
-	if (should_bind)
-		r = bind(fd, ai->ai_addr, ai->ai_addrlen);
-	else
-		r = connect(fd, ai->ai_addr, ai->ai_addrlen);
-	if (r == -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
-	}
+
+	r = bind(fd, ai->ai_addr, ai->ai_addrlen);
+	if (r == -1)
+		goto out;
 
 	return (fd);
 
  out:
-	serrno = errno;
-	close(fd);
-	errno = serrno;
+	serrno = EVUTIL_SOCKET_ERROR();
+	EVUTIL_CLOSESOCKET(fd);
+	EVUTIL_SET_SOCKET_ERROR(serrno);
 	return (-1);
 }
 
-static int
-make_socket(int should_bind, const char *address, u_short port)
+static struct addrinfo *
+make_addrinfo(const char *address, u_short port)
 {
-	int fd;
-        struct addrinfo ai, *aitop = NULL;
+        struct addrinfo *aitop = NULL;
+
 #ifdef HAVE_GETADDRINFO
+        struct addrinfo ai;
         char strport[NI_MAXSERV];
         int ai_result;
 
-        memset(&ai, 0, sizeof (ai));
+        memset(&ai, 0, sizeof(ai));
         ai.ai_family = AF_INET;
         ai.ai_socktype = SOCK_STREAM;
-        ai.ai_flags = should_bind ? AI_PASSIVE : 0;
-        snprintf(strport, sizeof (strport), "%d", port);
+        ai.ai_flags = AI_PASSIVE;  /* turn NULL host name into INADDR_ANY */
+        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 (-1);
+		return (NULL);
         }
 #else
-	if (fake_getaddrinfo(address, &ai) < 0) {
+	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 (-1);
+		return (NULL);
 	}
-	aitop = &ai;
+	aitop = &ai[cur];
+	((struct sockaddr_in *) aitop->ai_addr)->sin_port = htons(port);
 #endif
 
-	fd = make_socket_ai(should_bind, aitop);
+	return (aitop);
+}
+
+static int
+bind_socket(const char *address, u_short port)
+{
+	int fd;
+	struct addrinfo *aitop = make_addrinfo(address, port);
+
+	if (aitop == NULL)
+		return (-1);
+
+	fd = bind_socket_ai(aitop);
 
 #ifdef HAVE_GETADDRINFO
 	freeaddrinfo(aitop);
@@ -2365,4 +2470,43 @@ make_socket(int should_bind, const char 
 #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);
 }
diff -Nrup a/extra/libevent/kqueue.c b/extra/libevent/kqueue.c
--- a/extra/libevent/kqueue.c	2007-11-15 19:06:15 -02:00
+++ b/extra/libevent/kqueue.c	2008-04-28 14:52:15 -03:00
@@ -51,16 +51,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
 
@@ -72,27 +74,27 @@ struct kqop {
 	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;
@@ -115,6 +117,8 @@ kq_init(struct event_base *base)
 
 	kqueueop->kq = kq;
 
+	kqueueop->pid = getpid();
+
 	/* Initalize fields */
 	kqueueop->changes = malloc(NEVENT * sizeof(struct kevent));
 	if (kqueueop->changes == NULL) {
@@ -153,13 +157,7 @@ kq_init(struct event_base *base)
 	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;
@@ -210,7 +208,7 @@ kq_sighandler(int sig)
 	/* Do nothing here */
 }
 
-int
+static int
 kq_dispatch(struct event_base *base, void *arg, struct timeval *tv)
 {
 	struct kqop *kqop = arg;
@@ -277,7 +275,7 @@ kq_dispatch(struct event_base *base, voi
 			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);
@@ -287,7 +285,7 @@ kq_dispatch(struct event_base *base, voi
 }
 
 
-int
+static int
 kq_add(void *arg, struct event *ev)
 {
 	struct kqop *kqop = arg;
@@ -295,6 +293,7 @@ kq_add(void *arg, struct event *ev)
 
 	if (ev->ev_events & EV_SIGNAL) {
 		int nsignal = EVENT_SIGNAL(ev);
+                struct timespec timeout = { 0, 0 };
 
  		memset(&kev, 0, sizeof(kev));
 		kev.ident = nsignal;
@@ -303,11 +302,14 @@ kq_add(void *arg, struct event *ev)
 		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;
@@ -351,7 +353,7 @@ kq_add(void *arg, struct event *ev)
 	return (0);
 }
 
-int
+static int
 kq_del(void *arg, struct event *ev)
 {
 	struct kqop *kqop = arg;
@@ -371,7 +373,7 @@ kq_del(void *arg, struct event *ev)
 		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;
@@ -405,7 +407,7 @@ kq_del(void *arg, struct event *ev)
 	return (0);
 }
 
-void
+static void
 kq_dealloc(struct event_base *base, void *arg)
 {
 	struct kqop *kqop = arg;
@@ -414,7 +416,7 @@ kq_dealloc(struct event_base *base, void
 		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);
diff -Nrup a/extra/libevent/log.c b/extra/libevent/log.c
--- a/extra/libevent/log.c	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/log.c	2008-04-28 14:52:15 -03:00
@@ -48,7 +48,6 @@
 #include "misc.h"
 #endif
 #include <sys/types.h>
-#include <sys/tree.h>
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #else
diff -Nrup a/extra/libevent/log.h b/extra/libevent/log.h
--- a/extra/libevent/log.h	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/log.h	2008-04-28 14:52:15 -03:00
@@ -27,17 +27,25 @@
 #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
 #else
 #define event_debug(x) do {;} while (0)
 #endif
+
+#undef EV_CHECK_FMT
 
 #endif
diff -Nrup a/extra/libevent/min_heap.h b/extra/libevent/min_heap.h
--- /dev/null	Wed Dec 31 16:00:00 196900
+++ b/extra/libevent/min_heap.h	2008-04-28 14:52:16 -03:00
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2006 Maxim Yegorushkin <maxim.yegorushkin@stripped>
+ * 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"
+
+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 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;
+        e->min_heap_idx = -1;
+        min_heap_shift_down_(s, 0u, s->p[--s->n]);
+        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_ */
diff -Nrup a/extra/libevent/poll.c b/extra/libevent/poll.c
--- a/extra/libevent/poll.c	2007-11-15 19:06:15 -02:00
+++ b/extra/libevent/poll.c	2008-04-28 14:52:15 -03:00
@@ -39,7 +39,6 @@
 #include <sys/_time.h>
 #endif
 #include <sys/queue.h>
-#include <sys/tree.h>
 #include <poll.h>
 #include <signal.h>
 #include <stdio.h>
@@ -68,24 +67,23 @@ struct pollop {
 			      * "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;
@@ -102,17 +100,6 @@ poll_init(struct event_base *base)
 	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)
@@ -147,7 +134,7 @@ poll_check_ok(struct pollop *pop)
 #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;
@@ -201,13 +188,9 @@ poll_dispatch(struct event_base *base, v
 			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);
 		}
 	}
@@ -215,7 +198,7 @@ poll_dispatch(struct event_base *base, v
 	return (0);
 }
 
-int
+static int
 poll_add(void *arg, struct event *ev)
 {
 	struct pollop *pop = arg;
@@ -320,7 +303,7 @@ poll_add(void *arg, struct event *ev)
  * Nothing to be done here.
  */
 
-int
+static int
 poll_del(void *arg, struct event *ev)
 {
 	struct pollop *pop = arg;
@@ -373,7 +356,7 @@ poll_del(void *arg, struct event *ev)
 	return (0);
 }
 
-void
+static void
 poll_dealloc(struct event_base *base, void *arg)
 {
 	struct pollop *pop = arg;
diff -Nrup a/extra/libevent/select.c b/extra/libevent/select.c
--- a/extra/libevent/select.c	2007-11-15 19:06:15 -02:00
+++ b/extra/libevent/select.c	2008-04-28 14:52:15 -03:00
@@ -42,7 +42,6 @@
 #include <sys/select.h>
 #endif
 #include <sys/queue.h>
-#include <sys/tree.h>
 #include <signal.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -73,26 +72,25 @@ struct selectop {
 	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;
@@ -138,22 +136,7 @@ check_selectop(struct selectop *sop)
 #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;
@@ -198,13 +181,9 @@ select_dispatch(struct event_base *base,
 			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);
 		}
 	}
@@ -273,7 +252,7 @@ select_resize(struct selectop *sop, int 
 }
 
 
-int
+static int
 select_add(void *arg, struct event *ev)
 {
 	struct selectop *sop = arg;
@@ -323,7 +302,7 @@ select_add(void *arg, struct event *ev)
  * Nothing to be done here.
  */
 
-int
+static int
 select_del(void *arg, struct event *ev)
 {
 	struct selectop *sop = arg;
@@ -351,7 +330,7 @@ select_del(void *arg, struct event *ev)
 	return (0);
 }
 
-void
+static void
 select_dealloc(struct event_base *base, void *arg)
 {
 	struct selectop *sop = arg;
diff -Nrup a/extra/libevent/signal.c b/extra/libevent/signal.c
--- a/extra/libevent/signal.c	2007-11-01 16:37:50 -02:00
+++ b/extra/libevent/signal.c	2008-04-28 14:52:15 -03:00
@@ -30,20 +30,27 @@
 #include "config.h"
 #endif
 
+#ifdef WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <winsock2.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 @@ static void
 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 @@ evsignal_init(struct event_base *base)
 	 * 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 @@ evsignal_handler(int sig)
 
 	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_handler(int sig)
 	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 @@ evsignal_dealloc(struct event_base *base
 	}
 	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);
 }
Thread
bk commit into 6.0 tree (davi:1.2632)Davi Arnaut28 Apr
  • Re: bk commit into 6.0 tree (davi:1.2632)Konstantin Osipov28 Apr
    • Adding new source files (was: Re: bk commit into 6.0 tree (davi:1.2632))Joerg Bruehe9 May