diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2017-11-02 20:10:23 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2017-11-02 20:11:08 +0100 |
commit | 7008b07005c50ca2865ead36f5b3cee0c8d1bacc (patch) | |
tree | 414e328707fadb3c89c1eb8eb07ebd04fb7a24c3 /src | |
parent | bfb270acfa30713dc8c968bb9ee40cf5a2360359 (diff) | |
parent | 97932cd2689659addfbb58dc6148928b73af3bd0 (diff) |
Merge #11593: rpc: work-around an upstream libevent bug
97932cd rpc: further constrain the libevent workaround (Cory Fields)
6b58360 rpc: work-around an upstream libevent bug (Cory Fields)
Pull request description:
A rare race condition may trigger while awaiting the body of a message.
This may fix some reported rpc hangs/crashes.
This work-around mimics what libevent does internally once a write has started, which is what usually happens, but not always due to the processing happening on a different thread: https://github.com/libevent/libevent/blob/e7ff4ef2b4fc950a765008c18e74281cdb5e7668/http.c#L373
Fixed upstream at: https://github.com/libevent/libevent/commit/5ff8eb26371c4dc56f384b2de35bea2d87814779
Tree-SHA512: b9fa97cae9da2a44101c5faf1e3be0b9cbdf722982d35541cf224be31430779c75e519c8ed18d06ab7487bfb1211069b28f22739f126d6c28ca62d3f73b79a52
Diffstat (limited to 'src')
-rw-r--r-- | src/httpserver.cpp | 28 |
1 files changed, 26 insertions, 2 deletions
diff --git a/src/httpserver.cpp b/src/httpserver.cpp index 31b6a3705b..f6cbaa20b7 100644 --- a/src/httpserver.cpp +++ b/src/httpserver.cpp @@ -24,6 +24,7 @@ #include <event2/thread.h> #include <event2/buffer.h> +#include <event2/bufferevent.h> #include <event2/util.h> #include <event2/keyvalq_struct.h> @@ -239,6 +240,16 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m) /** HTTP request callback */ static void http_request_cb(struct evhttp_request* req, void* arg) { + // Disable reading to work around a libevent bug, fixed in 2.2.0. + if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { + evhttp_connection* conn = evhttp_request_get_connection(req); + if (conn) { + bufferevent* bev = evhttp_connection_get_bufferevent(conn); + if (bev) { + bufferevent_disable(bev, EV_READ); + } + } + } std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req)); LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n", @@ -601,8 +612,21 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply) struct evbuffer* evb = evhttp_request_get_output_buffer(req); assert(evb); evbuffer_add(evb, strReply.data(), strReply.size()); - HTTPEvent* ev = new HTTPEvent(eventBase, true, - std::bind(evhttp_send_reply, req, nStatus, (const char*)nullptr, (struct evbuffer *)nullptr)); + auto req_copy = req; + HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{ + evhttp_send_reply(req_copy, nStatus, nullptr, nullptr); + // Re-enable reading from the socket. This is the second part of the libevent + // workaround above. + if (event_get_version_number() >= 0x02010600 && event_get_version_number() < 0x02020001) { + evhttp_connection* conn = evhttp_request_get_connection(req_copy); + if (conn) { + bufferevent* bev = evhttp_connection_get_bufferevent(conn); + if (bev) { + bufferevent_enable(bev, EV_READ | EV_WRITE); + } + } + } + }); ev->trigger(nullptr); replySent = true; req = nullptr; // transferred back to main thread |