This looks awesome.  Is it possible to add a regression test that triggers
the behavior?

On Mon, May 9, 2011 at 11:46 PM, Kevin Ko <kevin.s...@gmail.com> wrote:

> Hi,
>
> Patch in question:
>  -
> Fix the case when failed evhttp_make_request() leaved request in the queue.
>  -
> http://levent.git.sourceforge.net/git/gitweb.cgi?p=levent/libevent;a=commit;h=0d6622e
>
> The above patch introduces a failing assertion in
> evhttp_connection_fail().  This happens because the patch defers the
> assignment of the outstanding request to the evcon->requests list,
> while evhttp_connection_fail() assumes that the request lies in the
> list.
>
> One scenario in which this can happen is when the request list is
> empty and a connection is made to an unreachable host.  The assertion
> will then fail after bufferevent_socket_connect() errors out (with
> ENETUNREACH in my case).
>
> At the end of this message, I've attached a gdb backtrace of an
> instance with the failed assertion and a patch that should revise the
> original solution to have an effect only when
> evhttp_connection_connect() fails.
>
> Kevin
>
> ***** begin gdb backtrace *****
>
> #0  0xb7fe2430 in __kernel_vsyscall ()
> #1  0xb7e8f651 in *__GI_raise (sig=6)
>    at ../nptl/sysdeps/unix/sysv/linux/raise.c:64
> #2  0xb7e92a82 in *__GI_abort () at abort.c:92
> #3  0x08090a8f in event_exit (errcode=-559030611) at log.c:79
> #4  0x08090be9 in event_errx (eval=-559030611,
>    fmt=0x80d3e78 "%s:%d: Assertion %s failed in %s") at log.c:136
> #5  0x080894ec in evhttp_connection_fail (evcon=0x8572480,
>     error=EVCON_HTTP_EOF) at http.c:689
> #6  0x0808a766 in evhttp_error_cb (bufev=0x8572560, what=32, arg=0x8572480)
>     at http.c:1327
> #7  0x0808a7ce in evhttp_connection_cb (bufev=0x8572560, what=32,
>     arg=0x8572480) at http.c:1352
> #8  0x0807cde5 in _bufferevent_run_eventcb (bufev=0x8572560, what=32)
>     at bufferevent.c:264
> #9  0x0807fcce in bufferevent_socket_connect (bev=0x8572560, sa=0x8571bd0,
>     socklen=16) at bufferevent_sock.c:420
> #10 0x0807fd9a in bufferevent_connect_getaddrinfo_cb (result=0,
> ai=0x8571bb0,
>     arg=0x8572560) at bufferevent_sock.c:453
> #11 0x080872ac in evutil_getaddrinfo_async (dns_base=0x0,
>     nodename=0x8572548 "72.14.204.141", servname=0xbfffe1c2 "80",
>     hints_in=0xbfffe198, cb=0x807fcfe <bufferevent_connect_getaddrinfo_cb>,
>     arg=0x8572560) at evutil.c:1396
> #12 0x0807fed4 in bufferevent_socket_connect_hostname (bev=0x8572560,
>     evdns_base=0x0, family=0, hostname=0x8572548 "72.14.204.141", port=80)
>     at bufferevent_sock.c:489
> #13 0x0808bee8 in evhttp_connection_connect (evcon=0x8572480) at
> http.c:2148
> #14 0x0808c0a1 in evhttp_make_request (evcon=0x8572480, req=0x85715b0,
>     type=EVHTTP_REQ_POST, uri=0x855b640 "/verify") at http.c:2199
>
> ***** end gdb backtrace *****
>
> ***** begin patch *****
>
> diff --git a/libevent2/http.c b/libevent2/http.c
> index 06fe614..0797b5a 100644
> --- a/libevent2/http.c
> +++ b/libevent2/http.c
> @@ -2194,21 +2194,21 @@ evhttp_make_request(struct evhttp_connection
> *evcon,
>         req->evcon = evcon;
>         EVUTIL_ASSERT(!(req->flags & EVHTTP_REQ_OWN_CONNECTION));
>
> +       TAILQ_INSERT_TAIL(&evcon->requests, req, next);
> +
>         /* If the connection object is not connected; make it so */
>         if (!evhttp_connected(evcon)) {
>                 int res = evhttp_connection_connect(evcon);
> -               /*
> -                * Enqueue the request only if we aren't going to
> -                * return failure from evhttp_make_request().
> -                */
> -               if (res == 0)
> -                       TAILQ_INSERT_TAIL(&evcon->requests, req, next);
> +               /* evhttp_connection_fail(), which is called through
> +                * evhttp_connection_connect(), assumes that req lies in
> +                * evcon->requests.  Thus, enqueue the request in advance
> and r
> +                * it in the error case. */
> +               if (res != 0)
> +                       TAILQ_REMOVE(&evcon->requests, req, next);
>
>                 return res;
>         }
>
> -       TAILQ_INSERT_TAIL(&evcon->requests, req, next);
> -
>         /*
>          * If it's connected already and we are the first in the queue,
>          * then we can dispatch this request immediately.  Otherwise, it
>
> ***** end patch *****
> ***********************************************************************
> To unsubscribe, send an e-mail to majord...@freehaven.net with
> unsubscribe libevent-users    in the body.
>

Reply via email to