diff options
author | Cory Fields <cory-nospam-@coryfields.com> | 2017-11-01 12:02:57 -0400 |
---|---|---|
committer | Cory Fields <cory-nospam-@coryfields.com> | 2017-11-01 17:49:07 -0400 |
commit | 6b58360f9b64eb0b680a662fdfd590e47f115f44 (patch) | |
tree | 2e80850dcc9c56af25f4771648b67179994dee35 | |
parent | cffa5ee132f3ef6a8d138eb98d15da2b61999ca4 (diff) | |
download | bitcoin-6b58360f9b64eb0b680a662fdfd590e47f115f44.tar.xz |
rpc: work-around an upstream libevent bug
A rare race condition may trigger while awaiting the body of a message, see
upsteam commit 5ff8eb26371c4dc56f384b2de35bea2d87814779 for details.
This may fix some reported rpc hangs/crashes.
-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..63a634b244 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() < 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() < 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 |