tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Diff for libevent 1.4.11



The following diff brings NetBSD's libevent 1.4.4 into sync with 1.4.11,
retaining the minor changes present when Niels originally checked it into
NetBSD and when it was previously updated, mostly unifdef WIN32.

Comments much appreciated.  I don't use most of the more complicated
functionality in libevent so I'd appreciate results from anyone who does.

I will eventually upgrade us to libevent-2 at which point I'll start
fresh in src/external -- but not just now.

Thor

Index: Makefile
===================================================================
RCS file: /cvsroot/src/lib/libevent/Makefile,v
retrieving revision 1.4
diff -u -r1.4 Makefile
--- Makefile    16 May 2008 20:24:57 -0000      1.4
+++ Makefile    8 Jul 2009 04:47:37 -0000
@@ -4,7 +4,7 @@
 NOLINT=                # Until someone explains to me how to avoid lint 
stupidity
 USE_SHLIBDIR=  yes
 
-CPPFLAGS+=-DHAVE_CONFIG_H -I${.CURDIR}
+CPPFLAGS+=-I${.CURDIR}
 .include <bsd.own.mk>
 
 LIB=   event
Index: buffer.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/buffer.c,v
retrieving revision 1.4
diff -u -r1.4 buffer.c
--- buffer.c    16 May 2008 20:24:57 -0000      1.4
+++ buffer.c    8 Jul 2009 04:47:37 -0000
@@ -26,10 +26,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
 #include <sys/types.h>
 #include <sys/time.h>
 #include <sys/ioctl.h>
@@ -43,6 +39,8 @@
 #include <unistd.h>
 
 #include "event.h"
+#include "config.h"
+#include "evutil.h"
 
 struct evbuffer *
 evbuffer_new(void)
@@ -131,13 +129,13 @@
 
                va_copy(aq, ap);
 
-               sz = vsnprintf(buffer, space, fmt, aq);
+               sz = evutil_vsnprintf(buffer, space, fmt, aq);
 
                va_end(aq);
 
                if (sz < 0)
                        return (-1);
