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)
This commit is contained in:
commit
5e21388c48
@ -73,7 +73,7 @@
|
|||||||
|
|
||||||
# How many seconds bitcoin will wait for a complete RPC HTTP request.
|
# How many seconds bitcoin will wait for a complete RPC HTTP request.
|
||||||
# after the HTTP connection is established.
|
# after the HTTP connection is established.
|
||||||
#rpctimeout=30
|
#rpcclienttimeout=30
|
||||||
|
|
||||||
# By default, only RPC connections from localhost are allowed.
|
# By default, only RPC connections from localhost are allowed.
|
||||||
# Specify as many rpcallowip= settings as you like to allow connections from other hosts,
|
# Specify as many rpcallowip= settings as you like to allow connections from other hosts,
|
||||||
|
@ -106,6 +106,26 @@ class AuthServiceProxy(object):
|
|||||||
name = "%s.%s" % (self.__service_name, name)
|
name = "%s.%s" % (self.__service_name, name)
|
||||||
return AuthServiceProxy(self.__service_url, name, connection=self.__conn)
|
return AuthServiceProxy(self.__service_url, name, connection=self.__conn)
|
||||||
|
|
||||||
|
def _request(self, method, path, postdata):
|
||||||
|
'''
|
||||||
|
Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout).
|
||||||
|
This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5.
|
||||||
|
'''
|
||||||
|
headers = {'Host': self.__url.hostname,
|
||||||
|
'User-Agent': USER_AGENT,
|
||||||
|
'Authorization': self.__auth_header,
|
||||||
|
'Content-type': 'application/json'}
|
||||||
|
try:
|
||||||
|
self.__conn.request(method, path, postdata, headers)
|
||||||
|
return self._get_response()
|
||||||
|
except httplib.BadStatusLine as e:
|
||||||
|
if e.line == "''": # if connection was closed, try again
|
||||||
|
self.__conn.close()
|
||||||
|
self.__conn.request(method, path, postdata, headers)
|
||||||
|
return self._get_response()
|
||||||
|
else:
|
||||||
|
raise
|
||||||
|
|
||||||
def __call__(self, *args):
|
def __call__(self, *args):
|
||||||
AuthServiceProxy.__id_count += 1
|
AuthServiceProxy.__id_count += 1
|
||||||
|
|
||||||
@ -115,13 +135,7 @@ class AuthServiceProxy(object):
|
|||||||
'method': self.__service_name,
|
'method': self.__service_name,
|
||||||
'params': args,
|
'params': args,
|
||||||
'id': AuthServiceProxy.__id_count}, default=EncodeDecimal)
|
'id': AuthServiceProxy.__id_count}, default=EncodeDecimal)
|
||||||
self.__conn.request('POST', self.__url.path, postdata,
|
response = self._request('POST', self.__url.path, postdata)
|
||||||
{'Host': self.__url.hostname,
|
|
||||||
'User-Agent': USER_AGENT,
|
|
||||||
'Authorization': self.__auth_header,
|
|
||||||
'Content-type': 'application/json'})
|
|
||||||
|
|
||||||
response = self._get_response()
|
|
||||||
if response['error'] is not None:
|
if response['error'] is not None:
|
||||||
raise JSONRPCException(response['error'])
|
raise JSONRPCException(response['error'])
|
||||||
elif 'result' not in response:
|
elif 'result' not in response:
|
||||||
@ -133,13 +147,7 @@ class AuthServiceProxy(object):
|
|||||||
def _batch(self, rpc_call_list):
|
def _batch(self, rpc_call_list):
|
||||||
postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal)
|
postdata = json.dumps(list(rpc_call_list), default=EncodeDecimal)
|
||||||
log.debug("--> "+postdata)
|
log.debug("--> "+postdata)
|
||||||
self.__conn.request('POST', self.__url.path, postdata,
|
return self._request('POST', self.__url.path, postdata)
|
||||||
{'Host': self.__url.hostname,
|
|
||||||
'User-Agent': USER_AGENT,
|
|
||||||
'Authorization': self.__auth_header,
|
|
||||||
'Content-type': 'application/json'})
|
|
||||||
|
|
||||||
return self._get_response()
|
|
||||||
|
|
||||||
def _get_response(self):
|
def _get_response(self):
|
||||||
http_response = self.__conn.getresponse()
|
http_response = self.__conn.getresponse()
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900;
|
||||||
|
|
||||||
std::string HelpMessageCli()
|
std::string HelpMessageCli()
|
||||||
{
|
{
|
||||||
string strUsage;
|
string strUsage;
|
||||||
@ -37,6 +39,7 @@ std::string HelpMessageCli()
|
|||||||
strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
|
strUsage += HelpMessageOpt("-rpcwait", _("Wait for RPC server to start"));
|
||||||
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
|
strUsage += HelpMessageOpt("-rpcuser=<user>", _("Username for JSON-RPC connections"));
|
||||||
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
|
strUsage += HelpMessageOpt("-rpcpassword=<pw>", _("Password for JSON-RPC connections"));
|
||||||
|
strUsage += HelpMessageOpt("-rpcclienttimeout=<n>", strprintf(_("Timeout during HTTP requests (default: %d)"), DEFAULT_HTTP_CLIENT_TIMEOUT));
|
||||||
|
|
||||||
return strUsage;
|
return strUsage;
|
||||||
}
|
}
|
||||||
@ -150,7 +153,7 @@ UniValue CallRPC(const string& strMethod, const UniValue& params)
|
|||||||
struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
|
struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII
|
||||||
if (evcon == NULL)
|
if (evcon == NULL)
|
||||||
throw runtime_error("create connection failed");
|
throw runtime_error("create connection failed");
|
||||||
evhttp_connection_set_timeout(evcon, GetArg("-rpctimeout", 30));
|
evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT));
|
||||||
|
|
||||||
HTTPReply response;
|
HTTPReply response;
|
||||||
struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
|
struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII
|
||||||
|
@ -320,6 +320,15 @@ static void HTTPWorkQueueRun(WorkQueue<HTTPClosure>* queue)
|
|||||||
queue->Run();
|
queue->Run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** libevent event log callback */
|
||||||
|
static void libevent_log_cb(int severity, const char *msg)
|
||||||
|
{
|
||||||
|
if (severity >= EVENT_LOG_WARN) // Log warn messages and higher without debug category
|
||||||
|
LogPrintf("libevent: %s\n", msg);
|
||||||
|
else
|
||||||
|
LogPrint("libevent", "libevent: %s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
bool InitHTTPServer()
|
bool InitHTTPServer()
|
||||||
{
|
{
|
||||||
struct evhttp* http = 0;
|
struct evhttp* http = 0;
|
||||||
@ -335,6 +344,16 @@ bool InitHTTPServer()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Redirect libevent's logging to our own log
|
||||||
|
event_set_log_callback(&libevent_log_cb);
|
||||||
|
#if LIBEVENT_VERSION_NUMBER >= 0x02010100
|
||||||
|
// If -debug=libevent, set full libevent debugging.
|
||||||
|
// Otherwise, disable all libevent debugging.
|
||||||
|
if (LogAcceptCategory("libevent"))
|
||||||
|
event_enable_debug_logging(EVENT_DBG_ALL);
|
||||||
|
else
|
||||||
|
event_enable_debug_logging(EVENT_DBG_NONE);
|
||||||
|
#endif
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
evthread_use_windows_threads();
|
evthread_use_windows_threads();
|
||||||
#else
|
#else
|
||||||
@ -355,7 +374,7 @@ bool InitHTTPServer()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
evhttp_set_timeout(http, GetArg("-rpctimeout", DEFAULT_HTTP_TIMEOUT));
|
evhttp_set_timeout(http, GetArg("-rpcservertimeout", DEFAULT_HTTP_SERVER_TIMEOUT));
|
||||||
evhttp_set_max_body_size(http, MAX_SIZE);
|
evhttp_set_max_body_size(http, MAX_SIZE);
|
||||||
evhttp_set_gencb(http, http_request_cb, NULL);
|
evhttp_set_gencb(http, http_request_cb, NULL);
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
static const int DEFAULT_HTTP_THREADS=4;
|
static const int DEFAULT_HTTP_THREADS=4;
|
||||||
static const int DEFAULT_HTTP_WORKQUEUE=16;
|
static const int DEFAULT_HTTP_WORKQUEUE=16;
|
||||||
static const int DEFAULT_HTTP_TIMEOUT=30;
|
static const int DEFAULT_HTTP_SERVER_TIMEOUT=30;
|
||||||
|
|
||||||
struct evhttp_request;
|
struct evhttp_request;
|
||||||
struct event_base;
|
struct event_base;
|
||||||
|
@ -416,7 +416,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
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));
|
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));
|
||||||
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));
|
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));
|
||||||
}
|
}
|
||||||
string debugCategories = "addrman, alert, bench, coindb, db, lock, rand, rpc, selectcoins, mempool, mempoolrej, net, proxy, prune, http"; // Don't translate these and qt below
|
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
|
||||||
if (mode == HMM_BITCOIN_QT)
|
if (mode == HMM_BITCOIN_QT)
|
||||||
debugCategories += ", qt";
|
debugCategories += ", qt";
|
||||||
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
|
strUsage += HelpMessageOpt("-debug=<category>", strprintf(_("Output debugging information (default: %u, supplying <category> is optional)"), 0) + ". " +
|
||||||
@ -469,7 +469,7 @@ std::string HelpMessage(HelpMessageMode mode)
|
|||||||
strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS));
|
strUsage += HelpMessageOpt("-rpcthreads=<n>", strprintf(_("Set the number of threads to service RPC calls (default: %d)"), DEFAULT_HTTP_THREADS));
|
||||||
if (showDebug) {
|
if (showDebug) {
|
||||||
strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE));
|
strUsage += HelpMessageOpt("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE));
|
||||||
strUsage += HelpMessageOpt("-rpctimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_TIMEOUT));
|
strUsage += HelpMessageOpt("-rpcservertimeout=<n>", strprintf("Timeout during HTTP requests (default: %d)", DEFAULT_HTTP_SERVER_TIMEOUT));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mode == HMM_BITCOIN_QT)
|
if (mode == HMM_BITCOIN_QT)
|
||||||
@ -716,10 +716,8 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
|
|||||||
sa_hup.sa_flags = 0;
|
sa_hup.sa_flags = 0;
|
||||||
sigaction(SIGHUP, &sa_hup, NULL);
|
sigaction(SIGHUP, &sa_hup, NULL);
|
||||||
|
|
||||||
#if defined (__SVR4) && defined (__sun)
|
// Ignore SIGPIPE, otherwise it will bring the daemon down if the client closes unexpectedly
|
||||||
// ignore SIGPIPE on Solaris
|
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ********************************************************* Step 2: parameter interactions
|
// ********************************************************* Step 2: parameter interactions
|
||||||
|
Loading…
Reference in New Issue
Block a user