diff --git a/src/Makefile.am b/src/Makefile.am index 93b834d472..7e1af1c69d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -75,6 +75,7 @@ BITCOIN_CORE_H = \ base58.h \ bloom.h \ blockencodings.h \ + callrpc.h \ chain.h \ chainparams.h \ chainparamsbase.h \ @@ -310,6 +311,7 @@ libbitcoin_util_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_util_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_util_a_SOURCES = \ support/pagelocker.cpp \ + callrpc.cpp \ chainparamsbase.cpp \ clientversion.cpp \ compat/glibc_sanity.cpp \ @@ -319,6 +321,7 @@ libbitcoin_util_a_SOURCES = \ rpc/protocol.cpp \ support/cleanse.cpp \ sync.cpp \ + uint256.cpp \ util.cpp \ utilmoneystr.cpp \ utilstrencodings.cpp \ diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index a0f9cd4876..052f2b9efc 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -3,6 +3,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "callrpc.h" #if defined(HAVE_CONFIG_H) #include "config/bitcoin-config.h" #endif @@ -16,19 +17,10 @@ #include #include - -#include -#include -#include -#include - #include using namespace std; -static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; -static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; - std::string HelpMessageCli() { const boost::scoped_ptr defaultBaseParams(CBaseChainParams::Factory(CBaseChainParams::MAIN)); @@ -54,20 +46,6 @@ std::string HelpMessageCli() // Start // -// -// Exception thrown on connection error. This error is used to determine -// when to wait if -rpcwait is given. -// -class CConnectionFailed : public std::runtime_error -{ -public: - - explicit inline CConnectionFailed(const std::string& msg) : - std::runtime_error(msg) - {} - -}; - static bool AppInitRPC(int argc, char* argv[]) { // @@ -113,117 +91,6 @@ static bool AppInitRPC(int argc, char* argv[]) return true; } - -/** Reply structure for request_done to fill in */ -struct HTTPReply -{ - int status; - std::string body; -}; - -static void http_request_done(struct evhttp_request *req, void *ctx) -{ - HTTPReply *reply = static_cast(ctx); - - if (req == NULL) { - /* If req is NULL, it means an error occurred while connecting, but - * I'm not sure how to find out which one. We also don't really care. - */ - reply->status = 0; - return; - } - - reply->status = evhttp_request_get_response_code(req); - - struct evbuffer *buf = evhttp_request_get_input_buffer(req); - if (buf) - { - size_t size = evbuffer_get_length(buf); - const char *data = (const char*)evbuffer_pullup(buf, size); - if (data) - reply->body = std::string(data, size); - evbuffer_drain(buf, size); - } -} - -UniValue CallRPC(const string& strMethod, const UniValue& params) -{ - std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); - int port = GetArg("-rpcport", BaseParams().RPCPort()); - - // Create event base - struct event_base *base = event_base_new(); // TODO RAII - if (!base) - throw runtime_error("cannot create event_base"); - - // Synchronously look up hostname - struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII - if (evcon == NULL) - throw runtime_error("create connection failed"); - evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); - - HTTPReply response; - struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII - if (req == NULL) - throw runtime_error("create http request failed"); - - // Get credentials - std::string strRPCUserColonPass; - if (mapArgs["-rpcpassword"] == "") { - // Try fall back to cookie-based authentication if no password is provided - if (!GetAuthCookie(&strRPCUserColonPass)) { - throw runtime_error(strprintf( - _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"), - GetConfigFile().string().c_str())); - - } - } else { - strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; - } - - struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req); - assert(output_headers); - evhttp_add_header(output_headers, "Host", host.c_str()); - evhttp_add_header(output_headers, "Connection", "close"); - evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str()); - - // Attach request data - std::string strRequest = JSONRPCRequest(strMethod, params, 1); - struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req); - assert(output_buffer); - evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); - - int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/"); - if (r != 0) { - evhttp_connection_free(evcon); - event_base_free(base); - throw CConnectionFailed("send http request failed"); - } - - event_base_dispatch(base); - evhttp_connection_free(evcon); - event_base_free(base); - - if (response.status == 0) - throw CConnectionFailed("couldn't connect to server"); - else if (response.status == HTTP_UNAUTHORIZED) - throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); - else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) - throw runtime_error(strprintf("server returned HTTP error %d", response.status)); - else if (response.body.empty()) - throw runtime_error("no response from server"); - - // Parse reply - UniValue valReply(UniValue::VSTR); - if (!valReply.read(response.body)) - throw runtime_error("couldn't parse reply from server"); - const UniValue& reply = valReply.get_obj(); - if (reply.empty()) - throw runtime_error("expected reply to have result, error and id properties"); - - return reply; -} - int CommandLineRPC(int argc, char *argv[]) { string strPrint; diff --git a/src/callrpc.cpp b/src/callrpc.cpp new file mode 100644 index 0000000000..ebf7ddfe74 --- /dev/null +++ b/src/callrpc.cpp @@ -0,0 +1,122 @@ +#include "chainparamsbase.h" +#include "callrpc.h" +#include "util.h" +#include "utilstrencodings.h" +#include "rpc/protocol.h" + +#include +#include +#include +#include + +using namespace std; + +/** Reply structure for request_done to fill in */ +struct HTTPReply +{ + int status; + std::string body; +}; + +static void http_request_done(struct evhttp_request *req, void *ctx) +{ + HTTPReply *reply = static_cast(ctx); + + if (req == NULL) { + /* If req is NULL, it means an error occurred while connecting, but + * I'm not sure how to find out which one. We also don't really care. + */ + reply->status = 0; + return; + } + + reply->status = evhttp_request_get_response_code(req); + + struct evbuffer *buf = evhttp_request_get_input_buffer(req); + if (buf) + { + size_t size = evbuffer_get_length(buf); + const char *data = (const char*)evbuffer_pullup(buf, size); + if (data) + reply->body = std::string(data, size); + evbuffer_drain(buf, size); + } +} + +UniValue CallRPC(const string& strMethod, const UniValue& params) +{ + std::string host = GetArg("-rpcconnect", DEFAULT_RPCCONNECT); + int port = GetArg("-rpcport", BaseParams().RPCPort()); + + // Create event base + struct event_base *base = event_base_new(); // TODO RAII + if (!base) + throw runtime_error("cannot create event_base"); + + // Synchronously look up hostname + struct evhttp_connection *evcon = evhttp_connection_base_new(base, NULL, host.c_str(), port); // TODO RAII + if (evcon == NULL) + throw runtime_error("create connection failed"); + evhttp_connection_set_timeout(evcon, GetArg("-rpcclienttimeout", DEFAULT_HTTP_CLIENT_TIMEOUT)); + + HTTPReply response; + struct evhttp_request *req = evhttp_request_new(http_request_done, (void*)&response); // TODO RAII + if (req == NULL) + throw runtime_error("create http request failed"); + + // Get credentials + std::string strRPCUserColonPass; + if (mapArgs["-rpcpassword"] == "") { + // Try fall back to cookie-based authentication if no password is provided + if (!GetAuthCookie(&strRPCUserColonPass)) { + throw runtime_error(strprintf( + _("Could not locate RPC credentials. No authentication cookie could be found, and no rpcpassword is set in the configuration file (%s)"), + GetConfigFile().string().c_str())); + + } + } else { + strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"]; + } + + struct evkeyvalq *output_headers = evhttp_request_get_output_headers(req); + assert(output_headers); + evhttp_add_header(output_headers, "Host", host.c_str()); + evhttp_add_header(output_headers, "Connection", "close"); + evhttp_add_header(output_headers, "Authorization", (std::string("Basic ") + EncodeBase64(strRPCUserColonPass)).c_str()); + + // Attach request data + std::string strRequest = JSONRPCRequest(strMethod, params, 1); + struct evbuffer * output_buffer = evhttp_request_get_output_buffer(req); + assert(output_buffer); + evbuffer_add(output_buffer, strRequest.data(), strRequest.size()); + + int r = evhttp_make_request(evcon, req, EVHTTP_REQ_POST, "/"); + if (r != 0) { + evhttp_connection_free(evcon); + event_base_free(base); + throw CConnectionFailed("send http request failed"); + } + + event_base_dispatch(base); + evhttp_connection_free(evcon); + event_base_free(base); + + if (response.status == 0) + throw CConnectionFailed("couldn't connect to server"); + else if (response.status == HTTP_UNAUTHORIZED) + throw runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); + else if (response.status >= 400 && response.status != HTTP_BAD_REQUEST && response.status != HTTP_NOT_FOUND && response.status != HTTP_INTERNAL_SERVER_ERROR) + throw runtime_error(strprintf("server returned HTTP error %d", response.status)); + else if (response.body.empty()) + throw runtime_error("no response from server"); + + // Parse reply + UniValue valReply(UniValue::VSTR); + if (!valReply.read(response.body)) + throw runtime_error("couldn't parse reply from server"); + const UniValue& reply = valReply.get_obj(); + if (reply.empty()) + throw runtime_error("expected reply to have result, error and id properties"); + + return reply; +} diff --git a/src/callrpc.h b/src/callrpc.h new file mode 100644 index 0000000000..79a91274ef --- /dev/null +++ b/src/callrpc.h @@ -0,0 +1,33 @@ +// Copyright (c) 2009-2010 Satoshi Nakamoto +// Copyright (c) 2009-2014 The Bitcoin developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CALLRPC_H +#define BITCOIN_CALLRPC_H + +#include +#include + +#include + +static const char DEFAULT_RPCCONNECT[] = "127.0.0.1"; +static const int DEFAULT_HTTP_CLIENT_TIMEOUT=900; + +// +// Exception thrown on connection error. This error is used to determine +// when to wait if -rpcwait is given. +// +class CConnectionFailed : public std::runtime_error +{ +public: + + explicit inline CConnectionFailed(const std::string& msg) : + std::runtime_error(msg) + {} + +}; + +UniValue CallRPC(const std::string& strMethod, const UniValue& params); + +#endif // BITCOIN_CALLRPC_H