-               if (sz < space) {
+               if ((size_t)sz < space) {
                        buf->off += sz;
                        if (buf->cb != NULL)
                                (*buf->cb)(buf, oldoff, buf->off, buf->cbarg);
@@ -340,7 +338,7 @@
                 * about it.  If the reader does not tell us how much
                 * data we should read, we artifically limit it.
                 */
-               if (n > buf->totallen << 2)
+               if ((size_t)n > buf->totallen << 2)
                        n = buf->totallen << 2;
                if (n < EVBUFFER_MAX_READ)
                        n = EVBUFFER_MAX_READ;
Index: config.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/config.h,v
retrieving revision 1.3
diff -u -r1.3 config.h
--- config.h    16 May 2008 20:24:57 -0000      1.3
+++ config.h    8 Jul 2009 04:47:37 -0000
@@ -227,7 +227,7 @@
 #define TIME_WITH_SYS_TIME 1
 
 /* Version number of package */
-#define VERSION "1.4.4-stable"
+#define VERSION "1.4.11-stable"
 
 /* Define to `int' if <sys/types.h> does not define. */
 /* #undef pid_t */
Index: evbuffer.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/evbuffer.c,v
retrieving revision 1.4
diff -u -r1.4 evbuffer.c
--- evbuffer.c  16 May 2008 20:24:57 -0000      1.4
+++ evbuffer.c  8 Jul 2009 04:47:37 -0000
@@ -389,6 +389,11 @@
     int timeout_read, int timeout_write) {
        bufev->timeout_read = timeout_read;
        bufev->timeout_write = timeout_write;
+
+       if (event_pending(&bufev->ev_read, EV_READ, NULL))
+               bufferevent_add(&bufev->ev_read, timeout_read);
+       if (event_pending(&bufev->ev_write, EV_WRITE, NULL))
+               bufferevent_add(&bufev->ev_write, timeout_write);
 }
 
 /*
Index: evdns.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/evdns.c,v
retrieving revision 1.2
diff -u -r1.2 evdns.c
--- evdns.c     26 Jan 2009 15:09:56 -0000      1.2
+++ evdns.c     8 Jul 2009 04:47:39 -0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: evdns.c,v 1.2 2009/01/26 15:09:56 christos Exp $ */
+/*     $NetBSD: evdns.c,v 1.1.8.1 2009/02/01 23:46:53 snj Exp $ */
 
 /* The original version of this module was written by Adam Langley; for
  * a history of modifications, check out the subversion logs.
@@ -35,9 +35,7 @@
  */
 
 #include <sys/types.h>
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #ifdef DNS_USE_FTIME_FOR_ID
 #include <sys/timeb.h>
@@ -334,7 +332,7 @@
 {
        static char buf[32];
        u32 a = ntohl(address);
-       snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
+       evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d",
                       (int)(u8)((a>>24)&0xff),
                       (int)(u8)((a>>16)&0xff),
                       (int)(u8)((a>>8 )&0xff),
@@ -365,7 +363,7 @@
   if (!evdns_log_fn)
     return;
   va_start(args,fmt);
-  vsnprintf(buf, sizeof(buf), fmt, args);
+  evutil_vsnprintf(buf, sizeof(buf), fmt, args);
   buf[sizeof(buf)-1] = '\0';
   evdns_log_fn(warn, buf);
   va_end(args);
@@ -630,7 +628,10 @@
 static void
 reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply 
*reply) {
        int error;
-       static const int error_codes[] = {DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, 
DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED};
+       static const int error_codes[] = {
+               DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST,
+               DNS_ERR_NOTIMPL, DNS_ERR_REFUSED
+       };
 
        if (flags & 0x020f || !reply || !reply->have_answer) {
                /* there was an error */
@@ -651,16 +652,18 @@
                        /* we regard these errors as marking a bad nameserver */
                        if (req->reissue_count < global_max_reissues) {
                                char msg[64];
-                               snprintf(msg, sizeof(msg), "Bad response %d 
(%s)",
+                               evutil_snprintf(msg, sizeof(msg),
+                                   "Bad response %d (%s)",
                                         error, evdns_err_to_string(error));
                                nameserver_failed(req->ns, msg);
                                if (!request_reissue(req)) return;
                        }
                        break;
                case DNS_ERR_SERVERFAILED:
-                       /* rcode 2 (servfailed) sometimes means "we are broken" 
and
-                        * sometimes (with some binds) means "that request was 
very
-                        * confusing."  Treat this as a timeout, not a failure. 
+                       /* rcode 2 (servfailed) sometimes means "we
+                        * are broken" and sometimes (with some binds)
+                        * means "that request was very confusing."
+                        * Treat this as a timeout, not a failure.
                         */
                        log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from 
nameserver %s; "
                                "will allow the request to time out.",
@@ -672,10 +675,13 @@
                }
 
                if (req->search_state && req->request_type != TYPE_PTR) {
-                       /* if we have a list of domains to search in, try the 
next one */
+                       /* if we have a list of domains to search in,
+                        * try the next one */
                        if (!search_try_next(req)) {
-                               /* a new request was issued so this request is 
finished and */
-                               /* the user callback will be made when that 
request (or a */
+                               /* a new request was issued so this
+                                * request is finished and */
+                               /* the user callback will be made when
+                                * that request (or a */
                                /* child of it) finishes. */
                                request_finished(req, &req_head);
                                return;
@@ -752,10 +758,10 @@
 /* parses a raw request from a nameserver */
 static int
 reply_parse(u8 *packet, int length) {
-       int j = 0;  /* index into packet */
+       int j = 0, k = 0;  /* index into packet */
        u16 _t;  /* used by the macros */
        u32 _t32;  /* used by the macros */
-       char tmp_name[256]; /* used by the macros */
+       char tmp_name[256], cmp_name[256]; /* used by the macros */
 
        u16 trans_id, questions, answers, authority, additional, datalength;
         u16 flags = 0;
@@ -788,10 +794,21 @@
 
        /* This macro skips a name in the DNS reply. */
 #define SKIP_NAME \
-       do { tmp_name[0] = '\0';                                        \
-               if (name_parse(packet, length, &j, tmp_name, 
sizeof(tmp_name))<0) \
-                       goto err;                                               
                                                        \
-       } while(0);
+       do { tmp_name[0] = '\0';                                \
+               if (name_parse(packet, length, &j, tmp_name, 
sizeof(tmp_name))<0)\
+                       goto err;                               \
+       } while(0)
+#define TEST_NAME \
+       do { tmp_name[0] = '\0';                                \
+               cmp_name[0] = '\0';                             \
+               k = j;                                          \
+               if (name_parse(packet, length, &j, tmp_name, 
sizeof(tmp_name))<0)\
+                       goto err;                                       \
+               if (name_parse(req->request, req->request_len, &k, cmp_name, 
sizeof(cmp_name))<0)       \
+                       goto err;                               \
+               if (memcmp(tmp_name, cmp_name, strlen (tmp_name)) != 0) \
+                       return (-1); /* we ignore mismatching names */  \
+       } while(0)
 
        reply.type = req->request_type;
 
@@ -800,7 +817,7 @@
                /* the question looks like
                 *   <label:name><u16:type><u16:class>
                 */
-               SKIP_NAME;
+               TEST_NAME;
                j += 4;
                if (j > length) goto err;
        }
@@ -974,12 +991,16 @@
        u16 trans_id;
 #ifdef DNS_USE_CPU_CLOCK_FOR_ID
        struct timespec ts;
+       static int clkid = -1;
+       if (clkid == -1) {
+               clkid = CLOCK_REALTIME;
 #ifdef CLOCK_MONOTONIC
-       if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
-#else
-       if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
+               if (clock_gettime(CLOCK_MONOTONIC, &ts) != -1)
+                       clkid = CLOCK_MONOTONIC;
 #endif
-       event_err(1, "clock_gettime");
+       }
+       if (clock_gettime(clkid, &ts) == -1)
+               event_err(1, "clock_gettime");
        trans_id = ts.tv_nsec & 0xffff;
 #endif
 
@@ -1509,7 +1530,7 @@
        assert(!(in && inaddr_name));
        if (in) {
                a = ntohl(in->s_addr);
-               snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+               evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
                                (int)(u8)((a    )&0xff),
                                (int)(u8)((a>>8 )&0xff),
                                (int)(u8)((a>>16)&0xff),
@@ -1526,7 +1547,7 @@
 evdns_server_request_add_cname_reply(struct evdns_server_request *req, const 
char *name, const char *cname, int ttl)
 {
        return evdns_server_request_add_reply(
-                 req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
+                 req, EVDNS_ANSWER_SECTION, name, TYPE_CNAME, CLASS_INET,
                  ttl, -1, 1, cname);
 }
 
@@ -2222,13 +2243,13 @@
        }
 }
 
-int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type 
callback, void *ptr) {
+int evdns_resolve_reverse(const struct in_addr *in, int flags, 
evdns_callback_type callback, void *ptr) {
        char buf[32];
        struct request *req;
        u32 a;
        assert(in);
        a = ntohl(in->s_addr);
-       snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
+       evutil_snprintf(buf, sizeof(buf), "%d.%d.%d.%d.in-addr.arpa",
                        (int)(u8)((a    )&0xff),
                        (int)(u8)((a>>8 )&0xff),
                        (int)(u8)((a>>16)&0xff),
@@ -2240,7 +2261,7 @@
        return 0;
 }
 
-int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, 
evdns_callback_type callback, void *ptr) {
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, 
evdns_callback_type callback, void *ptr) {
        /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */
        char buf[73];
        char *cp;
Index: evdns.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/evdns.h,v
retrieving revision 1.1
diff -u -r1.1 evdns.h
--- evdns.h     16 May 2008 20:24:57 -0000      1.1
+++ evdns.h     8 Jul 2009 04:47:39 -0000
@@ -346,7 +346,7 @@
   @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);
+int evdns_resolve_reverse(const struct in_addr *in, int flags, 
evdns_callback_type callback, void *ptr);
 
 
 /**
@@ -359,7 +359,7 @@
   @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);
+int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, 
evdns_callback_type callback, void *ptr);
 
 
 /**
Index: event.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/event.c,v
retrieving revision 1.9
diff -u -r1.9 event.c
--- event.c     16 May 2008 20:24:57 -0000      1.9
+++ event.c     8 Jul 2009 04:47:39 -0000
@@ -30,9 +30,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <sys/types.h>
 #ifdef HAVE_SYS_TIME_H
@@ -69,7 +67,7 @@
 #endif
 
 /* In order of preference */
-const struct eventop *eventops[] = {
+static const struct eventop *eventops[] = {
 #ifdef HAVE_EVENT_PORTS
        &evportops,
 #endif
@@ -168,7 +166,6 @@
        
        min_heap_ctor(&base->timeheap);
        TAILQ_INIT(&base->eventqueue);
-       TAILQ_INIT(&base->sig.signalqueue);
        base->sig.ev_signal_pair[0] = -1;
        base->sig.ev_signal_pair[1] = -1;
        
@@ -219,9 +216,20 @@
                ++n_deleted;
        }
 
+       for (i = 0; i < base->nactivequeues; ++i) {
+               for (ev = TAILQ_FIRST(base->activequeues[i]); ev; ) {
+                       struct event *next = TAILQ_NEXT(ev, ev_active_next);
+                       if (!(ev->ev_flags & EVLIST_INTERNAL)) {
+                               event_del(ev);
+                               ++n_deleted;
+                       }
+                       ev = next;
+               }
+       }
+
        if (n_deleted)
                event_debug(("%s: %d events were still set in base",
-                                        __func__, n_deleted));
+                       __func__, n_deleted));
 
        if (base->evsel->dealloc != NULL)
                base->evsel->dealloc(base, base->evbase);
@@ -254,6 +262,17 @@
        if (!evsel->need_reinit)
                return (0);
 
+       if (base->sig.ev_signal_added) {
+               /* we cannot call event_del here because the base has
+                * not been reinitialized yet. */
+               event_queue_remove(base, &base->sig.ev_signal,
+                   EVLIST_INSERTED);
+               if (base->sig.ev_signal.ev_flags & EVLIST_ACTIVE)
+                       event_queue_remove(base, &base->sig.ev_signal,
+                           EVLIST_ACTIVE);
+               base->sig.ev_signal_added = 0;
+       }
+
        if (base->evsel->dealloc != NULL)
                base->evsel->dealloc(base, base->evbase);
        evbase = base->evbase = evsel->init(base);
@@ -387,14 +406,14 @@
 
 /* not thread safe */
 int
-event_loopexit(struct timeval *tv)
+event_loopexit(const struct timeval *tv)
 {
        return (event_once(-1, EV_TIMEOUT, event_loopexit_cb,
                    current_base, tv));
 }
 
 int
-event_base_loopexit(struct event_base *event_base, struct timeval *tv)
+event_base_loopexit(struct event_base *event_base, const struct timeval *tv)
 {
        return (event_base_once(event_base, -1, EV_TIMEOUT, event_loopexit_cb,
                    event_base, tv));
@@ -436,7 +455,10 @@
        struct timeval *tv_p;
        int res, done;
 
-       if(!TAILQ_EMPTY(&base->sig.signalqueue))
+       /* clear time cache */
+       base->tv_cache.tv_sec = 0;
+
+       if (base->sig.ev_signal_added)
                evsignal_base = base;
        done = 0;
        while (!done) {
@@ -504,6 +526,9 @@
                        done = 1;
        }
 
+       /* clear time cache */
+       base->tv_cache.tv_sec = 0;
+
        event_debug(("%s: asked to terminate loop.", __func__));
        return (0);
 }
@@ -531,7 +556,7 @@
 /* not threadsafe, event scheduled once. */
 int
 event_once(int fd, short events,
-    void (*callback)(int, short, void *), void *arg, struct timeval *tv)
+    void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
 {
        return event_base_once(current_base, fd, events, callback, arg, tv);
 }
@@ -539,7 +564,7 @@
 /* Schedules an event once */
 int
 event_base_once(struct event_base *base, int fd, short events,
-    void (*callback)(int, short, void *), void *arg, struct timeval *tv)
+    void (*callback)(int, short, void *), void *arg, const struct timeval *tv)
 {
        struct event_once *eonce;
        struct timeval etv;
@@ -648,13 +673,11 @@
        int flags = 0;
 
        if (ev->ev_flags & EVLIST_INSERTED)
-               flags |= (ev->ev_events & (EV_READ|EV_WRITE));
+               flags |= (ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL));
        if (ev->ev_flags & EVLIST_ACTIVE)
                flags |= ev->ev_res;
        if (ev->ev_flags & EVLIST_TIMEOUT)
                flags |= EV_TIMEOUT;
-       if (ev->ev_flags & EVLIST_SIGNAL)
-               flags |= EV_SIGNAL;
 
        event &= (EV_TIMEOUT|EV_READ|EV_WRITE|EV_SIGNAL);
 
@@ -671,11 +694,12 @@
 }
 
 int
-event_add(struct event *ev, struct timeval *tv)
+event_add(struct event *ev, const struct timeval *tv)
 {
        struct event_base *base = ev->ev_base;
        const struct eventop *evsel = base->evsel;
        void *evbase = base->evbase;
+       int res = 0;
 
        event_debug((
                 "event_add: event: %p, %s%s%scall %p",
@@ -687,14 +711,36 @@
 
        assert(!(ev->ev_flags & ~EVLIST_ALL));
 
-       if (tv != NULL) {
+       /*
+        * prepare for timeout insertion further below, if we get a
+        * failure on any step, we should not change any state.
+        */
+       if (tv != NULL && !(ev->ev_flags & EVLIST_TIMEOUT)) {
+               if (min_heap_reserve(&base->timeheap,
+                       1 + min_heap_size(&base->timeheap)) == -1)
+                       return (-1);  /* ENOMEM == errno */
+       }
+
+       if ((ev->ev_events & (EV_READ|EV_WRITE|EV_SIGNAL)) &&
+           !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
+               res = evsel->add(evbase, ev);
+               if (res != -1)
+                       event_queue_insert(base, ev, EVLIST_INSERTED);
+       }
+
+       /* 
+        * we should change the timout state only if the previous event
+        * addition succeeded.
+        */
+       if (res != -1 && tv != NULL) {
                struct timeval now;
 
+               /* 
+                * we already reserved memory above for the case where we
+                * are not replacing an exisiting timeout.
+                */
                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
@@ -716,29 +762,13 @@
                evutil_timeradd(&now, tv, &ev->ev_timeout);
 
                event_debug((
-                        "event_add: timeout in %d seconds, call %p",
+                        "event_add: timeout in %ld seconds, call %p",
                         tv->tv_sec, ev->ev_callback));
 
                event_queue_insert(base, ev, EVLIST_TIMEOUT);
        }
 
-       if ((ev->ev_events & (EV_READ|EV_WRITE)) &&
-           !(ev->ev_flags & (EVLIST_INSERTED|EVLIST_ACTIVE))) {
-               int res = evsel->add(evbase, ev);
-               if (res != -1)
-                       event_queue_insert(base, ev, EVLIST_INSERTED);
-
-               return (res);
-       } else if ((ev->ev_events & EV_SIGNAL) &&
-           !(ev->ev_flags & EVLIST_SIGNAL)) {
-               int res = evsel->add(evbase, ev);
-               if (res != -1)
-                       event_queue_insert(base, ev, EVLIST_SIGNAL);
-
-               return (res);
-       }
-
-       return (0);
+       return (res);
 }
 
 int
@@ -776,9 +806,6 @@
        if (ev->ev_flags & EVLIST_INSERTED) {
                event_queue_remove(base, ev, EVLIST_INSERTED);
                return (evsel->del(evbase, ev));
-       } else if (ev->ev_flags & EVLIST_SIGNAL) {
-               event_queue_remove(base, ev, EVLIST_SIGNAL);
-               return (evsel->del(evbase, ev));
        }
 
        return (0);
@@ -825,7 +852,7 @@
        assert(tv->tv_sec >= 0);
        assert(tv->tv_usec >= 0);
 
-       event_debug(("timeout_next: in %d seconds", tv->tv_sec));
+       event_debug(("timeout_next: in %ld seconds", tv->tv_sec));
        return (0);
 }
 
@@ -915,9 +942,6 @@
        case EVLIST_TIMEOUT:
                min_heap_erase(&base->timeheap, ev);
                break;
-       case EVLIST_SIGNAL:
-               TAILQ_REMOVE(&base->sig.signalqueue, ev, ev_signal_next);
-               break;
        default:
                event_errx(1, "%s: unknown queue %x", __func__, queue);
        }
@@ -952,9 +976,6 @@
                min_heap_push(&base->timeheap, ev);
                break;
        }
-       case EVLIST_SIGNAL:
-               TAILQ_INSERT_TAIL(&base->sig.signalqueue, ev, ev_signal_next);
-               break;
        default:
                event_errx(1, "%s: unknown queue %x", __func__, queue);
        }
Index: event.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/event.h,v
retrieving revision 1.5
diff -u -r1.5 event.h
--- event.h     16 May 2008 20:24:58 -0000      1.5
+++ event.h     8 Jul 2009 04:47:40 -0000
@@ -391,7 +391,7 @@
   @return 0 if successful, or -1 if an error occurred
   @see event_loop(), event_base_loop(), event_base_loopexit()
   */
