Skip to content

Commit 5e21388

Browse files
committed
Merge pull request #6695
ddf98d1 Make RPC tests cope with server-side timeout between requests (Wladimir J. van der Laan) 2190ea6 rpc: Split option -rpctimeout into -rpcservertimeout and -rpcclienttimeout (Wladimir J. van der Laan) 8b2d6ed http: Disable libevent debug logging, if not explicitly enabled (Wladimir J. van der Laan) 5ce43da init: Ignore SIGPIPE (Wladimir J. van der Laan)
2 parents b0ce450 + ddf98d1 commit 5e21388

File tree

6 files changed

+51
-23
lines changed

6 files changed

+51
-23
lines changed

contrib/debian/examples/bitcoin.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373

7474
# How many seconds bitcoin will wait for a complete RPC HTTP request.
7575
# after the HTTP connection is established.
76-
#rpctimeout=30
76+
#rpcclienttimeout=30
7777

7878
# By default, only RPC connections from localhost are allowed.
7979
# Specify as many rpcallowip= settings as you like to allow connections from other hosts,

qa/rpc-tests/test_framework/authproxy.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,26 @@ def __getattr__(self, name):
106106
name = "%s.%s" % (self.__service_name, name)
107107
return AuthServiceProxy(self.__service_url, name, connection=self.__conn)
108108

109+
def _request(self, method, path, postdata):
110+
'''
111+
Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout).
112+
This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5.
113+
'''
114+
headers = {'Host': self.__url.hostname,
115+
'User-Agent': USER_AGENT,
116+
'Authorization': self.__auth_header,
117+
'Content-type': 'application/json'}
118+
try:
119+
self.__conn.request(method, path, postdata, headers)
120+
return self._get_response()
121+
except httplib.BadStatusLine as e:
122+
if e.line == "''": # if connection was closed, try again
123+
self.__conn.close()
124+
self.__conn.request(method, path, postdata, headers)
125+
return self._get_response()
126+
else:
127+
raise
128+
109129
def __call__(self, *args):
110130
AuthServiceProxy.__id_count += 1
111131

@@ -115,13 +135,7 @@ def __call__(self, *args):
115135
'method': self.__service_name,
116136
'params': args,
117137
'id': AuthServiceProxy.__id_count}, default=EncodeDecimal)
118-
self.__conn.request('POST', self.__url.path, postdata,
119-
{'Host': self.__url.hostname,
120-
'User-Agent': USER_AGENT,
121-
'Authorization': self.__auth_header,
122-
'Content-type': 'application/json'})
123-
124-
response = self._get_response()
138+
response = self._request('POST', self.__url.path, postdata)
125139
if response['error'] is not None:
126140
raise JSONRPCException(response['error'])
127141
elif 'result' not in response:
@@ -133,13 +147,7 @@ def __call__(self, *args):
133147
def _batch(self, rpc_call_list):
134148
postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal)
135149
log.debug("--> "+postdata)
136-
self.__conn.request('POST', self.__url.path, postdata,
137-
{'Host': self.__url.hostname,
138-
'User-Agent': USER_AGENT,
139-
'Authorization': self.__auth_header,
140-
'Content-type': 'application/json'})
141-
142-
return self._get_response()
150+
return self._request('POST', self.__url.path, postdata)
143151

144152
def _get_response(self):
145153
http_response = self.__conn.getresponse()

src/bitcoin-cli.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222

2323
using namespace std;
2424

25+
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
26+
2527
std::string HelpMessageCli()
2628
{
2729
string strUsage;
@@ -37,6 +39,7 @@ std::string HelpMessageCli()
3739
strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
3840
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
3941
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
42+
strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
4043

4144
return strUsage;
4245
}
@@ -150,7 +153,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
150153
struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
151154
if (evcon == NULL)
152155
throw runtime_error("create connection failed");
153-
evhttp_connection_set_timeout(evcon, GetArg("-rpctimeout", 30));
156+
evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
154157

155158
HTTPReply response;
156159
struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII

src/httpserver.cpp

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,15 @@ static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
320320
queue->Run();
321321
}
322322

323+
/** libevent event log callback */
324+
static void libevent_log_cb(int severity, const char *msg)
325+
{
326+
if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category
327+
LogPrintf("libevent: %s\n", msg);
328+
else
329+
LogPrint("libevent", "libevent: %s\n", msg);
330+
}
331+
323332
bool InitHTTPServer()
324333
{
325334
struct evhttp* http = 0;
@@ -335,6 +344,16 @@ bool InitHTTPServer()
335344
return false;
336345
}
337346

347+
// Redirect libevent's logging to our own log
348+
event_set_log_callback(&libevent_log_cb);
349+
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
350+
// If -debug=libevent, set full libevent debugging.
351+
// Otherwise, disable all libevent debugging.
352+
if (LogAcceptCategory("libevent"))
353+
event_enable_debug_logging(EVENT_DBG_ALL);
354+
else
355+
event_enable_debug_logging(EVENT_DBG_NONE);
356+
#endif
338357
#ifdef WIN32
339358
evthread_use_windows_threads();
340359
#else
@@ -355,7 +374,7 @@ bool InitHTTPServer()
355374
return false;
356375
}
357376

358-
evhttp_set_timeout(http, GetArg("-rpctimeout", DEFAULT_HTTP_TIMEOUT));
377+
evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
359378
evhttp_set_max_body_size(http, MAX_SIZE);
360379
evhttp_set_gencb(http, http_request_cb, NULL);
361380

src/httpserver.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
static const int DEFAULT_HTTP_THREADS=4;
1515
static const int DEFAULT_HTTP_WORKQUEUE=16;
16-
static const int DEFAULT_HTTP_TIMEOUT=30;
16+
static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;
1717

1818
struct evhttp_request;
1919
struct event_base;

src/init.cpp

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ std::string HelpMessage(HelpMessageMode mode)
416416
strUsage += HelpMessageOpt("-limitdescendantcount=<n>", strprintf("Do not accept transactions if any ancestor would have <n> or more in-mempool descendants (default: %u)", DEFAULT_DESCENDANT_LIMIT));
417417
strUsage += HelpMessageOpt("-limitdescendantsize=<n>", strprintf("Do not accept transactions if any ancestor would have more than <n> kilobytes of in-mempool descendants (default: %u).", DEFAULT_DESCENDANT_SIZE_LIMIT));
418418
}
419-
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http"; // Don't translate these and qt below
419+
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http, libevent"; // Don't translate these and qt below
420420
if (mode == HMM_BITCOIN_QT)
421421
debugCategories += ", qt";
422422
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
@@ -469,7 +469,7 @@ std::string HelpMessage(HelpMessageMode mode)
469469
strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS));
470470
if (showDebug) {
471471
strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE));
472-
strUsage += HelpMessageOpt("-rpctimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_TIMEOUT));
472+
strUsage += HelpMessageOpt("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT));
473473
}
474474

475475
if (mode == HMM_BITCOIN_QT)
@@ -716,10 +716,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
716716
sa_hup.sa_flags = 0;
717717
sigaction(SIGHUP, &sa_hup, NULL);
718718

719-
#if defined (__SVR4) && defined (__sun)
720-
// ignore SIGPIPE on Solaris
719+
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
721720
signal(SIGPIPE, SIG_IGN);
722-
#endif
723721
#endif
724722

725723
// ********************************************************* Step 2: parameter interactions

0 commit comments

Comments
 (0)