aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Maxwell <greg@xiph.org>2015-01-13 17:43:39 -0800
committerWladimir J. van der Laan <laanwj@gmail.com>2015-01-15 09:38:24 +0100
commitaaf55d25c6191c0effd5fa5dd5d2d0f17e715854 (patch)
tree9c438c4fb95a06ae231d68bbef302884dcd0fce6
parent249bf0e0492758d71dc5d8fa77103b31b604979f (diff)
downloadbitcoin-aaf55d25c6191c0effd5fa5dd5d2d0f17e715854.tar.xz
Add a -rpckeepalive and disable RPC use of HTTP persistent connections.
It turns out that some miners have been staying with old versions of Bitcoin Core because their software behaves poorly with persistent connections and the Bitcoin Core thread and connection limits. What happens is that underlying HTTP libraries leave connections open invisibly to their users and then the user runs into the default four thread limit. This looks like Bitcoin Core is unresponsive to RPC. There are many things that should be improved in Bitcoin Core's behavior here, e.g. supporting more concurrent connections, not tying up threads for idle connections, disconnecting kept-alive connections when limits are reached, etc. All are fairly big, risky changes. Disabling keep-alive is a simple workaround. It's often not easy to turn off the keep-alive support in the client where it may be buried in some platform library. If you are one of the few who really needs persistent connections you probably know that you want them and can find a switch; while if you don't and the misbehavior is hitting you it is hard to discover the source of your problems is keepalive related. Given that it is best to default to off until they're handled better. Github-Merge: #5655 Rebased-From: 16a5c18cea7330bd68dc9d2f768eb518af88795b 56c1093dae0c523f9f643f00c67414691272a983 1dd8ee72afc26191da51d8d3a5590eab7c9368f6
-rwxr-xr-xqa/rpc-tests/httpbasics.py30
-rwxr-xr-xqa/rpc-tests/test_framework.py5
-rw-r--r--src/init.cpp1
-rw-r--r--src/rpcserver.cpp2
4 files changed, 34 insertions, 4 deletions
diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py
index a94edaffa5..8cbf1d7f4c 100755
--- a/qa/rpc-tests/httpbasics.py
+++ b/qa/rpc-tests/httpbasics.py
@@ -20,7 +20,10 @@ try:
except ImportError:
import urlparse
-class RESTTest (BitcoinTestFramework):
+class HTTPBasicsTest (BitcoinTestFramework):
+ def setup_nodes(self):
+ return start_nodes(4, self.options.tmpdir, extra_args=[['-rpckeepalive=1'], ['-rpckeepalive=0'], [], []])
+
def run_test(self):
#################################################
@@ -71,6 +74,29 @@ class RESTTest (BitcoinTestFramework):
assert_equal('"error":null' in out1, True)
assert_equal(conn.sock!=None, False) #now the connection must be closed after the response
+ #node1 (2nd node) is running with disabled keep-alive option
+ urlNode1 = urlparse.urlparse(self.nodes[1].url)
+ authpair = urlNode1.username + ':' + urlNode1.password
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair)}
+
+ conn = httplib.HTTPConnection(urlNode1.hostname, urlNode1.port)
+ conn.connect()
+ conn.request('GET', '/', '{"method": "getbestblockhash"}', headers)
+ out1 = conn.getresponse().read();
+ assert_equal('"error":null' in out1, True)
+ assert_equal(conn.sock!=None, False) #connection must be closed because keep-alive was set to false
+
+ #node2 (third node) is running with standard keep-alive parameters which means keep-alive is off
+ urlNode2 = urlparse.urlparse(self.nodes[2].url)
+ authpair = urlNode2.username + ':' + urlNode2.password
+ headers = {"Authorization": "Basic " + base64.b64encode(authpair)}
+
+ conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port)
+ conn.connect()
+ conn.request('GET', '/', '{"method": "getbestblockhash"}', headers)
+ out1 = conn.getresponse().read();
+ assert_equal('"error":null' in out1, True)
+ assert_equal(conn.sock!=None, False) #connection must be closed because bitcoind should use keep-alive by default
if __name__ == '__main__':
- RESTTest ().main ()
+ HTTPBasicsTest ().main ()
diff --git a/qa/rpc-tests/test_framework.py b/qa/rpc-tests/test_framework.py
index 6c4ec073c2..4c8a11b821 100755
--- a/qa/rpc-tests/test_framework.py
+++ b/qa/rpc-tests/test_framework.py
@@ -33,8 +33,11 @@ class BitcoinTestFramework(object):
print("Initializing test directory "+self.options.tmpdir)
initialize_chain(self.options.tmpdir)
+ def setup_nodes(self):
+ return start_nodes(4, self.options.tmpdir)
+
def setup_network(self, split = False):
- self.nodes = start_nodes(4, self.options.tmpdir)
+ self.nodes = self.setup_nodes()
# Connect the nodes as a "chain". This allows us
# to split the network between nodes 1 and 2 to get
diff --git a/src/init.cpp b/src/init.cpp
index 49f80b8b0b..436139ea2c 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -381,6 +381,7 @@ std::string HelpMessage(HelpMessageMode mode)
strUsage += " -rpcport=<port> " + strprintf(_("Listen for JSON-RPC connections on <port> (default: %u or testnet: %u)"), 8332, 18332) + "\n";
strUsage += " -rpcallowip=<ip> " + _("Allow JSON-RPC connections from specified source. Valid for <ip> are a single IP (e.g. 1.2.3.4), a network/netmask (e.g. 1.2.3.4/255.255.255.0) or a network/CIDR (e.g. 1.2.3.4/24). This option can be specified multiple times") + "\n";
strUsage += " -rpcthreads=<n> " + strprintf(_("Set the number of threads to service RPC calls (default: %d)"), 4) + "\n";
+ strUsage += " -rpckeepalive " + strprintf(_("RPC support for HTTP persistent connections (default: %d)"), 0) + "\n";
strUsage += "\n" + _("RPC SSL options: (see the Bitcoin Wiki for SSL setup instructions)") + "\n";
strUsage += " -rpcssl " + _("Use OpenSSL (https) for JSON-RPC connections") + "\n";
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index 4b82646585..aa0ed8ba96 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -954,7 +954,7 @@ void ServiceConnection(AcceptedConnection *conn)
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto, MAX_SIZE);
// HTTP Keep-Alive is false; close connection immediately
- if (mapHeaders["connection"] == "close")
+ if ((mapHeaders["connection"] == "close") || (!GetBoolArg("-rpckeepalive", false)))
fRun = false;
// Process via JSON-RPC API