-int event_loopexit(struct timeval *);
+int event_loopexit(const struct timeval *);
 
 
 /**
@@ -408,7 +408,7 @@
   @return 0 if successful, or -1 if an error occurred
   @see event_loopexit()
  */
-int event_base_loopexit(struct event_base *, struct timeval *);
+int event_base_loopexit(struct event_base *, const struct timeval *);
 
 /**
   Abort the active event_loop() immediately.
@@ -550,7 +550,8 @@
   @see event_set()
 
  */
-int event_once(int, short, void (*)(int, short, void *), void *, struct 
timeval *);
+int event_once(int, short, void (*)(int, short, void *), void *,
+    const struct timeval *);
 
 
 /**
@@ -571,7 +572,9 @@
   @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 *);
+int event_base_once(struct event_base *base, int fd, short events,
+    void (*callback)(int, short, void *), void *arg,
+    const struct timeval *timeout);
 
 
 /**
@@ -592,7 +595,7 @@
   @return 0 if successful, or -1 if an error occurred
   @see event_del(), event_set()
   */
-int event_add(struct event *, struct timeval *);
+int event_add(struct event *ev, const struct timeval *timeout);
 
 
 /**
@@ -622,7 +625,7 @@
   @return 1 if the event is pending, or 0 if the event has not occurred
 
  */
-int event_pending(struct event *, short, struct timeval *);
+int event_pending(struct event *ev, short event, struct timeval *tv);
 
 
 /**
@@ -1053,7 +1056,6 @@
 
   @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);
 
Index: event_tagging.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/event_tagging.c,v
retrieving revision 1.1
diff -u -r1.1 event_tagging.c
--- event_tagging.c     16 May 2008 20:24:58 -0000      1.1
+++ event_tagging.c     8 Jul 2009 04:47:40 -0000
@@ -26,9 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #ifdef HAVE_SYS_TYPES_H
 #include <sys/types.h>
Index: evhttp.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/evhttp.h,v
retrieving revision 1.1
diff -u -r1.1 evhttp.h
--- evhttp.h    16 May 2008 20:24:58 -0000      1.1
+++ evhttp.h    8 Jul 2009 04:47:40 -0000
@@ -210,7 +210,6 @@
        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 */
 
@@ -262,6 +261,10 @@
 void evhttp_connection_set_local_address(struct evhttp_connection *evcon,
     const char *address);
 
+/** sets the local port from which http connections are made */
+void evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+    unsigned short port);
+
 /** Sets the timeout for events related to this connection */
 void evhttp_connection_set_timeout(struct evhttp_connection *evcon,
     int timeout_in_secs);
@@ -326,10 +329,20 @@
 
 /**
  * Helper function to parse out arguments in a query.
- * The arguments are separated by key and value.
- * URI should already be decoded.
+ *
+ * Parsing a uri like
+ *
+ *    http://foo.com/?q=test&s=some+thing
+ *
+ * will result in two entries in the key value queue.
+
+ * The first entry is: key="q", value="test"
+ * The second entry is: key="s", value="some thing"
+ *
+ * @param uri the request URI
+ * @param headers the head of the evkeyval queue
  */
-void evhttp_parse_query(const char *uri, struct evkeyvalq *);
+void evhttp_parse_query(const char *uri, struct evkeyvalq *headers);
 
 
 /**
Index: evrpc.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/evrpc.c,v
retrieving revision 1.1
diff -u -r1.1 evrpc.c
--- evrpc.c     16 May 2008 20:24:58 -0000      1.1
+++ evrpc.c     8 Jul 2009 04:47:41 -0000
@@ -25,9 +25,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <sys/types.h>
 #include <sys/socket.h>
@@ -78,10 +76,10 @@
                assert(evrpc_unregister_rpc(base, rpc->uri));
        }
        while ((hook = TAILQ_FIRST(&base->input_hooks)) != NULL) {
-               assert(evrpc_remove_hook(base, INPUT, hook));
+               assert(evrpc_remove_hook(base, EVRPC_INPUT, hook));
        }
        while ((hook = TAILQ_FIRST(&base->output_hooks)) != NULL) {
-               assert(evrpc_remove_hook(base, OUTPUT, hook));
+               assert(evrpc_remove_hook(base, EVRPC_OUTPUT, hook));
        }
        free(base);
 }
@@ -96,14 +94,14 @@
        struct evrpc_hook_list *head = NULL;
        struct evrpc_hook *hook = NULL;
        switch (hook_type) {
-       case INPUT:
+       case EVRPC_INPUT:
                head = &base->in_hooks;
                break;
-       case OUTPUT:
+       case EVRPC_OUTPUT:
                head = &base->out_hooks;
                break;
        default:
-               assert(hook_type == INPUT || hook_type == OUTPUT);
+               assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
        }
 
        hook = calloc(1, sizeof(struct evrpc_hook));
@@ -141,14 +139,14 @@
        struct _evrpc_hooks *base = vbase;
        struct evrpc_hook_list *head = NULL;
        switch (hook_type) {
-       case INPUT:
+       case EVRPC_INPUT:
                head = &base->in_hooks;
                break;
-       case OUTPUT:
+       case EVRPC_OUTPUT:
                head = &base->out_hooks;
                break;
        default:
-               assert(hook_type == INPUT || hook_type == OUTPUT);
+               assert(hook_type == EVRPC_INPUT || hook_type == EVRPC_OUTPUT);
        }
 
        return (evrpc_remove_hook_internal(head, handle));
@@ -414,11 +412,11 @@
        }
 
        while ((hook = TAILQ_FIRST(&pool->input_hooks)) != NULL) {
-               assert(evrpc_remove_hook(pool, INPUT, hook));
+               assert(evrpc_remove_hook(pool, EVRPC_INPUT, hook));
        }
 
        while ((hook = TAILQ_FIRST(&pool->output_hooks)) != NULL) {
-               assert(evrpc_remove_hook(pool, OUTPUT, hook));
+               assert(evrpc_remove_hook(pool, EVRPC_OUTPUT, hook));
        }
 
        free(pool);
Index: evrpc.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/evrpc.h,v
retrieving revision 1.1
diff -u -r1.1 evrpc.h
--- evrpc.h     16 May 2008 20:24:58 -0000      1.1
+++ evrpc.h     8 Jul 2009 04:47:41 -0000
@@ -437,10 +437,19 @@
  */
 
 enum EVRPC_HOOK_TYPE {
-       INPUT,          /**< apply the function to an input hook */
-       OUTPUT          /**< apply the function to an output hook */
+       EVRPC_INPUT,            /**< apply the function to an input hook */
+       EVRPC_OUTPUT            /**< apply the function to an output hook */
 };
 
+#ifndef WIN32
+/** Deprecated alias for EVRPC_INPUT.  Not available on windows, where it
+ * conflicts with platform headers. */
+#define INPUT EVRPC_INPUT
+/** Deprecated alias for EVRPC_OUTPUT.  Not available on windows, where it
+ * conflicts with platform headers. */
+#define OUTPUT EVRPC_OUTPUT
+#endif
+
 /** adds a processing hook to either an rpc base or rpc pool
  *
  * If a hook returns -1, the processing is aborted.
Index: evsignal.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/evsignal.h,v
retrieving revision 1.3
diff -u -r1.3 evsignal.h
--- evsignal.h  16 May 2008 20:24:58 -0000      1.3
+++ evsignal.h  8 Jul 2009 04:47:41 -0000
@@ -35,11 +35,11 @@
 typedef void (*ev_sighandler_t)(int);
 
 struct evsignal_info {
-       struct event_list signalqueue;
        struct event ev_signal;
        int ev_signal_pair[2];
        int ev_signal_added;
        volatile sig_atomic_t evsignal_caught;
+       struct event_list evsigevents[NSIG];
        sig_atomic_t evsigcaught[NSIG];
 #ifdef HAVE_SIGACTION
        struct sigaction **sh_old;
Index: evutil.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/evutil.c,v
retrieving revision 1.1
diff -u -r1.1 evutil.c
--- evutil.c    16 May 2008 20:24:58 -0000      1.1
+++ evutil.c    8 Jul 2009 04:47:41 -0000
@@ -25,9 +25,8 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
+#include <stdio.h>
 
 #include <sys/types.h>
 #ifdef HAVE_SYS_SOCKET_H
@@ -75,3 +74,21 @@
 #error "I don't know how to parse 64-bit integers."
 #endif
 }
+int
+evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+{
+       int r;
+       va_list ap;
+       va_start(ap, format);
+       r = evutil_vsnprintf(buf, buflen, format, ap);
+       va_end(ap);
+       return r;
+}
+
+int
+evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap)
+{
+       int r = vsnprintf(buf, buflen, format, ap);
+       buf[buflen-1] = '\0';
+       return r;
+}
Index: evutil.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/evutil.h,v
retrieving revision 1.1
diff -u -r1.1 evutil.h
--- evutil.h    16 May 2008 20:24:58 -0000      1.1
+++ evutil.h    8 Jul 2009 04:47:41 -0000
@@ -38,6 +38,7 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+#include <stdarg.h>
 
 #include <sys/types.h>
 #include <sys/time.h>
@@ -79,6 +80,13 @@
 
 #define evutil_gettimeofday(tv, tz) gettimeofday((tv), (tz))
 
+int evutil_snprintf(char *buf, size_t buflen, const char *format, ...)
+#ifdef __GNUC__
+       __attribute__((format(printf, 3, 4)))
+#endif
+       ;
+int evutil_vsnprintf(char *buf, size_t buflen, const char *format, va_list ap);
+
 #ifdef __cplusplus
 }
 #endif
Index: http-internal.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/http-internal.h,v
retrieving revision 1.1
diff -u -r1.1 http-internal.h
--- http-internal.h     16 May 2008 20:24:58 -0000      1.1
+++ http-internal.h     8 Jul 2009 04:47:41 -0000
@@ -18,6 +18,13 @@
 #define HTTP_PREFIX            "http://";
 #define HTTP_DEFAULTPORT       80
 
+enum message_read_status {
+       ALL_DATA_READ = 1,
+       MORE_DATA_EXPECTED = 0,
+       DATA_CORRUPTED = -1,
+       REQUEST_CANCELED = -2
+};
+
 enum evhttp_connection_error {
        EVCON_HTTP_TIMEOUT,
        EVCON_HTTP_EOF,
@@ -31,9 +38,15 @@
 /* A stupid connection object - maybe make this a bufferevent later */
 
 enum evhttp_connection_state {
-       EVCON_DISCONNECTED,     /* not currently connected not trying either */
-       EVCON_CONNECTING,       /* tries to currently connect */
-       EVCON_CONNECTED         /* connection is established */
+       EVCON_DISCONNECTED,     /**< not currently connected not trying either*/
+       EVCON_CONNECTING,       /**< tries to currently connect */
+       EVCON_IDLE,             /**< connection is established */
+       EVCON_READING_FIRSTLINE,/**< reading Request-Line (incoming conn) or
+                                **< Status-Line (outgoing conn) */
+       EVCON_READING_HEADERS,  /**< reading request/response headers */
+       EVCON_READING_BODY,     /**< reading request/response body */
+       EVCON_READING_TRAILER,  /**< reading request/response chunked trailer */
+       EVCON_WRITING           /**< writing request/response headers/body */
 };
 
 struct event_base;
