diff --git a/bufferevent-internal.h b/bufferevent-internal.h index 8c45fe9c..8d12a4e8 100644 --- a/bufferevent-internal.h +++ b/bufferevent-internal.h @@ -37,6 +37,7 @@ extern "C" { #include "evthread-internal.h" #include "event2/thread.h" #include "ratelim-internal.h" +#include "event2/bufferevent_struct.h" /* These flags are reasons that we might be declining to actually enable reading or writing on a bufferevent. @@ -288,6 +289,20 @@ void bufferevent_unsuspend_write(struct bufferevent *bufev, bufferevent_suspend_ #define bufferevent_wm_unsuspend_read(b) \ bufferevent_unsuspend_read((b), BEV_SUSPEND_WM) +/* + Disable a bufferevent. Equivalent to bufferevent_disable(), but + first resets 'connecting' flag to force EV_WRITE down for sure. + + XXXX this method will go away in the future; try not to add new users. + See comment in evhttp_connection_reset() for discussion. + + @param bufev the bufferevent to be disabled + @param event any combination of EV_READ | EV_WRITE. + @return 0 if successful, or -1 if an error occurred + @see bufferevent_disable() + */ +int bufferevent_disable_hard(struct bufferevent *bufev, short event); + /** Internal: Set up locking on a bufferevent. If lock is set, use it. * Otherwise, use a new lock. */ int bufferevent_enable_locking(struct bufferevent *bufev, void *lock); diff --git a/bufferevent.c b/bufferevent.c index 876a83f4..e1e9e47d 100644 --- a/bufferevent.c +++ b/bufferevent.c @@ -474,6 +474,24 @@ bufferevent_settimeout(struct bufferevent *bufev, } +int +bufferevent_disable_hard(struct bufferevent *bufev, short event) +{ + int r = 0; + struct bufferevent_private *bufev_private = + EVUTIL_UPCAST(bufev, struct bufferevent_private, bev); + + BEV_LOCK(bufev); + bufev->enabled &= ~event; + + bufev_private->connecting = 0; + if (bufev->be_ops->disable(bufev, event) < 0) + r = -1; + + BEV_UNLOCK(bufev); + return r; +} + int bufferevent_disable(struct bufferevent *bufev, short event) { diff --git a/http.c b/http.c index 575623aa..e9eb3521 100644 --- a/http.c +++ b/http.c @@ -101,6 +101,7 @@ #include "util-internal.h" #include "http-internal.h" #include "mm-internal.h" +#include "bufferevent-internal.h" #ifndef _EVENT_HAVE_GETNAMEINFO #define NI_MAXSERV 32 @@ -1157,7 +1158,18 @@ evhttp_connection_reset(struct evhttp_connection *evcon) { struct evbuffer *tmp; - bufferevent_disable(evcon->bufev, EV_READ|EV_WRITE); + /* XXXX This is not actually an optimal fix. Instead we ought to have + an API for "stop connecting", or use bufferevent_setfd to turn off + connecting. But for Libevent 2.0, this seems like a minimal change + least likely to disrupt the rest of the bufferevent and http code. + + Why is this here? If the fd is set in the bufferevent, and the + bufferevent is connecting, then you can't actually stop the + bufferevent from trying to connect with bufferevent_disable(). The + connect will never trigger, since we close the fd, but the timeout + might. That caused an assertion failure in evhttp_connection_fail. + */ + bufferevent_disable_hard(evcon->bufev, EV_READ|EV_WRITE); if (evcon->fd != -1) { /* inform interested parties about connection close */