From ee21912510275c7a0ebeafd2ff553c1db4a4f460 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 28 Apr 2014 13:48:26 +0200 Subject: rpc: Use netmasks instead of wildcards for IP address matching `-rpcallowip` currently has a wacky wildcard-based format. After this commit it will accept the more standard format, for example: - Ranges with netmask 127.0.0.0/255.255.255.0, ::/0 - Ranges with cidr 12.3.4.5/24, 12:34:56:78:9a:bc:de:00/112 - Loose IPs ::1, 127.0.0.1 Trying to use the old *?-based format will result in an error message at launch. --- src/rpcserver.cpp | 63 ++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 14 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index f78cb420f..5740cca13 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -38,6 +38,7 @@ static map > deadlineTimers; static ssl::context* rpc_ssl_context = NULL; static boost::thread_group* rpc_worker_group = NULL; static boost::asio::io_service::work *rpc_dummy_work = NULL; +static std::vector rpc_allow_subnets; //!< List of subnets to allow RPC connections from void RPCTypeCheck(const Array& params, const list& typesExpected, @@ -358,25 +359,34 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) stream << HTTPReply(nStatus, strReply, false) << std::flush; } -bool ClientAllowed(const boost::asio::ip::address& address) +// Convert boost::asio address to CNetAddr +static CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address) { + CNetAddr netaddr; // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses if (address.is_v6() && (address.to_v6().is_v4_compatible() || address.to_v6().is_v4_mapped())) - return ClientAllowed(address.to_v6().to_v4()); - - if (address == asio::ip::address_v4::loopback() - || address == asio::ip::address_v6::loopback() - || (address.is_v4() - // Check whether IPv4 addresses match 127.0.0.0/8 (loopback subnet) - && (address.to_v4().to_ulong() & 0xff000000) == 0x7f000000)) - return true; - - const string strAddress = address.to_string(); - const vector& vAllow = mapMultiArgs["-rpcallowip"]; - BOOST_FOREACH(string strAllow, vAllow) - if (WildcardMatch(strAddress, strAllow)) + address = address.to_v6().to_v4(); + + if(address.is_v4()) + { + boost::asio::ip::address_v4::bytes_type bytes = address.to_v4().to_bytes(); + netaddr.SetRaw(NET_IPV4, &bytes[0]); + } + else + { + boost::asio::ip::address_v6::bytes_type bytes = address.to_v6().to_bytes(); + netaddr.SetRaw(NET_IPV6, &bytes[0]); + } + return netaddr; +} + +bool ClientAllowed(const boost::asio::ip::address& address) +{ + CNetAddr netaddr = BoostAsioToCNetAddr(address); + BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets) + if (subnet.Match(netaddr)) return true; return false; } @@ -502,6 +512,31 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor& vAllow = mapMultiArgs["-rpcallowip"]; + BOOST_FOREACH(string strAllow, vAllow) + { + CSubNet subnet(strAllow); + if(!subnet.IsValid()) + { + uiInterface.ThreadSafeMessageBox( + strprintf("Invalid -rpcallowip subnet specification: %s", strAllow), + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return; + } + rpc_allow_subnets.push_back(subnet); + } + } + std::string strAllowed; + BOOST_FOREACH(const CSubNet &subnet, rpc_allow_subnets) + strAllowed += subnet.ToString() + " "; + LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed); + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; if (((mapArgs["-rpcpassword"] == "") || (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword()) -- cgit v1.2.3 From 21bf3d257b88c45e2bb0b47e36e73d7462760c2c Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 28 Apr 2014 15:23:29 +0200 Subject: Add tests for BoostAsioToCNetAddr --- src/rpcserver.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 5740cca13..ac40ea7cf 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -359,8 +359,7 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) stream << HTTPReply(nStatus, strReply, false) << std::flush; } -// Convert boost::asio address to CNetAddr -static CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address) +CNetAddr BoostAsioToCNetAddr(boost::asio::ip::address address) { CNetAddr netaddr; // Make sure that IPv4-compatible and IPv4-mapped IPv6 addresses are treated as IPv4 addresses -- cgit v1.2.3 From 0a0cd345520382bd726fef50c62864715b03f164 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Wed, 7 May 2014 09:09:13 +0200 Subject: rpc: pass errors from async_accept According to the [boost::asio documentation](http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/basic_socket_acceptor/async_accept/overload2.html), the function signature of the handler must be: void handler( const boost::system::error_code& error // Result of operation. ); We were binding *all* the arguments, instead of all but the error, resulting in nullary function that never got the error. Fix this by adding an input argument substitution. --- src/rpcserver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index ac40ea7cf..44f329dd1 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -466,7 +466,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor Date: Wed, 7 May 2014 09:24:44 +0200 Subject: rpc: Make sure conn object is always cleaned up Make sure conn object always gets cleaned up by using a `boost::shared_ptr`. This makes valgrind happy - before this commit, one connection object always leaked at shutdown, as well as can avoid other leaks, when for example an exception happens. Also add an explicit Close() to the !ClientAllowed path to make it similar to the normal path (I'm not sure whether it is needed, but it can't hurt). --- src/rpcserver.cpp | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 44f329dd1..442bf5c9c 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -444,7 +444,7 @@ template static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor > acceptor, ssl::context& context, bool fUseSSL, - AcceptedConnection* conn, + boost::shared_ptr< AcceptedConnection > conn, const boost::system::error_code& error); /** @@ -456,7 +456,7 @@ static void RPCListen(boost::shared_ptr< basic_socket_acceptor* conn = new AcceptedConnectionImpl(acceptor->get_io_service(), context, fUseSSL); + boost::shared_ptr< AcceptedConnectionImpl > conn(new AcceptedConnectionImpl(acceptor->get_io_service(), context, fUseSSL)); acceptor->async_accept( conn->sslStream.lowest_layer(), @@ -477,23 +477,20 @@ template static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptor > acceptor, ssl::context& context, const bool fUseSSL, - AcceptedConnection* conn, + boost::shared_ptr< AcceptedConnection > conn, const boost::system::error_code& error) { // Immediately start accepting new connections, except when we're cancelled or our socket is closed. if (error != asio::error::operation_aborted && acceptor->is_open()) RPCListen(acceptor, context, fUseSSL); - AcceptedConnectionImpl* tcp_conn = dynamic_cast< AcceptedConnectionImpl* >(conn); + AcceptedConnectionImpl* tcp_conn = dynamic_cast< AcceptedConnectionImpl* >(conn.get()); - // TODO: Actually handle errors if (error) { - delete conn; // TODO: Actually handle errors LogPrintf("%s: Error: %s\n", __func__, error.message()); } - // Restrict callers by IP. It is important to // do this before starting client thread, to filter out // certain DoS and misbehaving clients. @@ -502,12 +499,11 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptorstream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush; - delete conn; + conn->close(); } else { - ServiceConnection(conn); + ServiceConnection(conn.get()); conn->close(); - delete conn; } } -- cgit v1.2.3 From cef44941e798c33f7334bf90a2dd531f9bada8c3 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Fri, 9 May 2014 10:01:50 +0200 Subject: rpc: keep track of acceptors, and cancel them in StopRPCThreads Fixes #4156. The problem is that the boost::asio::io_service destructor waits for the acceptors to finish (on windows, and boost 1.55). Fix this by keeping track of the acceptors and cancelling them before stopping the event loops. --- src/rpcserver.cpp | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 442bf5c9c..d4a229b09 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -39,6 +39,7 @@ static ssl::context* rpc_ssl_context = NULL; static boost::thread_group* rpc_worker_group = NULL; static boost::asio::io_service::work *rpc_dummy_work = NULL; static std::vector rpc_allow_subnets; //!< List of subnets to allow RPC connections from +static std::vector< boost::shared_ptr > rpc_acceptors; void RPCTypeCheck(const Array& params, const list& typesExpected, @@ -593,12 +594,13 @@ void StartRPCThreads() asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any(); ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", Params().RPCPort())); boost::system::error_code v6_only_error; - boost::shared_ptr acceptor(new ip::tcp::acceptor(*rpc_io_service)); bool fListening = false; std::string strerr; try { + boost::shared_ptr acceptor(new ip::tcp::acceptor(*rpc_io_service)); + rpc_acceptors.push_back(acceptor); acceptor->open(endpoint.protocol()); acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); @@ -616,7 +618,6 @@ void StartRPCThreads() { strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what()); } - try { // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately if (!fListening || loopback || v6_only_error) @@ -624,7 +625,8 @@ void StartRPCThreads() bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any(); endpoint.address(bindAddress); - acceptor.reset(new ip::tcp::acceptor(*rpc_io_service)); + boost::shared_ptr acceptor(new ip::tcp::acceptor(*rpc_io_service)); + rpc_acceptors.push_back(acceptor); acceptor->open(endpoint.protocol()); acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); acceptor->bind(endpoint); @@ -668,7 +670,16 @@ void StopRPCThreads() { if (rpc_io_service == NULL) return; + // First, cancel all timers and acceptors + // This is not done automatically by ->stop(), and in some cases the destructor of + // asio::io_service can hang if this is skipped. + BOOST_FOREACH(const boost::shared_ptr &acceptor, rpc_acceptors) + acceptor->cancel(); + rpc_acceptors.clear(); + BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr) &timer, deadlineTimers) + timer.second->cancel(); deadlineTimers.clear(); + rpc_io_service->stop(); if (rpc_worker_group != NULL) rpc_worker_group->join_all(); -- cgit v1.2.3 From deb3572ab160221124dfa3e9c5c4e493529f59e4 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Mon, 17 Feb 2014 17:35:40 +0100 Subject: Add -rpcbind option to allow binding RPC port on a specific interface Add -rpcbind command option to specify binding RPC service on one or multiple specific interfaces. Functionality if -rpcbind is not specified remains the same as before: - If no -rpcallowip specified, bind on localhost - If no -rpcbind specified, bind on any interface Implements part of #3111. --- src/rpcserver.cpp | 95 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 60 insertions(+), 35 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index d4a229b09..2534a9dcf 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -508,6 +508,14 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptorimpl(), strCiphers.c_str()); } - // Try a dual IPv6/IPv4 socket, falling back to separate IPv4 and IPv6 sockets - const bool loopback = !mapArgs.count("-rpcallowip"); - asio::ip::address bindAddress = loopback ? asio::ip::address_v6::loopback() : asio::ip::address_v6::any(); - ip::tcp::endpoint endpoint(bindAddress, GetArg("-rpcport", Params().RPCPort())); - boost::system::error_code v6_only_error; + std::vector vEndpoints; + bool bBindAny = false; + int defaultPort = GetArg("-rpcport", Params().RPCPort()); + if (!mapArgs.count("-rpcallowip")) // Default to loopback if not allowing external IPs + { + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::loopback(), defaultPort)); + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v4::loopback(), defaultPort)); + if (mapArgs.count("-rpcbind")) + { + LogPrintf("WARNING: option -rpcbind was ignored because -rpcallowip was not specified, refusing to allow everyone to connect\n"); + } + } else if (mapArgs.count("-rpcbind")) // Specific bind address + { + BOOST_FOREACH(const std::string &addr, mapMultiArgs["-rpcbind"]) + { + try { + vEndpoints.push_back(ParseEndpoint(addr, defaultPort)); + } + catch(boost::system::system_error &e) + { + uiInterface.ThreadSafeMessageBox( + strprintf(_("Could not parse -rpcbind value %s as network address"), addr), + "", CClientUIInterface::MSG_ERROR); + StartShutdown(); + return; + } + } + } else { // No specific bind address specified, bind to any + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::any(), defaultPort)); + vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v4::any(), defaultPort)); + // Prefer making the socket dual IPv6/IPv4 instead of binding + // to both addresses seperately. + bBindAny = true; + } bool fListening = false; std::string strerr; - try + BOOST_FOREACH(const ip::tcp::endpoint &endpoint, vEndpoints) { + asio::ip::address bindAddress = endpoint.address(); + LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", bindAddress.to_string(), endpoint.port(), bBindAny); + boost::system::error_code v6_only_error; boost::shared_ptr acceptor(new ip::tcp::acceptor(*rpc_io_service)); rpc_acceptors.push_back(acceptor); - acceptor->open(endpoint.protocol()); - acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); - - // Try making the socket dual IPv6/IPv4 (if listening on the "any" address) - acceptor->set_option(boost::asio::ip::v6_only(loopback), v6_only_error); - - acceptor->bind(endpoint); - acceptor->listen(socket_base::max_connections); - - RPCListen(acceptor, *rpc_ssl_context, fUseSSL); - - fListening = true; - } - catch(boost::system::system_error &e) - { - strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv6, falling back to IPv4: %s"), endpoint.port(), e.what()); - } - try { - // If dual IPv6/IPv4 failed (or we're opening loopback interfaces only), open IPv4 separately - if (!fListening || loopback || v6_only_error) - { - bindAddress = loopback ? asio::ip::address_v4::loopback() : asio::ip::address_v4::any(); - endpoint.address(bindAddress); - boost::shared_ptr acceptor(new ip::tcp::acceptor(*rpc_io_service)); - rpc_acceptors.push_back(acceptor); + try { acceptor->open(endpoint.protocol()); acceptor->set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + + // Try making the socket dual IPv6/IPv4 when listening on the IPv6 "any" address + acceptor->set_option(boost::asio::ip::v6_only( + !bBindAny || bindAddress != asio::ip::address_v6::any()), v6_only_error); + acceptor->bind(endpoint); acceptor->listen(socket_base::max_connections); RPCListen(acceptor, *rpc_ssl_context, fUseSSL); fListening = true; + // If dual IPv6/IPv4 bind succesful, skip binding to IPv4 separately + if(bBindAny && bindAddress == asio::ip::address_v6::any() && !v6_only_error) + break; + } + catch(boost::system::system_error &e) + { + LogPrintf("ERROR: Binding RPC on address %s port %i failed: %s\n", bindAddress.to_string(), endpoint.port(), e.what()); + strerr = strprintf(_("An error occurred while setting up the RPC address %s port %u for listening: %s"), bindAddress.to_string(), endpoint.port(), e.what()); } - } - catch(boost::system::system_error &e) - { - strerr = strprintf(_("An error occurred while setting up the RPC port %u for listening on IPv4: %s"), endpoint.port(), e.what()); } if (!fListening) { -- cgit v1.2.3 From 171ca7745e77c9f78f26556457fe64e5b2004a75 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Mon, 17 Mar 2014 08:19:54 -0400 Subject: estimatefee / estimatepriority RPC methods New RPC methods: return an estimate of the fee (or priority) a transaction needs to be likely to confirm in a given number of blocks. Mike Hearn created the first version of this method for estimating fees. It works as follows: For transactions that took 1 to N (I picked N=25) blocks to confirm, keep N buckets with at most 100 entries in each recording the fees-per-kilobyte paid by those transactions. (separate buckets are kept for transactions that confirmed because they are high-priority) The buckets are filled as blocks are found, and are saved/restored in a new fee_estiamtes.dat file in the data directory. A few variations on Mike's initial scheme: To estimate the fee needed for a transaction to confirm in X buckets, all of the samples in all of the buckets are used and a median of all of the data is used to make the estimate. For example, imagine 25 buckets each containing the full 100 entries. Those 2,500 samples are sorted, and the estimate of the fee needed to confirm in the very next block is the 50'th-highest-fee-entry in that sorted list; the estimate of the fee needed to confirm in the next two blocks is the 150'th-highest-fee-entry, etc. That algorithm has the nice property that estimates of how much fee you need to pay to get confirmed in block N will always be greater than or equal to the estimate for block N+1. It would clearly be wrong to say "pay 11 uBTC and you'll get confirmed in 3 blocks, but pay 12 uBTC and it will take LONGER". A single block will not contribute more than 10 entries to any one bucket, so a single miner and a large block cannot overwhelm the estimates. --- src/rpcserver.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2534a9dcf..72a7fe83e 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -268,6 +268,8 @@ static const CRPCCommand vRPCCommands[] = { "createmultisig", &createmultisig, true, true , false }, { "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */ { "verifymessage", &verifymessage, false, false, false }, + { "estimatefee", &estimatefee, true, true, false }, + { "estimatepriority", &estimatepriority, true, true, false }, #ifdef ENABLE_WALLET /* Wallet */ -- cgit v1.2.3 From 18e72167ddfeaea95253b62994c6d64b55b35005 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Wed, 7 May 2014 17:10:35 +0200 Subject: Push cs_mains down in ProcessBlock --- src/rpcserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 72a7fe83e..d4ceb7f99 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -254,7 +254,7 @@ static const CRPCCommand vRPCCommands[] = { "getblocktemplate", &getblocktemplate, true, false, false }, { "getmininginfo", &getmininginfo, true, false, false }, { "getnetworkhashps", &getnetworkhashps, true, false, false }, - { "submitblock", &submitblock, false, false, false }, + { "submitblock", &submitblock, false, true, false }, /* Raw transactions */ { "createrawtransaction", &createrawtransaction, false, false, false }, -- cgit v1.2.3 From 33e5b4291036bbdad075f4a549491af72d8a0618 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Tue, 17 Jun 2014 09:09:12 +0200 Subject: rpc: Ignore and log errors during cancel Cancelling the RPC acceptors can sometimes result in an error about a bad file descriptor. As this is the shutdown sequence we need to continue nevertheless, ignore these errors, log a warning and proceed. Fixes #4352. --- src/rpcserver.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index d4ceb7f99..2f7f5cc2a 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -700,11 +700,20 @@ void StopRPCThreads() // First, cancel all timers and acceptors // This is not done automatically by ->stop(), and in some cases the destructor of // asio::io_service can hang if this is skipped. + boost::system::error_code ec; BOOST_FOREACH(const boost::shared_ptr &acceptor, rpc_acceptors) - acceptor->cancel(); + { + acceptor->cancel(ec); + if (ec) + LogPrintf("%s: Warning: %s when cancelling acceptor", __func__, ec.message()); + } rpc_acceptors.clear(); BOOST_FOREACH(const PAIRTYPE(std::string, boost::shared_ptr) &timer, deadlineTimers) - timer.second->cancel(); + { + timer.second->cancel(ec); + if (ec) + LogPrintf("%s: Warning: %s when cancelling timer", __func__, ec.message()); + } deadlineTimers.clear(); rpc_io_service->stop(); -- cgit v1.2.3 From 6afa49329de860c080cdfd9b1c65afe313a43860 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 19 Jun 2014 08:19:07 +0200 Subject: rpc: Add acceptors only when listening succeeded --- src/rpcserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 2f7f5cc2a..56b5f2de0 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -642,7 +642,6 @@ void StartRPCThreads() LogPrintf("Binding RPC on address %s port %i (IPv4+IPv6 bind any: %i)\n", bindAddress.to_string(), endpoint.port(), bBindAny); boost::system::error_code v6_only_error; boost::shared_ptr acceptor(new ip::tcp::acceptor(*rpc_io_service)); - rpc_acceptors.push_back(acceptor); try { acceptor->open(endpoint.protocol()); @@ -658,6 +657,7 @@ void StartRPCThreads() RPCListen(acceptor, *rpc_ssl_context, fUseSSL); fListening = true; + rpc_acceptors.push_back(acceptor); // If dual IPv6/IPv4 bind succesful, skip binding to IPv4 separately if(bBindAny && bindAddress == asio::ip::address_v6::any() && !v6_only_error) break; -- cgit v1.2.3 From cf0c47b2698a3e23654d9fd24f6b2ef9689bde3d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Mon, 28 Apr 2014 12:52:32 +0200 Subject: Remove getwork() RPC call --- src/rpcserver.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 56b5f2de0..93da81e42 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -315,7 +315,6 @@ static const CRPCCommand vRPCCommands[] = /* Wallet-enabled mining */ { "getgenerate", &getgenerate, true, false, false }, { "gethashespersec", &gethashespersec, true, false, false }, - { "getwork", &getwork, true, false, true }, { "setgenerate", &setgenerate, true, true, false }, #endif // ENABLE_WALLET }; @@ -772,7 +771,7 @@ void JSONRequest::parse(const Value& valRequest) if (valMethod.type() != str_type) throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string"); strMethod = valMethod.get_str(); - if (strMethod != "getwork" && strMethod != "getblocktemplate") + if (strMethod != "getblocktemplate") LogPrint("rpc", "ThreadRPCServer method=%s\n", strMethod); // Parse params -- cgit v1.2.3 From 84ce18ca9339901f65d77a5821eb65f771316558 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 19 Jun 2014 15:10:04 +0200 Subject: Remove unnecessary dependencies for bitcoin-cli This commit removes all the unnecessary dependencies (key, core, netbase, sync, ...) from bitcoin-cli. To do this it shards the chain parameters into BaseParams, which contains just the RPC port and data directory (as used by utils and bitcoin-cli) and Params, with the rest. --- src/rpcserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 93da81e42..c5d09cf57 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -600,7 +600,7 @@ void StartRPCThreads() std::vector vEndpoints; bool bBindAny = false; - int defaultPort = GetArg("-rpcport", Params().RPCPort()); + int defaultPort = GetArg("-rpcport", BaseParams().RPCPort()); if (!mapArgs.count("-rpcallowip")) // Default to loopback if not allowing external IPs { vEndpoints.push_back(ip::tcp::endpoint(asio::ip::address_v6::loopback(), defaultPort)); -- cgit v1.2.3 From 2a72d4591f5adf25fcb4d0433b390ba6c37f57a9 Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Wed, 11 Jul 2012 18:52:41 +0000 Subject: JSON-RPC method: prioritisetransaction Accepts the transaction into mined blocks at a higher (or lower) priority --- src/rpcserver.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index c5d09cf57..6552de8c4 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -254,6 +254,7 @@ static const CRPCCommand vRPCCommands[] = { "getblocktemplate", &getblocktemplate, true, false, false }, { "getmininginfo", &getmininginfo, true, false, false }, { "getnetworkhashps", &getnetworkhashps, true, false, false }, + { "prioritisetransaction", &prioritisetransaction, true, false, false }, { "submitblock", &submitblock, false, true, false }, /* Raw transactions */ -- cgit v1.2.3 From c912e22db08d0a44ad6fd027c09bbdf79c34dbbc Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Jun 2014 11:24:43 -0400 Subject: RPC cleanup: Improve HTTP server replies 1) support varying content types 2) support only sending the header 3) properly deliver error message as content, if HTTP error 4) move AcceptedConnection class to header, for wider use --- src/rpcserver.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 6552de8c4..b85b17c81 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -393,16 +393,6 @@ bool ClientAllowed(const boost::asio::ip::address& address) return false; } -class AcceptedConnection -{ -public: - virtual ~AcceptedConnection() {} - - virtual std::iostream& stream() = 0; - virtual std::string peer_address_to_string() const = 0; - virtual void close() = 0; -}; - template class AcceptedConnectionImpl : public AcceptedConnection { -- cgit v1.2.3 From 854d013012c2d457d5296227d212b053cbea5239 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Wed, 4 Jun 2014 11:38:33 -0400 Subject: RPC code movement: separate out JSON-RPC execution logic from HTTP server logic --- src/rpcserver.cpp | 129 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 72 insertions(+), 57 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index b85b17c81..49bc05e5d 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -809,6 +809,71 @@ static string JSONRPCExecBatch(const Array& vReq) return write_string(Value(ret), false) + "\n"; } +static bool HTTPReq_JSONRPC(AcceptedConnection *conn, + string& strRequest, + map& mapHeaders, + bool fRun) +{ + // Check authorization + if (mapHeaders.count("authorization") == 0) + { + conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + return false; + } + + if (!HTTPAuthorized(mapHeaders)) + { + LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string()); + /* Deter brute-forcing short passwords. + If this results in a DoS the user really + shouldn't have their RPC port exposed. */ + if (mapArgs["-rpcpassword"].size() < 20) + MilliSleep(250); + + conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + return false; + } + + JSONRequest jreq; + try + { + // Parse request + Value valRequest; + if (!read_string(strRequest, valRequest)) + throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); + + string strReply; + + // singleton request + if (valRequest.type() == obj_type) { + jreq.parse(valRequest); + + Value result = tableRPC.execute(jreq.strMethod, jreq.params); + + // Send reply + strReply = JSONRPCReply(result, Value::null, jreq.id); + + // array of requests + } else if (valRequest.type() == array_type) + strReply = JSONRPCExecBatch(valRequest.get_array()); + else + throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); + + conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush; + } + catch (Object& objError) + { + ErrorReply(conn->stream(), objError, jreq.id); + return false; + } + catch (std::exception& e) + { + ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); + return false; + } + return true; +} + void ServiceConnection(AcceptedConnection *conn) { bool fRun = true; @@ -825,67 +890,17 @@ void ServiceConnection(AcceptedConnection *conn) // Read HTTP message headers and body ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto); - if (strURI != "/") { - conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; - break; - } - - // Check authorization - if (mapHeaders.count("authorization") == 0) - { - conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; - break; - } - if (!HTTPAuthorized(mapHeaders)) - { - LogPrintf("ThreadRPCServer incorrect password attempt from %s\n", conn->peer_address_to_string()); - /* Deter brute-forcing short passwords. - If this results in a DoS the user really - shouldn't have their RPC port exposed. */ - if (mapArgs["-rpcpassword"].size() < 20) - MilliSleep(250); - - conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; - break; - } + // HTTP Keep-Alive is false; close connection immediately if (mapHeaders["connection"] == "close") fRun = false; - JSONRequest jreq; - try - { - // Parse request - Value valRequest; - if (!read_string(strRequest, valRequest)) - throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); - - string strReply; - - // singleton request - if (valRequest.type() == obj_type) { - jreq.parse(valRequest); - - Value result = tableRPC.execute(jreq.strMethod, jreq.params); - - // Send reply - strReply = JSONRPCReply(result, Value::null, jreq.id); - - // array of requests - } else if (valRequest.type() == array_type) - strReply = JSONRPCExecBatch(valRequest.get_array()); - else - throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); - - conn->stream() << HTTPReply(HTTP_OK, strReply, fRun) << std::flush; - } - catch (Object& objError) - { - ErrorReply(conn->stream(), objError, jreq.id); - break; + if (strURI == "/") { + if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun)) + break; } - catch (std::exception& e) - { - ErrorReply(conn->stream(), JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); + + else { + conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; break; } } -- cgit v1.2.3 From 40a158e100c517c73d9a75434e48cfe904ea00cc Mon Sep 17 00:00:00 2001 From: Philip Kaufmann Date: Fri, 27 Jun 2014 11:13:25 +0200 Subject: minor code format fix in rpc-related files --- src/rpcserver.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 49bc05e5d..54043458d 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -25,10 +25,10 @@ #include #include "json/json_spirit_writer_template.h" -using namespace std; using namespace boost; using namespace boost::asio; using namespace json_spirit; +using namespace std; static std::string strRPCUserColonPass; @@ -897,9 +897,7 @@ void ServiceConnection(AcceptedConnection *conn) if (strURI == "/") { if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun)) break; - } - - else { + } else { conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; break; } -- cgit v1.2.3 From 645d497aa0010525441ce409e8e6d327a157ab39 Mon Sep 17 00:00:00 2001 From: jtimon Date: Fri, 27 Jun 2014 13:28:08 +0200 Subject: Replace HexBits with strprintf --- src/rpcserver.cpp | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 54043458d..6a87c8bf9 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -97,16 +97,6 @@ Value ValueFromAmount(int64_t amount) return (double)amount / (double)COIN; } -std::string HexBits(unsigned int nBits) -{ - union { - int32_t nBits; - char cBits[4]; - } uBits; - uBits.nBits = htonl((int32_t)nBits); - return HexStr(BEGIN(uBits.cBits), END(uBits.cBits)); -} - uint256 ParseHashV(const Value& v, string strName) { string strHex; -- cgit v1.2.3 From 16f33f163d4e2c10320a96a22bbab71c9a0df195 Mon Sep 17 00:00:00 2001 From: kazcw Date: Sat, 28 Jun 2014 18:14:36 -0700 Subject: fix RPC error replies After pull #4288, RPC messages indicating errors have a Content-Length unrelated to their actual contents, rendering bitcoin-cli and curl unable to decode the reply. This patch sets the Content-Length field based on the actual content returned. Additionally, pull #4288 clobbered the error descriptions provided in ErrorReply, which bitcoin-cli relies upon; this patch moves #4288 http-error descriptions to an HTTPError method, allowing HTTPReply to pass content on unchanged. --- src/rpcserver.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index 6a87c8bf9..f47b3385d 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -481,7 +481,7 @@ static void RPCAcceptHandler(boost::shared_ptr< basic_socket_acceptorstream() << HTTPReply(HTTP_FORBIDDEN, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_FORBIDDEN, false) << std::flush; conn->close(); } else { @@ -807,7 +807,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, // Check authorization if (mapHeaders.count("authorization") == 0) { - conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush; return false; } @@ -820,7 +820,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, if (mapArgs["-rpcpassword"].size() < 20) MilliSleep(250); - conn->stream() << HTTPReply(HTTP_UNAUTHORIZED, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_UNAUTHORIZED, false) << std::flush; return false; } @@ -888,7 +888,7 @@ void ServiceConnection(AcceptedConnection *conn) if (!HTTPReq_JSONRPC(conn, strRequest, mapHeaders, fRun)) break; } else { - conn->stream() << HTTPReply(HTTP_NOT_FOUND, "", false) << std::flush; + conn->stream() << HTTPError(HTTP_NOT_FOUND, false) << std::flush; break; } } -- cgit v1.2.3 From c8988460a2865b99ee96da6799d37ac6ccb79d4d Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Fri, 26 Jul 2013 01:06:01 +0200 Subject: Add support for watch-only addresses Changes: * Add Add/Have WatchOnly methods to CKeyStore, and implementations in CBasicKeyStore. * Add similar methods to CWallet, and support entries for it in CWalletDB. * Make IsMine in script/wallet return a new enum 'isminetype', rather than a boolean. This allows distinguishing between spendable and unspendable coins. * Add a field fSpendable to COutput (GetAvailableCoins' return type). * Mark watchonly coins in listunspent as 'watchonly': true. * Add 'watchonly' to validateaddress, suppressing script/pubkey/... in this case. Based on a patch by Eric Lombrozo. Conflicts: src/qt/walletmodel.cpp src/rpcserver.cpp src/wallet.cpp --- src/rpcserver.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index f47b3385d..363403c69 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -282,6 +282,7 @@ static const CRPCCommand vRPCCommands[] = { "getwalletinfo", &getwalletinfo, true, false, true }, { "importprivkey", &importprivkey, false, false, true }, { "importwallet", &importwallet, false, false, true }, + { "importaddress", &importaddress, false, false, true }, { "keypoolrefill", &keypoolrefill, true, false, true }, { "listaccounts", &listaccounts, false, false, true }, { "listaddressgroupings", &listaddressgroupings, false, false, true }, -- cgit v1.2.3 From 4278b1df45d93d18dfa0a8ce8d6fd7ac9b5344a6 Mon Sep 17 00:00:00 2001 From: "Wladimir J. van der Laan" Date: Thu, 3 Jul 2014 06:26:03 +0200 Subject: Clarify error message when invalid -rpcallowip Also add to HelpMessage() what specifications are valid. --- src/rpcserver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/rpcserver.cpp') diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp index f47b3385d..5c4d30749 100644 --- a/src/rpcserver.cpp +++ b/src/rpcserver.cpp @@ -512,7 +512,7 @@ void StartRPCThreads() if(!subnet.IsValid()) { uiInterface.ThreadSafeMessageBox( - strprintf("Invalid -rpcallowip subnet specification: %s", strAllow), + strprintf("Invalid -rpcallowip subnet specification: %s. Valid 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).", strAllow), "", CClientUIInterface::MSG_ERROR); StartShutdown(); return; -- cgit v1.2.3