Skip to content

Commit 75af065

Browse files
theunifurszy
authored andcommitted
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.
1 parent 50e5833 commit 75af065

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

src/httpserver.cpp

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <event2/http.h>
2727
#include <event2/thread.h>
2828
#include <event2/buffer.h>
29+
#include <event2/bufferevent.h>
2930
#include <event2/util.h>
3031
#include <event2/keyvalq_struct.h>
3132

@@ -251,6 +252,16 @@ static std::string RequestMethodString(HTTPRequest::RequestMethod m)
251252
/** HTTP request callback */
252253
static void http_request_cb(struct evhttp_request* req, void* arg)
253254
{
255+
// Disable reading to work around a libevent bug, fixed in 2.2.0.
256+
if (event_get_version_number() < 0x02020001) {
257+
evhttp_connection* conn = evhttp_request_get_connection(req);
258+
if (conn) {
259+
bufferevent* bev = evhttp_connection_get_bufferevent(conn);
260+
if (bev) {
261+
bufferevent_disable(bev, EV_READ);
262+
}
263+
}
264+
}
254265
std::unique_ptr<HTTPRequest> hreq(new HTTPRequest(req));
255266

256267
LogPrint(BCLog::HTTP, "Received a %s request for %s from %s\n",
@@ -615,9 +626,22 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
615626
struct evbuffer* evb = evhttp_request_get_output_buffer(req);
616627
assert(evb);
617628
evbuffer_add(evb, strReply.data(), strReply.size());
618-
HTTPEvent* ev = new HTTPEvent(eventBase, true,
619-
std::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
620-
ev->trigger(0);
629+
auto req_copy = req;
630+
HTTPEvent* ev = new HTTPEvent(eventBase, true, [req_copy, nStatus]{
631+
evhttp_send_reply(req_copy, nStatus, nullptr, nullptr);
632+
// Re-enable reading from the socket. This is the second part of the libevent
633+
// workaround above.
634+
if (event_get_version_number() < 0x02020001) {
635+
evhttp_connection* conn = evhttp_request_get_connection(req_copy);
636+
if (conn) {
637+
bufferevent* bev = evhttp_connection_get_bufferevent(conn);
638+
if (bev) {
639+
bufferevent_enable(bev, EV_READ | EV_WRITE);
640+
}
641+
}
642+
}
643+
});
644+
ev->trigger(nullptr);
621645
replySent = true;
622646
req = 0; // transferred back to main thread
623647
}

0 commit comments

Comments
 (0)