@@ -49,6 +62,7 @@
        struct evbuffer *output_buffer;
        
        char *bind_address;             /* address to use for binding the src */
+       u_short bind_port;              /* local port for binding the src */
 
        char *address;                  /* address to connect to */
        u_short port;
@@ -125,10 +139,10 @@
 
 int evhttp_hostportfile(char *, char **, u_short *, char **);
 
-int evhttp_parse_lines(struct evhttp_request *, struct evbuffer*);
+int evhttp_parse_firstline(struct evhttp_request *, struct evbuffer*);
+int evhttp_parse_headers(struct evhttp_request *, struct evbuffer*);
 
 void evhttp_start_read(struct evhttp_connection *);
-void evhttp_read_header(int, short, void *);
 void evhttp_make_header(struct evhttp_connection *, struct evhttp_request *);
 
 void evhttp_write_buffer(struct evhttp_connection *,
Index: http.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/http.c,v
retrieving revision 1.1
diff -u -r1.1 http.c
--- http.c      16 May 2008 20:24:58 -0000      1.1
+++ http.c      8 Jul 2009 04:47:42 -0000
@@ -26,9 +26,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
@@ -135,8 +133,8 @@
 extern int debug;
 
 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 int bind_socket_ai(struct addrinfo *, int reuse);
+static int bind_socket(const char *, u_short, int reuse);
 static void name_from_addr(struct sockaddr *, socklen_t, char **, char **);
 static int evhttp_associate_new_request_with_connection(
        struct evhttp_connection *evcon);
@@ -145,6 +143,14 @@
 static void evhttp_connection_stop_detectclose(
        struct evhttp_connection *evcon);
 static void evhttp_request_dispatch(struct evhttp_connection* evcon);
+static void evhttp_read_firstline(struct evhttp_connection *evcon,
+                                 struct evhttp_request *req);
+static void evhttp_read_header(struct evhttp_connection *evcon,
+    struct evhttp_request *req);
+static int evhttp_add_header_internal(struct evkeyvalq *headers,
+    const char *key, const char *value);
+static int evhttp_decode_uri_internal(const char *uri, size_t length,
+    char *ret, int always_decode_plus);
 
 void evhttp_read(int, short, void *);
 void evhttp_write(int, short, void *);
@@ -283,31 +289,46 @@
        evhttp_add_event(&evcon->ev, evcon->timeout, HTTP_WRITE_TIMEOUT);
 }
 
+static int
+evhttp_connected(struct evhttp_connection *evcon)
+{
+       switch (evcon->state) {
+       case EVCON_DISCONNECTED:
+       case EVCON_CONNECTING:
+               return (0);
+       case EVCON_IDLE:
+       case EVCON_READING_FIRSTLINE:
+       case EVCON_READING_HEADERS:
+       case EVCON_READING_BODY:
+       case EVCON_READING_TRAILER:
+       case EVCON_WRITING:
+       default:
+               return (1);
+       }
+}
+
 /*
- * Create the headers need for an HTTP request
+ * Create the headers needed for an HTTP request
  */
 static void
 evhttp_make_header_request(struct evhttp_connection *evcon,
     struct evhttp_request *req)
 {
-       char line[1024];
        const char *method;
        
-       evhttp_remove_header(req->output_headers, "Accept-Encoding");
        evhttp_remove_header(req->output_headers, "Proxy-Connection");
 
        /* Generate request line */
        method = evhttp_method(req->type);
-       snprintf(line, sizeof(line), "%s %s HTTP/%d.%d\r\n",
+       evbuffer_add_printf(evcon->output_buffer, "%s %s HTTP/%d.%d\r\n",
            method, req->uri, req->major, req->minor);
-       evbuffer_add(evcon->output_buffer, line, strlen(line));
 
        /* Add the content length on a post request if missing */
        if (req->type == EVHTTP_REQ_POST &&
            evhttp_find_header(req->output_headers, "Content-Length") == NULL){
                char size[12];
-               snprintf(size, sizeof(size), "%ld",
-                        (long)EVBUFFER_LENGTH(req->output_buffer));
+               evutil_snprintf(size, sizeof(size), "%ld",
+                   (long)EVBUFFER_LENGTH(req->output_buffer));
                evhttp_add_header(req->output_headers, "Content-Length", size);
        }
 }
@@ -359,7 +380,7 @@
        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);
+               evutil_snprintf(len, sizeof(len), "%ld", content_length);
                evhttp_add_header(headers, "Content-Length", len);
        }
 }
@@ -372,25 +393,33 @@
 evhttp_make_header_response(struct evhttp_connection *evcon,
     struct evhttp_request *req)
 {
-       char line[1024];
-       snprintf(line, sizeof(line), "HTTP/%d.%d %d %s\r\n",
+       int is_keepalive = evhttp_is_connection_keepalive(req->input_headers);
+       evbuffer_add_printf(evcon->output_buffer, "HTTP/%d.%d %d %s\r\n",
            req->major, req->minor, req->response_code,
            req->response_code_line);
-       evbuffer_add(evcon->output_buffer, line, strlen(line));
 
-       if (req->major == 1 && req->minor == 1)
-               evhttp_maybe_add_date_header(req->output_headers);
+       if (req->major == 1) {
+               if (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.
+               /*
+                * if the protocol is 1.0; and the connection was keep-alive
+                * we need to add a keep-alive header, too.
                 */
-               evhttp_maybe_add_content_length_header(req->output_headers,
-                   (long)EVBUFFER_LENGTH(req->output_buffer));
+               if (req->minor == 0 && is_keepalive)
+                       evhttp_add_header(req->output_headers,
+                           "Connection", "keep-alive");
+
+               if (req->minor == 1 || is_keepalive) {
+                       /* 
+                        * we need to add the content length if the
+                        * user did not give it, this is required for
+                        * persistent connections to work.
+                        */
+                       evhttp_maybe_add_content_length_header(
+                               req->output_headers,
+                               (long)EVBUFFER_LENGTH(req->output_buffer));
+               }
        }
 
        /* Potentially add headers for unidentified content. */
@@ -414,7 +443,6 @@
 void
 evhttp_make_header(struct evhttp_connection *evcon, struct evhttp_request *req)
 {
-       char line[1024];
        struct evkeyval *header;
 
        /*
@@ -428,9 +456,8 @@
        }
 
        TAILQ_FOREACH(header, req->output_headers, next) {
-               snprintf(line, sizeof(line), "%s: %s\r\n",
+               evbuffer_add_printf(evcon->output_buffer, "%s: %s\r\n",
                    header->key, header->value);
-               evbuffer_add(evcon->output_buffer, line, strlen(line));
        }
        evbuffer_add(evcon->output_buffer, "\r\n", 2);
 
@@ -477,7 +504,7 @@
                /* Generate request file */
                if (p2 == NULL)
                        p2 = "";
-               snprintf(file, sizeof(file), "/%s", p2);
+               evutil_snprintf(file, sizeof(file), "/%s", p2);
        }
 
        p = strchr(host, ':');
@@ -611,23 +638,29 @@
                (*evcon->cb)(evcon, evcon->cb_arg);
 }
 
+/**
+ * Advance the connection state.
+ * - If this is an outgoing connection, we've just processed the response;
+ *   idle or close the connection.
+ * - If this is an incoming connection, we've just processed the request;
+ *   respond.
+ */
 static void
 evhttp_connection_done(struct evhttp_connection *evcon)
 {
        struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
        int con_outgoing = evcon->flags & EVHTTP_CON_OUTGOING;
 
-       /*
-        * if this is an incoming connection, we need to leave the request
-        * on the connection, so that we can reply to it.
-        */
        if (con_outgoing) {
+               /* idle or close the connection */
                int need_close;
                TAILQ_REMOVE(&evcon->requests, req, next);
                req->evcon = NULL;
 
+               evcon->state = EVCON_IDLE;
+
                need_close = 
-                   evhttp_is_connection_close(req->flags, req->input_headers) 
||
+                   evhttp_is_connection_close(req->flags, req->input_headers)||
                    evhttp_is_connection_close(req->flags, req->output_headers);
 
                /* check if we got asked to close the connection */
@@ -637,10 +670,9 @@
                if (TAILQ_FIRST(&evcon->requests) != NULL) {
                        /*
                         * We have more requests; reset the connection
-                        * and deal with the next request.  xxx: no
-                        * persistent connection right now
+                        * and deal with the next request.
                         */
-                       if (evcon->state != EVCON_CONNECTED)
+                       if (!evhttp_connected(evcon))
                                evhttp_connection_connect(evcon);
                        else
                                evhttp_request_dispatch(evcon);
@@ -651,6 +683,12 @@
                         */
                        evhttp_connection_start_detectclose(evcon);
                }
+       } else {
+               /*
+                * incoming connection - we need to leave the request on the
+                * connection so that we can reply to it.
+                */
+               evcon->state = EVCON_WRITING;
        }
 
        /* notify the user of the request */
@@ -664,12 +702,17 @@
 
 /*
  * Handles reading from a chunked request.
- * return 1: all data has been read
- * return 0: more data is expected
- * return -1: data is corrupted
+ *   return ALL_DATA_READ:
+ *     all data has been read
+ *   return MORE_DATA_EXPECTED:
+ *     more data is expected
+ *   return DATA_CORRUPTED:
+ *     data is corrupted
+ *   return REQUEST_CANCLED:
+ *     request was canceled by the user calling evhttp_cancel_request
  */
 
-static int
+static enum message_read_status
 evhttp_handle_chunked_read(struct evhttp_request *req, struct evbuffer *buf)
 {
        int len;
@@ -677,6 +720,7 @@
        while ((len = EVBUFFER_LENGTH(buf)) > 0) {
                if (req->ntoread < 0) {
                        /* Read chunk size */
+                       ev_int64_t ntoread;
                        char *p = evbuffer_readline(buf);
                        char *endp;
                        int error;
@@ -687,28 +731,31 @@
                                free(p);
                                continue;
                        }
-                       req->ntoread = evutil_strtoll(p, &endp, 16);
-                       error = *p == '\0' || (*endp != '\0' && *endp != ' ');
+                       ntoread = evutil_strtoll(p, &endp, 16);
+                       error = (*p == '\0' ||
+                           (*endp != '\0' && *endp != ' ') ||
+                           ntoread < 0);
                        free(p);
                        if (error) {
                                /* could not get chunk size */
-                               return (-1);
+                               return (DATA_CORRUPTED);
                        }
+                       req->ntoread = ntoread;
                        if (req->ntoread == 0) {
                                /* Last chunk */
-                               return (1);
+                               return (ALL_DATA_READ);
                        }
                        continue;
                }
 
                /* don't have enough to complete a chunk; wait for more */
                if (len < req->ntoread)
-                       return (0);
+                       return (MORE_DATA_EXPECTED);
 
                /* Completed chunk */
                evbuffer_add(req->input_buffer,
-                   EVBUFFER_DATA(buf), req->ntoread);
-               evbuffer_drain(buf, req->ntoread);
+                   EVBUFFER_DATA(buf), (size_t)req->ntoread);
+               evbuffer_drain(buf, (size_t)req->ntoread);
                req->ntoread = -1;
                if (req->chunk_cb != NULL) {
                        (*req->chunk_cb)(req, req->cb_arg);
@@ -717,7 +764,28 @@
                }
        }
 
-       return (0);
+       return (MORE_DATA_EXPECTED);
+}
+
+static void
+evhttp_read_trailer(struct evhttp_connection *evcon, struct evhttp_request 
*req)
+{
+       struct evbuffer *buf = evcon->input_buffer;
+
+       switch (evhttp_parse_headers(req, buf)) {
+       case DATA_CORRUPTED:
+               evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
+               break;
+       case ALL_DATA_READ:
+               event_del(&evcon->ev);
+               evhttp_connection_done(evcon);
+               break;
+       case MORE_DATA_EXPECTED:
+       default:
+               evhttp_add_event(&evcon->ev, evcon->timeout,
+                   HTTP_READ_TIMEOUT);
+               break;
+       }
 }
 
 static void
@@ -726,16 +794,24 @@
        struct evbuffer *buf = evcon->input_buffer;
        
        if (req->chunked) {
-               int res = evhttp_handle_chunked_read(req, buf);
-               if (res == 1) {
+               switch (evhttp_handle_chunked_read(req, buf)) {
+               case ALL_DATA_READ:
                        /* finished last chunk */
-                       evhttp_connection_done(evcon);
+                       evcon->state = EVCON_READING_TRAILER;
+                       evhttp_read_trailer(evcon, req);
                        return;
-               } else if (res == -1) {
+               case DATA_CORRUPTED:
                        /* corrupted data */
                        evhttp_connection_fail(evcon,
                            EVCON_HTTP_INVALID_HEADER);
                        return;
+               case REQUEST_CANCELED:
+                       /* request canceled */
+                       evhttp_request_free(req);
+                       return;
+               case MORE_DATA_EXPECTED:
+               default:
+                       break;
                }
        } else if (req->ntoread < 0) {
                /* Read until connection close. */
@@ -743,8 +819,8 @@
        } else if (EVBUFFER_LENGTH(buf) >= req->ntoread) {
                /* Completed content length */
                evbuffer_add(req->input_buffer, EVBUFFER_DATA(buf),
-                   req->ntoread);
-               evbuffer_drain(buf, req->ntoread);
+                   (size_t)req->ntoread);
+               evbuffer_drain(buf, (size_t)req->ntoread);
                req->ntoread = 0;
                evhttp_connection_done(evcon);
                return;
@@ -779,15 +855,41 @@
        event_debug(("%s: got %d on %d\n", __func__, n, fd));
        
        if (n == -1) {
-               event_debug(("%s: evbuffer_read", __func__));
-               evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+               if (errno != EINTR && errno != EAGAIN) {
+                       event_debug(("%s: evbuffer_read", __func__));
+                       evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+               } else {
+                       evhttp_add_event(&evcon->ev, evcon->timeout,
+                           HTTP_READ_TIMEOUT);        
+               }
                return;
        } else if (n == 0) {
                /* Connection closed */
                evhttp_connection_done(evcon);
                return;
        }
-       evhttp_read_body(evcon, req);
+
+       switch (evcon->state) {
+       case EVCON_READING_FIRSTLINE:
+               evhttp_read_firstline(evcon, req);
+               break;
+       case EVCON_READING_HEADERS:
+               evhttp_read_header(evcon, req);
+               break;
+       case EVCON_READING_BODY:
+               evhttp_read_body(evcon, req);
+               break;
+       case EVCON_READING_TRAILER:
+               evhttp_read_trailer(evcon, req);
+               break;
+       case EVCON_DISCONNECTED:
+       case EVCON_CONNECTING:
+       case EVCON_IDLE:
+       case EVCON_WRITING:
+       default:
+               event_errx(1, "%s: illegal connection state %d",
+                          __func__, evcon->state);
+       }
 }
 
 static void
@@ -797,6 +899,8 @@
        struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
        assert(req != NULL);
 
+       assert(evcon->state == EVCON_WRITING);
+
        /* We are done writing our header and are now expecting the response */
        req->kind = EVHTTP_RESPONSE;
 
@@ -814,7 +918,7 @@
 
        /* notify interested parties that this connection is going down */
        if (evcon->fd != -1) {
-               if (evcon->state == EVCON_CONNECTED && evcon->closecb != NULL)
+               if (evhttp_connected(evcon) && evcon->closecb != NULL)
                        (*evcon->closecb)(evcon, evcon->closecb_arg);
        }
 
@@ -864,6 +968,13 @@
                event_err(1, "%s: strdup", __func__);
 }
 
+void
+evhttp_connection_set_local_port(struct evhttp_connection *evcon,
+    unsigned short port)
+{
+       assert(evcon->state == EVCON_DISCONNECTED);
+       evcon->bind_port = port;
+}
 
 static void
 evhttp_request_dispatch(struct evhttp_connection* evcon)
@@ -878,7 +989,9 @@
        evhttp_connection_stop_detectclose(evcon);
        
        /* we assume that the connection is connected already */
-       assert(evcon->state == EVCON_CONNECTED);
+       assert(evcon->state == EVCON_IDLE);
+
+       evcon->state = EVCON_WRITING;
 
        /* Create the header from the store arguments */
        evhttp_make_header(evcon, req);
@@ -895,7 +1008,7 @@
 
        if (evcon->fd != -1) {
                /* inform interested parties about connection close */
-               if (evcon->state == EVCON_CONNECTED && evcon->closecb != NULL)
+               if (evhttp_connected(evcon) && evcon->closecb != NULL)
                        (*evcon->closecb)(evcon, evcon->closecb_arg);
 
                EVUTIL_CLOSESOCKET(evcon->fd);
@@ -903,8 +1016,10 @@
        }
        evcon->state = EVCON_DISCONNECTED;
 
-       /* remove unneeded flags */
-       evcon->flags &= ~EVHTTP_CON_CLOSEDETECT;
+       evbuffer_drain(evcon->input_buffer,
+           EVBUFFER_LENGTH(evcon->input_buffer));
+       evbuffer_drain(evcon->output_buffer,
+           EVBUFFER_LENGTH(evcon->output_buffer));
 }
 
 static void
@@ -981,7 +1096,7 @@
 
        /* Reset the retry count as we were successful in connecting */
        evcon->retry_cnt = 0;
-       evcon->state = EVCON_CONNECTED;
+       evcon->state = EVCON_IDLE;
 
        /* try to start requests that have queued up on this connection */
        evhttp_request_dispatch(evcon);
@@ -1177,22 +1292,46 @@
        return (0);
 }
 
+static int
+evhttp_header_is_valid_value(const char *value)
+{
+       const char *p = value;
+
+       while ((p = strpbrk(p, "\r\n")) != NULL) {
+               /* we really expect only one new line */
+               p += strspn(p, "\r\n");
+               /* we expect a space or tab for continuation */
+               if (*p != ' ' && *p != '\t')
+                       return (0);
+       }
+       return (1);
+}
+
 int
 evhttp_add_header(struct evkeyvalq *headers,
     const char *key, const char *value)
 {
-       struct evkeyval *header = NULL;
-
        event_debug(("%s: key: %s val: %s\n", __func__, key, value));
 
-       if (strchr(value, '\r') != NULL || strchr(value, '\n') != NULL ||
-           strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
+       if (strchr(key, '\r') != NULL || strchr(key, '\n') != NULL) {
                /* drop illegal headers */
-               event_debug(("%s: dropping illegal header\n", __func__));
+               event_debug(("%s: dropping illegal header key\n", __func__));
+               return (-1);
+       }
+       
+       if (!evhttp_header_is_valid_value(value)) {
+               event_debug(("%s: dropping illegal header value\n", __func__));
                return (-1);
        }
 
-       header = calloc(1, sizeof(struct evkeyval));
+       return (evhttp_add_header_internal(headers, key, value));
+}
+
+static int
+evhttp_add_header_internal(struct evkeyvalq *headers,
+    const char *key, const char *value)
+{
+       struct evkeyval *header = calloc(1, sizeof(struct evkeyval));
        if (header == NULL) {
                event_warn("%s: calloc", __func__);
                return (-1);
@@ -1219,63 +1358,105 @@
  * request object given an event buffer.
  *
  * Returns
- *   -1  on error
- *    0  when we need to read more headers
- *    1  when all headers have been read.
+ *   DATA_CORRUPTED      on error
+ *   MORE_DATA_EXPECTED  when we need to read more headers
+ *   ALL_DATA_READ       when all headers have been read.
  */
 
-int
-evhttp_parse_lines(struct evhttp_request *req, struct evbuffer* buffer)
+enum message_read_status
+evhttp_parse_firstline(struct evhttp_request *req, struct evbuffer *buffer)
+{
+       char *line;
+       enum message_read_status status = ALL_DATA_READ;
+
+       line = evbuffer_readline(buffer);
+       if (line == NULL)
+               return (MORE_DATA_EXPECTED);
+
+       switch (req->kind) {
+       case EVHTTP_REQUEST:
+               if (evhttp_parse_request_line(req, line) == -1)
+                       status = DATA_CORRUPTED;
+               break;
+       case EVHTTP_RESPONSE:
+               if (evhttp_parse_response_line(req, line) == -1)
+                       status = DATA_CORRUPTED;
+               break;
+       default:
+               status = DATA_CORRUPTED;
+       }
+
+       free(line);
+       return (status);
+}
+
+static int
+evhttp_append_to_last_header(struct evkeyvalq *headers, const char *line)
+{
+       struct evkeyval *header = TAILQ_LAST(headers, evkeyvalq);
+       char *newval;
+       size_t old_len, line_len;
+
+       if (header == NULL)
+               return (-1);
+
+       old_len = strlen(header->value);
+       line_len = strlen(line);
+
+       newval = realloc(header->value, old_len + line_len + 1);
+       if (newval == NULL)
+               return (-1);
+
+       memcpy(newval + old_len, line, line_len + 1);
+       header->value = newval;
+
+       return (0);
+}
+
+enum message_read_status
+evhttp_parse_headers(struct evhttp_request *req, struct evbuffer* buffer)
 {
        char *line;
-       int done = 0;
+       enum message_read_status status = MORE_DATA_EXPECTED;
 
        struct evkeyvalq* headers = req->input_headers;
-       while ((line = evbuffer_readline(buffer)) != NULL) {
+       while ((line = evbuffer_readline(buffer))
+              != NULL) {
                char *skey, *svalue;
 
                if (*line == '\0') { /* Last header - Done */
-                       done = 1;
-                       free (line);
+                       status = ALL_DATA_READ;
+                       free(line);
                        break;
                }
 
-               /* Processing of header lines */
-               if (req->got_firstline == 0) {
-                       switch (req->kind) {
-                       case EVHTTP_REQUEST:
-                               if (evhttp_parse_request_line(req, line) == -1)
-                                       goto error;
-                               break;
-                       case EVHTTP_RESPONSE:
-                               if (evhttp_parse_response_line(req, line) == -1)
-                                       goto error;
-                               break;
-                       default:
-                               goto error;
-                       }
-                       req->got_firstline = 1;
-               } else {
-                       /* Regular header */
-                       svalue = line;
-                       skey = strsep(&svalue, ":");
-                       if (svalue == NULL)
+               /* Check if this is a continuation line */
+               if (*line == ' ' || *line == '\t') {
+                       if (evhttp_append_to_last_header(headers, line) == -1)
                                goto error;
+                       free(line);
+                       continue;
+               }
 
-                       svalue += strspn(svalue, " ");
+               /* Processing of header lines */
+               svalue = line;
+               skey = strsep(&svalue, ":");
+               if (svalue == NULL)
+                       goto error;
 
-                       if (evhttp_add_header(headers, skey, svalue) == -1)
-                               goto error;
-               }
+               svalue += strspn(svalue, " ");
 
-               free (line);
+               if (evhttp_add_header(headers, skey, svalue) == -1)
+                       goto error;
+
+               free(line);
        }
 
-       return (done);
+       return (status);
 
  error:
-       free (line);
-       return (-1);
+       free(line);
+       return (DATA_CORRUPTED);
 }
 
 static int
@@ -1301,15 +1482,16 @@
                req->ntoread = -1;
        } else {
                char *endp;
-               req->ntoread = evutil_strtoll(content_length, &endp, 10);
-               if (*content_length == '\0' || *endp != '\0') {
-                       event_warnx("%s: illegal content length: %s",
-                           __func__, content_length);
+               ev_int64_t ntoread = evutil_strtoll(content_length, &endp, 10);
+               if (*content_length == '\0' || *endp != '\0' || ntoread < 0) {
+                       event_debug(("%s: illegal content length: %s",
+                               __func__, content_length));
                        return (-1);
                }
+               req->ntoread = ntoread;
        }
                
-       event_debug(("%s: bytes to read: %d (in buffer %d)\n",
+       event_debug(("%s: bytes to read: %lld (in buffer %ld)\n",
                __func__, req->ntoread,
                EVBUFFER_LENGTH(req->evcon->input_buffer)));
 
@@ -1326,6 +1508,7 @@
                evhttp_connection_done(evcon);
                return;
        }
+       evcon->state = EVCON_READING_BODY;
        xfer_enc = evhttp_find_header(req->input_headers, "Transfer-Encoding");
        if (xfer_enc != NULL && strcasecmp(xfer_enc, "chunked") == 0) {
                req->chunked = 1;
@@ -1340,38 +1523,43 @@
        evhttp_read_body(evcon, req);
 }
 
-void
-evhttp_read_header(int fd, short what, void *arg)
+static void
+evhttp_read_firstline(struct evhttp_connection *evcon,
+                     struct evhttp_request *req)
 {
-       struct evhttp_connection *evcon = arg;
-       struct evhttp_request *req = TAILQ_FIRST(&evcon->requests);
-       int n, res;
+       enum message_read_status res;
 
-       if (what == EV_TIMEOUT) {
-               event_debug(("%s: timeout on %d\n", __func__, fd));
-               evhttp_connection_fail(evcon, EVCON_HTTP_TIMEOUT);
-               return;
-       }
-
-       n = evbuffer_read(evcon->input_buffer, fd, -1);
-       if (n == 0) {
-               event_debug(("%s: no more data on %d", __func__, fd));
-               evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+       res = evhttp_parse_firstline(req, evcon->input_buffer);
+       if (res == DATA_CORRUPTED) {
+               /* Error while reading, terminate */
+               event_debug(("%s: bad header lines on %d\n",
+                       __func__, evcon->fd));
+               evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
                return;
-       }
-       if (n == -1) {
-               event_debug(("%s: bad read on %d", __func__, fd));
-               evhttp_connection_fail(evcon, EVCON_HTTP_EOF);
+       } else if (res == MORE_DATA_EXPECTED) {
+               /* Need more header lines */
+               evhttp_add_event(&evcon->ev, 
+                    evcon->timeout, HTTP_READ_TIMEOUT);
                return;
        }
 
-       res = evhttp_parse_lines(req, evcon->input_buffer);
-       if (res == -1) {
+       evcon->state = EVCON_READING_HEADERS;
+       evhttp_read_header(evcon, req);
+}
+
+static void
+evhttp_read_header(struct evhttp_connection *evcon, struct evhttp_request *req)
+{
+       enum message_read_status res;
+       int fd = evcon->fd;
+
+       res = evhttp_parse_headers(req, evcon->input_buffer);
+       if (res == DATA_CORRUPTED) {
                /* Error while reading, terminate */
                event_debug(("%s: bad header lines on %d\n", __func__, fd));
                evhttp_connection_fail(evcon, EVCON_HTTP_INVALID_HEADER);
                return;
-       } else if (res == 0) {
+       } else if (res == MORE_DATA_EXPECTED) {
                /* Need more header lines */
                evhttp_add_event(&evcon->ev, 
                    evcon->timeout, HTTP_READ_TIMEOUT);
@@ -1510,7 +1698,8 @@
        assert(!(evcon->flags & EVHTTP_CON_INCOMING));
        evcon->flags |= EVHTTP_CON_OUTGOING;
        
-       evcon->fd = bind_socket(evcon->bind_address, 0);
+       evcon->fd = bind_socket(
+               evcon->bind_address, evcon->bind_port, 0 /*reuse*/);
        if (evcon->fd == -1) {
                event_debug(("%s: failed to bind to \"%s\"",
                        __func__, evcon->bind_address));
@@ -1564,7 +1753,7 @@
        TAILQ_INSERT_TAIL(&evcon->requests, req, next);
 
        /* If the connection object is not connected; make it so */
-       if (evcon->state != EVCON_CONNECTED)
+       if (!evhttp_connected(evcon))
                return (evhttp_connection_connect(evcon));
 
        /*
@@ -1589,10 +1778,11 @@
        /* Set up an event to read the headers */
        if (event_initialized(&evcon->ev))
                event_del(&evcon->ev);
-       event_set(&evcon->ev, evcon->fd, EV_READ, evhttp_read_header, evcon);
+       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);
+       evcon->state = EVCON_READING_FIRSTLINE;
 }
 
 static void
@@ -1676,8 +1866,6 @@
 evhttp_send_reply(struct evhttp_request *req, int code, const char *reason,
     struct evbuffer *databuf)
 {
-       /* set up to watch for client close */
-       evhttp_connection_start_detectclose(req->evcon);
        evhttp_response_code(req, code, reason);
        
        evhttp_send(req, databuf);
@@ -1687,8 +1875,6 @@
 evhttp_send_reply_start(struct evhttp_request *req, int code,
     const char *reason)
 {
-       /* set up to watch for client close */
-       evhttp_connection_start_detectclose(req->evcon);
        evhttp_response_code(req, code, reason);
        if (req->major == 1 && req->minor == 1) {
                /* use chunked encoding for HTTP/1.1 */
@@ -1807,16 +1993,16 @@
        return (p);
 }
 
-char *
-evhttp_decode_uri(const char *uri)
+/*
+ * @param always_decode_plus: when true we transform plus to space even
+ *     if we have not seen a ?.
+ */
+static int
+evhttp_decode_uri_internal(
+       const char *uri, size_t length, char *ret, int always_decode_plus)
 {
-       char c, *ret;
-       int i, j, in_query = 0;
-       
-       ret = malloc(strlen(uri) + 1);
-       if (ret == NULL)
-               event_err(1, "%s: malloc(%lu)", __func__,
-                         (unsigned long)(strlen(uri) + 1));
+       char c;
+       int i, j, in_query = always_decode_plus;
        
        for (i = j = 0; uri[i] != '\0'; i++) {
                c = uri[i];
@@ -1833,14 +2019,28 @@
                ret[j++] = c;
        }
        ret[j] = '\0';
-       
+
+       return (j);
+}
+
+char *
+evhttp_decode_uri(const char *uri)
+{
+       char *ret;
+
+       if ((ret = malloc(strlen(uri) + 1)) == NULL)
+               event_err(1, "%s: malloc(%lu)", __func__,
+                         (unsigned long)(strlen(uri) + 1));
+
+       evhttp_decode_uri_internal(uri, strlen(uri),
+           ret, 0 /*always_decode_plus*/);
+
        return (ret);
 }
 
 /* 
  * Helper function to parse out arguments in a query.
  * The arguments are separated by key and value.
- * URI should already be decoded.
  */
 
 void
@@ -1867,7 +2067,7 @@
 
        p = argument;
        while (p != NULL && *p != '\0') {
-               char *key, *value;
+               char *key, *value, *decoded_value;
                argument = strsep(&p, "&");
 
                value = argument;
@@ -1875,10 +2075,14 @@
                if (value == NULL)
                        goto error;
 
-               value = evhttp_decode_uri(value);
-               event_debug(("Query Param: %s -> %s\n", key, value));
-               evhttp_add_header(headers, key, value);
-               free(value);
+               if ((decoded_value = malloc(strlen(value) + 1)) == NULL)
+                       event_err(1, "%s: malloc", __func__);
+
+               evhttp_decode_uri_internal(value, strlen(value),
+                   decoded_value, 1 /*always_decode_plus*/);
+               event_debug(("Query Param: %s -> %s\n", key, decoded_value));
+               evhttp_add_header_internal(headers, key, decoded_value);
+               free(decoded_value);
        }
 
  error:
@@ -1966,7 +2170,8 @@
        int nfd;
 
        if ((nfd = accept(fd, (struct sockaddr *)&ss, &addrlen)) == -1) {
-               event_warn("%s: bad accept", __func__);
+               if (errno != EAGAIN && errno != EINTR)
+                       event_warn("%s: bad accept", __func__);
                return;
        }
        if (evutil_make_socket_nonblocking(nfd) < 0)
@@ -1981,7 +2186,7 @@
        int fd;
        int res;
 
-       if ((fd = bind_socket(address, port)) == -1)
+       if ((fd = bind_socket(address, port, 1 /*reuse*/)) == -1)
                return (-1);
 
        if (listen(fd, 128) == -1) {
@@ -2246,7 +2451,7 @@
 const char *
 evhttp_request_uri(struct evhttp_request *req) {
        if (req->uri == NULL)
-               event_debug(("%s: request %p has no uri\n", req));
+               event_debug(("%s: request %p has no uri\n", __func__, req));
        return (req->uri);
 }
 
@@ -2261,21 +2466,30 @@
        int fd, struct sockaddr *sa, socklen_t salen)
 {
        struct evhttp_connection *evcon;
-       char *hostname, *portname;
+       char *hostname = NULL, *portname = NULL;
 
        name_from_addr(sa, salen, &hostname, &portname);
+       if (hostname == NULL || portname == NULL) {
+               if (hostname) free(hostname);
+               if (portname) free(portname);
+               return (NULL);
+       }
+
        event_debug(("%s: new request from %s:%s on %d\n",
                        __func__, hostname, portname, fd));
 
        /* we need a connection object to put the http request on */
-       if ((evcon = evhttp_connection_new(hostname, atoi(portname))) == NULL)
+       evcon = evhttp_connection_new(hostname, atoi(portname));
+       free(hostname);
+       free(portname);
+       if (evcon == NULL)
                return (NULL);
 
        /* associate the base if we have one*/
        evhttp_connection_set_base(evcon, http->base);
 
        evcon->flags |= EVHTTP_CON_INCOMING;
-       evcon->state = EVCON_CONNECTED;
+       evcon->state = EVCON_READING_FIRSTLINE;
        
        evcon->fd = fd;
 
@@ -2367,32 +2581,37 @@
 name_from_addr(struct sockaddr *sa, socklen_t salen,
     char **phost, char **pport)
 {
-#ifdef HAVE_GETNAMEINFO
-       /* XXXX not threadsafe. */
-       static char ntop[NI_MAXHOST];
-       static char strport[NI_MAXSERV];
+       char ntop[NI_MAXHOST];
+       char strport[NI_MAXSERV];
        int ni_result;
 
-       if ((ni_result = getnameinfo(sa, salen,
+#ifdef HAVE_GETNAMEINFO
+       ni_result = getnameinfo(sa, salen,
                ntop, sizeof(ntop), strport, sizeof(strport),
-               NI_NUMERICHOST|NI_NUMERICSERV)) != 0) {
+               NI_NUMERICHOST|NI_NUMERICSERV);
+       
+       if (ni_result != 0) {
                if (ni_result == EAI_SYSTEM)
                        event_err(1, "getnameinfo failed");
                else
                        event_errx(1, "getnameinfo failed: %s", 
gai_strerror(ni_result));
+               return;
        }
- 
-       *phost = ntop;
-       *pport = strport;
 #else
-       /* XXXX */
+       ni_result = fake_getnameinfo(sa, salen,
+               ntop, sizeof(ntop), strport, sizeof(strport),
+               NI_NUMERICHOST|NI_NUMERICSERV);
+       if (ni_result != 0)
+                       return;
 #endif
+       *phost = strdup(ntop);
+       *pport = strdup(strport);
 }
 
-/* Either connect or bind */
-
+/* Create a non-blocking socket and bind it */
+/* todo: rename this function */
 static int
-bind_socket_ai(struct addrinfo *ai)
+bind_socket_ai(struct addrinfo *ai, int reuse)
 {
         int fd, on = 1, r;
        int serrno;
@@ -2413,11 +2632,16 @@
         }
 
         setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
-        setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
+       if (reuse) {
+               setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+                   (void *)&on, sizeof(on));
+       }
 
-       r = bind(fd, ai->ai_addr, ai->ai_addrlen);
-       if (r == -1)
-               goto out;
+       if (ai != NULL) {
+               r = bind(fd, ai->ai_addr, ai->ai_addrlen);
+               if (r == -1)
+                       goto out;
+       }
 
        return (fd);
 
@@ -2442,7 +2666,7 @@
         ai.ai_family = AF_INET;
         ai.ai_socktype = SOCK_STREAM;
         ai.ai_flags = AI_PASSIVE;  /* turn NULL host name into INADDR_ANY */
-        snprintf(strport, sizeof(strport), "%d", port);
+        evutil_snprintf(strport, sizeof(strport), "%d", port);
         if ((ai_result = getaddrinfo(address, strport, &ai, &aitop)) != 0) {
                 if ( ai_result == EAI_SYSTEM )
                         event_warn("getaddrinfo");
@@ -2467,15 +2691,21 @@
 }
 
 static int
-bind_socket(const char *address, u_short port)
+bind_socket(const char *address, u_short port, int reuse)
 {
        int fd;
-       struct addrinfo *aitop = make_addrinfo(address, port);
+       struct addrinfo *aitop = NULL;
+
+       /* just create an unbound socket */
+       if (address == NULL && port == 0)
+               return bind_socket_ai(NULL, 0);
+               
+       aitop = make_addrinfo(address, port);
 
        if (aitop == NULL)
                return (-1);
 
-       fd = bind_socket_ai(aitop);
+       fd = bind_socket_ai(aitop, reuse);
 
 #ifdef HAVE_GETADDRINFO
        freeaddrinfo(aitop);
Index: kqueue.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/kqueue.c,v
retrieving revision 1.6
diff -u -r1.6 kqueue.c
--- kqueue.c    16 May 2008 20:24:58 -0000      1.6
+++ kqueue.c    8 Jul 2009 04:47:42 -0000
@@ -30,9 +30,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <sys/types.h>
 #ifdef HAVE_SYS_TIME_H
@@ -48,6 +46,7 @@
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
+#include <assert.h>
 #ifdef HAVE_INTTYPES_H
 #include <inttypes.h>
 #endif
@@ -66,6 +65,7 @@
        struct kevent *changes;
        int nchanges;
        struct kevent *events;
+       struct event_list evsigevents[NSIG];
        int nevents;
        int kq;
        pid_t pid;
@@ -91,7 +91,7 @@
 static void *
 kq_init(struct event_base *base)
 {
-       int kq;
+       int i, kq;
        struct kqop *kqueueop;
 
        /* Disable kqueue when this environment variable is set */
@@ -127,6 +127,11 @@
        }
        kqueueop->nevents = NEVENT;
 
+        /* we need to keep track of multiple events per signal */
+       for (i = 0; i < NSIG; ++i) {
+               TAILQ_INIT(&kqueueop->evsigevents[i]);
+       }
+
        return (kqueueop);
 }
 
@@ -168,9 +173,9 @@
        memcpy(&kqop->changes[kqop->nchanges++], kev, sizeof(struct kevent));
 
        event_debug(("%s: fd %d %s%s",
-                __func__, kev->ident, 
-                kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
-                kev->flags == EV_DELETE ? " (del)" : ""));
+               __func__, (int)kev->ident, 
+               kev->filter == EVFILT_READ ? "EVFILT_READ" : "EVFILT_WRITE",
+               kev->flags == EV_DELETE ? " (del)" : ""));
 
        return (0);
 }
@@ -234,8 +239,6 @@
                        return (-1);
                }
 
-               ev = (struct event *)events[i].udata;
-
                if (events[i].filter == EVFILT_READ) {
                        which |= EV_READ;
                } else if (events[i].filter == EVFILT_WRITE) {
@@ -247,11 +250,20 @@
                if (!which)
                        continue;
 
-               if (!(ev->ev_events & EV_PERSIST))
-                       ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
+               if (events[i].filter == EVFILT_SIGNAL) {
+                       struct event_list *head =
+                           (struct event_list *)events[i].udata;
+                       TAILQ_FOREACH(ev, head, ev_signal_next) {
+                               event_active(ev, which, events[i].data);
+                       }
+               } else {
+                       ev = (struct event *)events[i].udata;
+
+                       if (!(ev->ev_events & EV_PERSIST))
+                               ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
 
-               event_active(ev, which,
-                   ev->ev_events & EV_SIGNAL ? events[i].data : 1);
+                       event_active(ev, which, 1);
+               }
        }
 
        return (0);
@@ -266,25 +278,30 @@
 
        if (ev->ev_events & EV_SIGNAL) {
                int nsignal = EVENT_SIGNAL(ev);
-               struct timespec timeout = { 0, 0 };
-
-               memset(&kev, 0, sizeof(kev));
-               kev.ident = nsignal;
-               kev.filter = EVFILT_SIGNAL;
-               kev.flags = EV_ADD;
-               if (!(ev->ev_events & EV_PERSIST))
-                       kev.flags |= EV_ONESHOT;
-               kev.udata = PTR_TO_UDATA(ev);
 
-               /* 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);
+               assert(nsignal >= 0 && nsignal < NSIG);
+               if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
+                       struct timespec timeout = { 0, 0 };
+
+                       memset(&kev, 0, sizeof(kev));
+                       kev.ident = nsignal;
+                       kev.filter = EVFILT_SIGNAL;
+                       kev.flags = EV_ADD;
+                       kev.udata = PTR_TO_UDATA(&kqop->evsigevents[nsignal]);
+
+                       /* 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);
+               }
 
+               TAILQ_INSERT_TAIL(&kqop->evsigevents[nsignal], ev,
+                   ev_signal_next);
                ev->ev_flags |= EVLIST_X_KQINKERNEL;
                return (0);
        }
@@ -337,17 +354,26 @@
 
        if (ev->ev_events & EV_SIGNAL) {
                int nsignal = EVENT_SIGNAL(ev);
+               struct timespec timeout = { 0, 0 };
 
-               memset(&kev, 0, sizeof(kev));
-               kev.ident = nsignal;
-               kev.filter = EVFILT_SIGNAL;
-               kev.flags = EV_DELETE;
+               assert(nsignal >= 0 && nsignal < NSIG);
+               TAILQ_REMOVE(&kqop->evsigevents[nsignal], ev, ev_signal_next);
+               if (TAILQ_EMPTY(&kqop->evsigevents[nsignal])) {
+                       memset(&kev, 0, sizeof(kev));
+                       kev.ident = nsignal;
+                       kev.filter = EVFILT_SIGNAL;
+                       kev.flags = EV_DELETE;
                
-               if (kq_insert(kqop, &kev) == -1)
-                       return (-1);
-
-               if (_evsignal_restore_handler(ev->ev_base, nsignal) == -1)
-                       return (-1);
+                       /* Because we insert signal events
+                        * immediately, we need to delete them
+                        * immediately, too */
+                       if (kevent(kqop->kq, &kev, 1, NULL, 0, &timeout) == -1)
+                               return (-1);
+
+                       if (_evsignal_restore_handler(ev->ev_base,
+                               nsignal) == -1)
+                               return (-1);
+               }
 
                ev->ev_flags &= ~EVLIST_X_KQINKERNEL;
                return (0);
Index: log.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/log.c,v
retrieving revision 1.2
diff -u -r1.2 log.c
--- log.c       16 May 2008 20:24:58 -0000      1.2
+++ log.c       8 Jul 2009 04:47:42 -0000
@@ -48,6 +48,7 @@
 #include <string.h>
 #include <errno.h>
 #include "event.h"
+#include "evutil.h"
 
 #include "log.h"
 
@@ -55,33 +56,6 @@
                          va_list ap);
 static void event_log(int severity, const char *msg);
 
-static int
-event_vsnprintf(char *str, size_t size, const char *format, va_list args)
-{
-       int r;
-       if (size == 0)
-               return -1;
-       r = vsnprintf(str, size, format, args);
-       str[size-1] = '\0';
-       if (r < 0 || ((size_t)r) >= size) {
-               /* different platforms behave differently on overflow;
-                * handle both kinds. */
-               return -1;
-       }
-       return r;
-}
-
-static int
-event_snprintf(char *str, size_t size, const char *format, ...)
-{
-    va_list ap;
-    int r;
-    va_start(ap, format);
-    r = event_vsnprintf(str, size, format, ap);
-    va_end(ap);
-    return r;
-}
-
 void
 event_err(int eval, const char *fmt, ...)
 {
@@ -151,14 +125,14 @@
        size_t len;
 
        if (fmt != NULL)
-               event_vsnprintf(buf, sizeof(buf), fmt, ap);
+               evutil_vsnprintf(buf, sizeof(buf), fmt, ap);
        else
                buf[0] = '\0';
 
        if (log_errno >= 0) {
                len = strlen(buf);
                if (len < sizeof(buf) - 3) {
-                       event_snprintf(buf + len, sizeof(buf) - len, ": %s",
+                       evutil_snprintf(buf + len, sizeof(buf) - len, ": %s",
                            strerror(log_errno));
                }
        }
Index: min_heap.h
===================================================================
RCS file: /cvsroot/src/lib/libevent/min_heap.h,v
retrieving revision 1.1
diff -u -r1.1 min_heap.h
--- min_heap.h  16 May 2008 20:24:58 -0000      1.1
+++ min_heap.h  8 Jul 2009 04:47:42 -0000
@@ -76,8 +76,8 @@
     if(s->n)
     {
         struct event* e = *s->p;
-        e->min_heap_idx = -1;
         min_heap_shift_down_(s, 0u, s->p[--s->n]);
+        e->min_heap_idx = -1;
         return e;
     }
     return 0;
@@ -87,7 +87,17 @@
 {
     if(((unsigned int)-1) != e->min_heap_idx)
     {
-        min_heap_shift_down_(s, e->min_heap_idx, s->p[--s->n]);
+        struct event *last = s->p[--s->n];
+        unsigned parent = (e->min_heap_idx - 1) / 2;
+       /* we replace e with the last element in the heap.  We might need to
+          shift it upward if it is less than its parent, or downward if it is
+          greater than one or both its children. Since the children are known
+          to be less than the parent, it can't need to shift both up and
+          down. */
+        if (e->min_heap_idx > 0 && min_heap_elem_greater(s->p[parent], last))
+             min_heap_shift_up_(s, e->min_heap_idx, last);
+        else
+             min_heap_shift_down_(s, e->min_heap_idx, last);
         e->min_heap_idx = -1;
         return 0;
     }
Index: poll.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/poll.c,v
retrieving revision 1.7
diff -u -r1.7 poll.c
--- poll.c      16 May 2008 20:24:58 -0000      1.7
+++ poll.c      8 Jul 2009 04:47:43 -0000
@@ -30,9 +30,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <sys/types.h>
 #ifdef HAVE_SYS_TIME_H
Index: shlib_version
===================================================================
RCS file: /cvsroot/src/lib/libevent/shlib_version,v
retrieving revision 1.5
diff -u -r1.5 shlib_version
--- shlib_version       11 Jan 2009 03:07:48 -0000      1.5
+++ shlib_version       8 Jul 2009 04:47:43 -0000
@@ -2,4 +2,4 @@
 #      Remember to update distrib/sets/lists/base/shl.* when changing
 #
 major=3
-minor=0
+minor=1
Index: signal.c
===================================================================
RCS file: /cvsroot/src/lib/libevent/signal.c,v
retrieving revision 1.6
diff -u -r1.6 signal.c
--- signal.c    16 May 2008 20:24:58 -0000      1.6
+++ signal.c    8 Jul 2009 04:47:43 -0000
@@ -30,9 +30,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include <sys/types.h>
 #ifdef HAVE_SYS_TIME_H
@@ -69,7 +67,7 @@
 static void
 evsignal_cb(int fd, short what, void *arg)
 {
-       static char signals[100];
+       static char signals[1];
        ssize_t n;
 
        n = recv(fd, signals, sizeof(signals), 0);
@@ -89,12 +87,15 @@
 void
 evsignal_init(struct event_base *base)
 {
+       int i;
+
        /* 
         * Our signal handler is going to write to one end of the socket
         * pair to wake up our event loop.  The event loop then scans for
         * signals that got delivered.
         */
-       if (evutil_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]);
@@ -103,6 +104,9 @@
        base->sig.sh_old_max = 0;
        base->sig.evsignal_caught = 0;
        memset(&base->sig.evsigcaught, 0, sizeof(sig_atomic_t)*NSIG);
+       /* initialize the queues for all events */
+       for (i = 0; i < NSIG; ++i)
+               TAILQ_INIT(&base->sig.evsigevents[i]);
 
         evutil_make_socket_nonblocking(base->sig.ev_signal_pair[0]);
 
@@ -131,14 +135,19 @@
         * a dynamic array is used to keep footprint on the low side.
         */
        if (evsignal >= sig->sh_old_max) {
+               int new_max = evsignal + 1;
                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);
+               p = realloc(sig->sh_old, new_max * sizeof(*sig->sh_old));
                if (p == NULL) {
                        event_warn("realloc");
                        return (-1);
                }
+
+               memset((char *)p + sig->sh_old_max * sizeof(*sig->sh_old),
+                   0, (new_max - sig->sh_old_max) * sizeof(*sig->sh_old));
+
+               sig->sh_old_max = new_max;
                sig->sh_old = p;
        }
 
@@ -183,19 +192,26 @@
        if (ev->ev_events & (EV_READ|EV_WRITE))
                event_errx(1, "%s: EV_SIGNAL incompatible use", __func__);
        evsignal = EVENT_SIGNAL(ev);
+       assert(evsignal >= 0 && evsignal < NSIG);
+       if (TAILQ_EMPTY(&sig->evsigevents[evsignal])) {
+               event_debug(("%s: %p: changing signal handler", __func__, ev));
+               if (_evsignal_set_handler(
+                           base, evsignal, evsignal_handler) == -1)
+                       return (-1);
 
-       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;
+               /* catch signals if they happen quickly */
+               evsignal_base = base;
 
-       if (!sig->ev_signal_added) {
-               sig->ev_signal_added = 1;
-               event_add(&sig->ev_signal, NULL);
+               if (!sig->ev_signal_added) {
+                       if (event_add(&sig->ev_signal, NULL))
+                               return (-1);
+                       sig->ev_signal_added = 1;
+               }
        }
 
+       /* multiple events may listen to the same signal */
+       TAILQ_INSERT_TAIL(&sig->evsigevents[evsignal], ev, ev_signal_next);
+
        return (0);
 }
 
@@ -232,8 +248,21 @@
 int
 evsignal_del(struct event *ev)
 {
+       struct event_base *base = ev->ev_base;
+       struct evsignal_info *sig = &base->sig;
+       int evsignal = EVENT_SIGNAL(ev);
+
+       assert(evsignal >= 0 && evsignal < NSIG);
+
+       /* multiple events may listen to the same signal */
+       TAILQ_REMOVE(&sig->evsigevents[evsignal], ev, ev_signal_next);
+
+       if (!TAILQ_EMPTY(&sig->evsigevents[evsignal]))
+               return (0);
+
        event_debug(("%s: %p: restoring signal handler", __func__, ev));
-       return _evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev));
+
+       return (_evsignal_restore_handler(ev->ev_base, EVENT_SIGNAL(ev)));
 }
 
 static void
@@ -241,7 +270,7 @@
 {
        int save_errno = errno;
 
-       if(evsignal_base == NULL) {
+       if (evsignal_base == NULL) {
                event_warn(
                        "%s: received signal %d, but have no base configured",
                        __func__, sig);
@@ -263,29 +292,41 @@
 void
 evsignal_process(struct event_base *base)
 {
-       struct event *ev;
+       struct evsignal_info *sig = &base->sig;
+       struct event *ev, *next_ev;
        sig_atomic_t ncalls;
-
+       int i;
+       
        base->sig.evsignal_caught = 0;
-       TAILQ_FOREACH(ev, &base->sig.signalqueue, ev_signal_next) {
-               ncalls = base->sig.evsigcaught[EVENT_SIGNAL(ev)];
-               if (ncalls) {
+       for (i = 1; i < NSIG; ++i) {
+               ncalls = sig->evsigcaught[i];
+               if (ncalls == 0)
+                       continue;
+               sig->evsigcaught[i] -= ncalls;
+
+               for (ev = TAILQ_FIRST(&sig->evsigevents[i]);
+                   ev != NULL; ev = next_ev) {
+                       next_ev = TAILQ_NEXT(ev, ev_signal_next);
                        if (!(ev->ev_events & EV_PERSIST))
                                event_del(ev);
                        event_active(ev, EV_SIGNAL, ncalls);
-                       base->sig.evsigcaught[EVENT_SIGNAL(ev)] = 0;
                }
+
        }
 }
 
 void
 evsignal_dealloc(struct event_base *base)
 {
-       if(base->sig.ev_signal_added) {
+       int i = 0;
+       if (base->sig.ev_signal_added) {
                event_del(&base->sig.ev_signal);
                base->sig.ev_signal_added = 0;
        }
-       assert(TAILQ_EMPTY(&base->sig.signalqueue));
+       for (i = 0; i < NSIG; ++i) {
+               if (i < base->sig.sh_old_max && base->sig.sh_old[i] != NULL)
+                       _evsignal_restore_handler(base, i);
+       }
 
        EVUTIL_CLOSESOCKET(base->sig.ev_signal_pair[0]);
        base->sig.ev_signal_pair[0] = -1;



Home | Main Index | Thread Index | Old Index