From 2f0721f80f4272bcb499370508e1192f2f500f03 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Wed, 30 Jan 2013 15:17:01 -0800 Subject: [PATCH 1/7] Work toward http/https client unification. --- src/cpp/ripple/Amount.cpp | 1 - src/cpp/ripple/AutoSocket.h | 12 ++++ src/cpp/ripple/CallRPC.cpp | 83 +++++++++++++++++++++--- src/cpp/ripple/Config.cpp | 18 +++-- src/cpp/ripple/Config.h | 4 ++ src/cpp/ripple/HttpsClient.cpp | 83 +++++++++++++----------- src/cpp/ripple/HttpsClient.h | 10 ++- src/cpp/ripple/OfferCreateTransactor.cpp | 2 +- src/cpp/ripple/RPCSub.cpp | 3 +- src/cpp/ripple/UniqueNodeList.cpp | 4 ++ 10 files changed, 161 insertions(+), 59 deletions(-) diff --git a/src/cpp/ripple/Amount.cpp b/src/cpp/ripple/Amount.cpp index 6ec1c6210..330886433 100644 --- a/src/cpp/ripple/Amount.cpp +++ b/src/cpp/ripple/Amount.cpp @@ -1056,7 +1056,6 @@ STAmount STAmount::setRate(uint64 rate) // <-- saTakerGot: Actual // <-- saTakerIssuerFee: Actual // <-- saOfferIssuerFee: Actual -// <-- bRemove: remove offer it is either fullfilled or unfunded bool STAmount::applyOffer( const uint32 uTakerPaysRate, const uint32 uOfferPaysRate, const STAmount& saOfferRate, diff --git a/src/cpp/ripple/AutoSocket.h b/src/cpp/ripple/AutoSocket.h index 1a3b6db7b..73883f41f 100644 --- a/src/cpp/ripple/AutoSocket.h +++ b/src/cpp/ripple/AutoSocket.h @@ -67,6 +67,18 @@ public: std::swap(mSecure, s.mSecure); } + boost::system::error_code verify(const std::string& strDomain) + { + boost::system::error_code ec; + + mSocket->set_verify_mode(boost::asio::ssl::verify_peer); + + // XXX Verify semantics of RFC 2818 are what we want. + mSocket->set_verify_callback(boost::asio::ssl::rfc2818_verification(strDomain), ec); + + return ec; + } + void async_handshake(handshake_type type, callback cbFunc) { if ((type == ssl_socket::client) || (mSecure)) diff --git a/src/cpp/ripple/CallRPC.cpp b/src/cpp/ripple/CallRPC.cpp index 6db317cca..a49ff29f3 100644 --- a/src/cpp/ripple/CallRPC.cpp +++ b/src/cpp/ripple/CallRPC.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include #include #include @@ -573,6 +575,29 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams) return (this->*(commandsA[i].pfpFunc))(jvParams); } +void callRPCAsync( + boost::asio::io_service& isService, +#if 0 + const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, +#endif + boost::function callbackFuncP) +{ + Json::Value jvResult(Json::objectValue); + Json::Value jvSub(Json::objectValue); + + jvSub["foo"] = "bar"; + + jvResult["result"] = jvSub; + + (callbackFuncP)(jvResult); +} + +// Place the async result somewhere useful. +void callRPCHandler(Json::Value* jvOutput, const Json::Value& jvInput) +{ + (*jvOutput) = jvInput; +} + int commandLineRPC(const std::vector& vCmd) { Json::Value jvOutput; @@ -615,7 +640,11 @@ int commandLineRPC(const std::vector& vCmd) if (!theConfig.RPC_ADMIN_PASSWORD.empty()) jvRequest["admin_password"] = theConfig.RPC_ADMIN_PASSWORD; - jvOutput = callRPC( + boost::asio::io_service isService; + + callRPCAsync( + isService, +#if 0 theConfig.RPC_IP, theConfig.RPC_PORT, theConfig.RPC_USER, @@ -624,7 +653,12 @@ int commandLineRPC(const std::vector& vCmd) jvRequest.isMember("method") // Allow parser to rewrite method. ? jvRequest["method"].asString() : vCmd[0], - jvParams); // Parsed, execute. + jvParams, // Parsed, execute. + boost::bind(callRPCHandler, jvOutput, _1)); +#endif + boost::bind(callRPCHandler, &jvOutput, _1)); + + isService.run(); // This blocks until there is no more outstanding async calls. if (jvOutput.isMember("result")) { @@ -681,7 +715,7 @@ int commandLineRPC(const std::vector& vCmd) return nRet; } -Json::Value callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams) +Json::Value callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL) { // Connect to localhost if (!theConfig.QUIET) @@ -694,10 +728,23 @@ Json::Value callRPC(const std::string& strIp, const int iPort, const std::string boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::address::from_string(strIp), iPort); - boost::asio::ip::tcp::iostream stream; - stream.connect(endpoint); - if (stream.fail()) - throw std::runtime_error("couldn't connect to server"); + boost::asio::ip::tcp::iostream stream; + boost::asio::io_service isService; + boost::asio::ssl::context cContext(boost::asio::ssl::context::sslv23); + boost::asio::ssl::stream stream_ssl(isService, cContext); + + if (bSSL) + { +// stream_ssl.connect(endpoint); +// if (stream_ssl.fail()) +// throw std::runtime_error("couldn't connect to server"); + } + else + { + stream.connect(endpoint); + if (stream.fail()) + throw std::runtime_error("couldn't connect to server"); + } // cLog(lsDEBUG) << "connected" << std::endl; @@ -713,14 +760,32 @@ Json::Value callRPC(const std::string& strIp, const int iPort, const std::string // cLog(lsDEBUG) << "send request " << strMethod << " : " << strRequest << std::endl; std::string strPost = createHTTPPost(strPath, strRequest, mapRequestHeaders); - stream << strPost << std::flush; + if (bSSL) + { +// stream_ssl << strPost << std::flush; + } + else + { + stream << strPost << std::flush; + } // std::cerr << "post " << strPost << std::endl; // Receive reply std::map mapHeaders; std::string strReply; - int nStatus = ReadHTTP(stream, mapHeaders, strReply); + + int nStatus; + + if (bSSL) + { +// nStatus = ReadHTTP(stream_ssl, mapHeaders, strReply); + } + else + { + nStatus = ReadHTTP(stream, mapHeaders, strReply); + } + if (nStatus == 401) throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); else if ((nStatus >= 400) && (nStatus != 400) && (nStatus != 404) && (nStatus != 500)) // ? diff --git a/src/cpp/ripple/Config.cpp b/src/cpp/ripple/Config.cpp index 7313d87cf..7af7c0824 100644 --- a/src/cpp/ripple/Config.cpp +++ b/src/cpp/ripple/Config.cpp @@ -134,26 +134,31 @@ void Config::setup(const std::string& strConf, bool bTestNet, bool bQuiet) if (strXdgConfigHome.empty()) { // $XDG_CONFIG_HOME was not set, use default based on $HOME. - strXdgConfigHome = str(boost::format("%s/.config") % strHome); + strXdgConfigHome = boost::str(boost::format("%s/.config") % strHome); } if (strXdgDataHome.empty()) { // $XDG_DATA_HOME was not set, use default based on $HOME. - strXdgDataHome = str(boost::format("%s/.local/share") % strHome); + strXdgDataHome = boost::str(boost::format("%s/.local/share") % strHome); } - CONFIG_DIR = str(boost::format("%s/" SYSTEM_NAME) % strXdgConfigHome); + CONFIG_DIR = boost::str(boost::format("%s/" SYSTEM_NAME) % strXdgConfigHome); CONFIG_FILE = CONFIG_DIR / strConfFile; - DATA_DIR = str(boost::format("%s/" SYSTEM_NAME) % strXdgDataHome); + DATA_DIR = boost::str(boost::format("%s/" SYSTEM_NAME) % strXdgDataHome); boost::filesystem::create_directories(CONFIG_DIR, ec); if (ec) - throw std::runtime_error(str(boost::format("Can not create %s") % CONFIG_DIR)); + throw std::runtime_error(boost::str(boost::format("Can not create %s") % CONFIG_DIR)); } } + SSL_CONTEXT.set_default_verify_paths(ec); + + if (ec) + throw std::runtime_error(boost::str(boost::format("Failed to set_default_verify_paths: %s") % ec.message())); + // Update default values load(); @@ -164,10 +169,11 @@ void Config::setup(const std::string& strConf, bool bTestNet, bool bQuiet) boost::filesystem::create_directories(DATA_DIR, ec); if (ec) - throw std::runtime_error(str(boost::format("Can not create %s") % DATA_DIR)); + throw std::runtime_error(boost::str(boost::format("Can not create %s") % DATA_DIR)); } Config::Config() + : SSL_CONTEXT(boost::asio::ssl::context::sslv23) { // // Defaults diff --git a/src/cpp/ripple/Config.h b/src/cpp/ripple/Config.h index 904f12ca9..11a6b8a1b 100644 --- a/src/cpp/ripple/Config.h +++ b/src/cpp/ripple/Config.h @@ -2,6 +2,8 @@ #define __CONFIG__ #include +#include +#include #include #include "types.h" @@ -167,6 +169,8 @@ public: uint32 SIGN_VALIDATION; uint32 SIGN_PROPOSAL; + boost::asio::ssl::context SSL_CONTEXT; // Generic SSL context. + Config(); int getSize(SizedItemName); diff --git a/src/cpp/ripple/HttpsClient.cpp b/src/cpp/ripple/HttpsClient.cpp index 517e2d02f..61a105f33 100644 --- a/src/cpp/ripple/HttpsClient.cpp +++ b/src/cpp/ripple/HttpsClient.cpp @@ -12,6 +12,8 @@ #include #include +#include "Config.h" + using namespace boost::system; using namespace boost::asio; @@ -21,9 +23,8 @@ HttpsClient::HttpsClient( const std::string& strPath, std::size_t responseMax ) : - mCtx(boost::asio::ssl::context::sslv23), + mSocket(io_service, theConfig.SSL_CONTEXT), mResolver(io_service), - mSocketSsl(io_service, mCtx), mResponse(responseMax), mStrPath(strPath), mPort(port), @@ -32,10 +33,12 @@ HttpsClient::HttpsClient( } void HttpsClient::httpsGet( + bool bSSL, std::deque deqSites, boost::posix_time::time_duration timeout, boost::function complete) { + mSSL = bSSL; mDeqSites = deqSites; mComplete = complete; mTimeout = timeout; @@ -47,21 +50,12 @@ void HttpsClient::httpsNext() { // std::cerr << "Fetch: " << mDeqSites[0] << std::endl; boost::shared_ptr query(new boost::asio::ip::tcp::resolver::query(mDeqSites[0], boost::lexical_cast(mPort), - ip::resolver_query_base::numeric_service|ip::resolver_query_base::numeric_service)); + ip::resolver_query_base::numeric_service)); mQuery = query; - mCtx.set_default_verify_paths(mShutdown); - if (mShutdown) - { - std::cerr << "set_default_verify_paths: " << mShutdown.message() << std::endl; - } + mDeadline.expires_from_now(mTimeout, mShutdown); - if (!mShutdown) - { - mDeadline.expires_from_now(mTimeout, mShutdown); - - // std::cerr << "expires_from_now: " << mShutdown.message() << std::endl; - } + // std::cerr << "expires_from_now: " << mShutdown.message() << std::endl; if (!mShutdown) { @@ -106,8 +100,6 @@ void HttpsClient::handleDeadline(const boost::system::error_code& ecResult) } else { - boost::system::error_code ec_shutdown; - std::cerr << "Deadline arrived." << std::endl; // Mark us as shutting down. @@ -118,15 +110,24 @@ void HttpsClient::handleDeadline(const boost::system::error_code& ecResult) mResolver.cancel(); // Stop the transaction. - mSocketSsl.shutdown(ec_shutdown); + mSocket.async_shutdown(boost::bind( + &HttpsClient::handleShutdown, + shared_from_this(), + boost::asio::placeholders::error)); - if (ec_shutdown) - { - std::cerr << "Shutdown error: " << mDeqSites[0] << ": " << ec_shutdown.message() << std::endl; - } } } +void HttpsClient::handleShutdown( + const boost::system::error_code& ecResult + ) +{ + if (ecResult) + { + std::cerr << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message() << std::endl; + } +} + void HttpsClient::handleResolve( const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator itrEndpoint @@ -141,12 +142,12 @@ void HttpsClient::handleResolve( invokeComplete(mShutdown); } - else + else { // std::cerr << "Resolve complete." << std::endl; boost::asio::async_connect( - mSocketSsl.lowest_layer(), + mSocket.lowest_layer(), itrEndpoint, boost::bind( &HttpsClient::ShandleConnect, @@ -168,11 +169,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) if (!mShutdown) { // std::cerr << "Connected." << std::endl; - - mSocketSsl.set_verify_mode(boost::asio::ssl::verify_peer); - - // XXX Verify semantics of RFC 2818 are what we want. - mSocketSsl.set_verify_callback(boost::asio::ssl::rfc2818_verification(mDeqSites[0]), mShutdown); + mShutdown = mSocket.verify(mDeqSites[0]); if (mShutdown) { @@ -181,16 +178,22 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) } if (!mShutdown) - { - mSocketSsl.async_handshake(boost::asio::ssl::stream::client, - boost::bind(&HttpsClient::ShandleRequest, - shared_from_this(), - boost::asio::placeholders::error)); - } - else { invokeComplete(mShutdown); } + else if (mSSL) + { + mSocket.async_handshake( + AutoSocket::ssl_socket::client, + boost::bind( + &HttpsClient::ShandleRequest, + shared_from_this(), + boost::asio::placeholders::error)); + } + else + { + handleRequest(ecResult); + } } void HttpsClient::handleRequest(const boost::system::error_code& ecResult) @@ -217,7 +220,7 @@ void HttpsClient::handleRequest(const boost::system::error_code& ecResult) "Connection: close\r\n\r\n"; boost::asio::async_write( - mSocketSsl, + mSocket, mRequest, boost::bind(&HttpsClient::ShandleWrite, shared_from_this(), @@ -241,7 +244,7 @@ void HttpsClient::handleWrite(const boost::system::error_code& ecResult) // std::cerr << "Wrote." << std::endl; boost::asio::async_read( - mSocketSsl, + mSocket, mResponse, boost::asio::transfer_all(), boost::bind(&HttpsClient::ShandleData, @@ -333,6 +336,7 @@ void HttpsClient::parseData() } void HttpsClient::httpsGet( + bool bSSL, boost::asio::io_service& io_service, std::deque deqSites, const unsigned short port, @@ -343,10 +347,11 @@ void HttpsClient::httpsGet( boost::shared_ptr client(new HttpsClient(io_service, port, strPath, responseMax)); - client->httpsGet(deqSites, timeout, complete); + client->httpsGet(bSSL, deqSites, timeout, complete); } void HttpsClient::httpsGet( + bool bSSL, boost::asio::io_service& io_service, std::string strSite, const unsigned short port, @@ -359,7 +364,7 @@ void HttpsClient::httpsGet( boost::shared_ptr client(new HttpsClient(io_service, port, strPath, responseMax)); - client->httpsGet(deqSites, timeout, complete); + client->httpsGet(bSSL, deqSites, timeout, complete); } // vim:ts=4 diff --git a/src/cpp/ripple/HttpsClient.h b/src/cpp/ripple/HttpsClient.h index a9d6c9384..d9f920fff 100644 --- a/src/cpp/ripple/HttpsClient.h +++ b/src/cpp/ripple/HttpsClient.h @@ -11,6 +11,7 @@ #include #include +#include "AutoSocket.h" // // Async https client. @@ -21,10 +22,10 @@ class HttpsClient : public boost::enable_shared_from_this private: typedef boost::shared_ptr pointer; - boost::asio::ssl::context mCtx; + bool mSSL; + AutoSocket mSocket; boost::asio::ip::tcp::resolver mResolver; boost::shared_ptr mQuery; - boost::asio::ssl::stream mSocketSsl; boost::asio::streambuf mRequest; boost::asio::streambuf mResponse; const std::string mStrPath; @@ -63,6 +64,8 @@ private: static void ShandleData(pointer This, const boost::system::error_code& ecResult) { This->handleData(ecResult); } + void handleShutdown(const boost::system::error_code& ecResult); + void parseData(); void httpsNext(); @@ -78,11 +81,13 @@ public: ); void httpsGet( + bool bSSL, std::deque deqSites, boost::posix_time::time_duration timeout, boost::function complete); static void httpsGet( + bool bSSL, boost::asio::io_service& io_service, std::deque deqSites, const unsigned short port, @@ -92,6 +97,7 @@ public: boost::function complete); static void httpsGet( + bool bSSL, boost::asio::io_service& io_service, std::string strSite, const unsigned short port, diff --git a/src/cpp/ripple/OfferCreateTransactor.cpp b/src/cpp/ripple/OfferCreateTransactor.cpp index 03743e151..bbe3522ec 100644 --- a/src/cpp/ripple/OfferCreateTransactor.cpp +++ b/src/cpp/ripple/OfferCreateTransactor.cpp @@ -152,7 +152,7 @@ TER OfferCreateTransactor::takeOffers( STAmount saTakerFunds = mEngine->getNodes().accountFunds(uTakerAccountID, saTakerPays); SLE::pointer sleOfferAccount; // Owner of offer. - if (!saOfferFunds.isPositive()) + if (!saOfferFunds.isPositive()) // Includes zero. { // Offer is unfunded, possibly due to previous balance action. cLog(lsINFO) << "takeOffers: offer unfunded: delete"; diff --git a/src/cpp/ripple/RPCSub.cpp b/src/cpp/ripple/RPCSub.cpp index e85d8ffe2..e9369d7b2 100644 --- a/src/cpp/ripple/RPCSub.cpp +++ b/src/cpp/ripple/RPCSub.cpp @@ -1,5 +1,6 @@ #include +#include "Application.h" #include "RPCSub.h" #include "CallRPC.h" @@ -63,7 +64,7 @@ void RPCSub::sendThread() cLog(lsDEBUG) << boost::str(boost::format("callRPC calling: %s") % mIp); // Drop result. - (void) callRPC(mIp, mPort, mUsername, mPassword, mPath, "event", jvEvent); +// (void) callRPC(theApp->getIOService(), mIp, mPort, mUsername, mPassword, mPath, "event", jvEvent); } catch (const std::exception& e) { diff --git a/src/cpp/ripple/UniqueNodeList.cpp b/src/cpp/ripple/UniqueNodeList.cpp index c0f4d8016..3b457b7a0 100644 --- a/src/cpp/ripple/UniqueNodeList.cpp +++ b/src/cpp/ripple/UniqueNodeList.cpp @@ -824,6 +824,7 @@ void UniqueNodeList::getIpsUrl(const RippleAddress& naNodePublic, section secSit && strScheme == "https") { HttpsClient::httpsGet( + true, theApp->getIOService(), strDomain, 443, @@ -867,6 +868,7 @@ void UniqueNodeList::getValidatorsUrl(const RippleAddress& naNodePublic, section && strScheme == "https") { HttpsClient::httpsGet( + true, theApp->getIOService(), strDomain, 443, @@ -1037,6 +1039,7 @@ void UniqueNodeList::fetchProcess(std::string strDomain) deqSites.push_back(strDomain); HttpsClient::httpsGet( + true, theApp->getIOService(), deqSites, 443, @@ -1572,6 +1575,7 @@ void UniqueNodeList::nodeNetwork() if (!theConfig.VALIDATORS_SITE.empty()) { HttpsClient::httpsGet( + true, theApp->getIOService(), theConfig.VALIDATORS_SITE, 443, From 48cf9df7a6021772f02b2cbd18503986f27cca51 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 31 Jan 2013 13:06:20 -0800 Subject: [PATCH 2/7] Revised PUBLIC_BYTES_MAX to 33 bytes. --- src/cpp/ripple/Config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpp/ripple/Config.h b/src/cpp/ripple/Config.h index 11a6b8a1b..741e9a7ef 100644 --- a/src/cpp/ripple/Config.h +++ b/src/cpp/ripple/Config.h @@ -31,7 +31,7 @@ #define VALIDATORS_FILE_NAME "validators.txt" const int DOMAIN_BYTES_MAX = 256; -const int PUBLIC_BYTES_MAX = 2048; // Maximum bytes for an account public key. +const int PUBLIC_BYTES_MAX = 33; // Maximum bytes for an account public key. const int SYSTEM_PEER_PORT = 6561; const int SYSTEM_WEBSOCKET_PORT = 6562; From fb1cd25f28523aaa9b1bf19b6d5dee0513b4e767 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Thu, 31 Jan 2013 13:07:37 -0800 Subject: [PATCH 3/7] More work toward http/https client unification. --- src/cpp/ripple/CallRPC.cpp | 161 ++++++++--------- src/cpp/ripple/CallRPC.h | 3 +- src/cpp/ripple/HttpsClient.cpp | 96 ++++++++--- src/cpp/ripple/HttpsClient.h | 32 +++- src/cpp/ripple/RPC.h | 2 +- src/cpp/ripple/UniqueNodeList.cpp | 276 ++++++++++++++++-------------- src/cpp/ripple/UniqueNodeList.h | 8 +- src/cpp/ripple/rpc.cpp | 4 +- 8 files changed, 327 insertions(+), 255 deletions(-) diff --git a/src/cpp/ripple/CallRPC.cpp b/src/cpp/ripple/CallRPC.cpp index a49ff29f3..a2af5f5cd 100644 --- a/src/cpp/ripple/CallRPC.cpp +++ b/src/cpp/ripple/CallRPC.cpp @@ -575,23 +575,6 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams) return (this->*(commandsA[i].pfpFunc))(jvParams); } -void callRPCAsync( - boost::asio::io_service& isService, -#if 0 - const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, -#endif - boost::function callbackFuncP) -{ - Json::Value jvResult(Json::objectValue); - Json::Value jvSub(Json::objectValue); - - jvSub["foo"] = "bar"; - - jvResult["result"] = jvSub; - - (callbackFuncP)(jvResult); -} - // Place the async result somewhere useful. void callRPCHandler(Json::Value* jvOutput, const Json::Value& jvInput) { @@ -642,6 +625,8 @@ int commandLineRPC(const std::vector& vCmd) boost::asio::io_service isService; +// void callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL, + boost::function callbackFuncP) callRPCAsync( isService, #if 0 @@ -715,7 +700,57 @@ int commandLineRPC(const std::vector& vCmd) return nRet; } -Json::Value callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL) +#define RPC_NOTIFY_MAX_BYTES 8192 +#define RPC_NOTIFY_SECONDS 10 + +bool responseRPC( + boost::function callbackFuncP, + const boost::system::error_code& ecResult, int iStatus, const std::string& strData) +{ + // Receive reply + if (iStatus == 401) + throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); + else if ((iStatus >= 400) && (iStatus != 400) && (iStatus != 404) && (iStatus != 500)) // ? + throw std::runtime_error(strprintf("server returned HTTP error %d", iStatus)); + else if (strData.empty()) + throw std::runtime_error("no response from server"); + + // Parse reply + cLog(lsDEBUG) << "RPC reply: " << strData << std::endl; + + Json::Reader reader; + Json::Value jvReply; + + if (!reader.parse(strData, jvReply)) + throw std::runtime_error("couldn't parse reply from server"); + + if (jvReply.isNull()) + throw std::runtime_error("expected reply to have result, error and id properties"); + + Json::Value jvResult(Json::objectValue); + + jvResult["result"] = jvReply; + + (callbackFuncP)(jvResult); + + return false; +} + +// Build the request. +void requestRPC(const std::string& strMethod, const Json::Value& jvParams, const std::map& mHeaders, const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost) +{ + std::ostream osRequest(&sb); + + osRequest << + createHTTPPost( + strHost, + strPath, + JSONRPCRequest(strMethod, jvParams, Json::Value(1)), + mHeaders); +} + +void callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL, + boost::function callbackFuncP) { // Connect to localhost if (!theConfig.QUIET) @@ -726,86 +761,32 @@ Json::Value callRPC(const std::string& strIp, const int iPort, const std::string // std::cerr << "Method: " << strMethod << std::endl; } - boost::asio::ip::tcp::endpoint - endpoint(boost::asio::ip::address::from_string(strIp), iPort); - boost::asio::ip::tcp::iostream stream; - boost::asio::io_service isService; - boost::asio::ssl::context cContext(boost::asio::ssl::context::sslv23); - boost::asio::ssl::stream stream_ssl(isService, cContext); - - if (bSSL) - { -// stream_ssl.connect(endpoint); -// if (stream_ssl.fail()) -// throw std::runtime_error("couldn't connect to server"); - } - else - { - stream.connect(endpoint); - if (stream.fail()) - throw std::runtime_error("couldn't connect to server"); - } - - // cLog(lsDEBUG) << "connected" << std::endl; - // HTTP basic authentication std::string strUserPass64 = EncodeBase64(strUsername + ":" + strPassword); + std::map mapRequestHeaders; + mapRequestHeaders["Authorization"] = std::string("Basic ") + strUserPass64; - // Log(lsDEBUG) << "requesting" << std::endl; - // Send request - std::string strRequest = JSONRPCRequest(strMethod, jvParams, Json::Value(1)); + // Log(lsDEBUG) << "requesting" << std::endl; // cLog(lsDEBUG) << "send request " << strMethod << " : " << strRequest << std::endl; - std::string strPost = createHTTPPost(strPath, strRequest, mapRequestHeaders); - if (bSSL) - { -// stream_ssl << strPost << std::flush; - } - else - { - stream << strPost << std::flush; - } - - // std::cerr << "post " << strPost << std::endl; - - // Receive reply - std::map mapHeaders; - std::string strReply; - - int nStatus; - - if (bSSL) - { -// nStatus = ReadHTTP(stream_ssl, mapHeaders, strReply); - } - else - { - nStatus = ReadHTTP(stream, mapHeaders, strReply); - } - - if (nStatus == 401) - throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); - else if ((nStatus >= 400) && (nStatus != 400) && (nStatus != 404) && (nStatus != 500)) // ? - throw std::runtime_error(strprintf("server returned HTTP error %d", nStatus)); - else if (strReply.empty()) - throw std::runtime_error("no response from server"); - - // Parse reply - cLog(lsDEBUG) << "RPC reply: " << strReply << std::endl; - - Json::Reader reader; - Json::Value valReply; - - if (!reader.parse(strReply, valReply)) - throw std::runtime_error("couldn't parse reply from server"); - - if (valReply.isNull()) - throw std::runtime_error("expected reply to have result, error and id properties"); - - return valReply; + HttpsClient::httpsRequest( + bSSL, + theApp->getIOService(), + strIp, + iPort, + boost::bind( + &requestRPC, + strMethod, + jvParams, + mapRequestHeaders, + "/", _1, _2), + RPC_NOTIFY_MAX_BYTES, + boost::posix_time::seconds(RPC_NOTIFY_SECONDS), + boost::bind(&responseRPC, callbackFuncP, _1, _2, _3)); } + // vim:ts=4 diff --git a/src/cpp/ripple/CallRPC.h b/src/cpp/ripple/CallRPC.h index 5a5aae7a0..aba9ce6e9 100644 --- a/src/cpp/ripple/CallRPC.h +++ b/src/cpp/ripple/CallRPC.h @@ -48,7 +48,8 @@ public: }; extern int commandLineRPC(const std::vector& vCmd); -extern Json::Value callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& params); +extern void void callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL, + boost::function callbackFuncP); #endif diff --git a/src/cpp/ripple/HttpsClient.cpp b/src/cpp/ripple/HttpsClient.cpp index 61a105f33..d35111765 100644 --- a/src/cpp/ripple/HttpsClient.cpp +++ b/src/cpp/ripple/HttpsClient.cpp @@ -20,32 +20,61 @@ using namespace boost::asio; HttpsClient::HttpsClient( boost::asio::io_service& io_service, const unsigned short port, - const std::string& strPath, std::size_t responseMax ) : mSocket(io_service, theConfig.SSL_CONTEXT), mResolver(io_service), mResponse(responseMax), - mStrPath(strPath), mPort(port), mDeadline(io_service) { } -void HttpsClient::httpsGet( +void HttpsClient::makeGet(const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost) +{ + std::ostream osRequest(&sb); + + osRequest << + "GET " << strPath << " HTTP/1.0\r\n" + "Host: " << strHost << "\r\n" + "Accept: */*\r\n" // YYY Do we need this line? + "Connection: close\r\n\r\n"; +} + +void HttpsClient::httpsRequest( bool bSSL, std::deque deqSites, + boost::function build, boost::posix_time::time_duration timeout, - boost::function complete) { - + boost::function complete) +{ mSSL = bSSL; mDeqSites = deqSites; + mBuild = build; mComplete = complete; mTimeout = timeout; httpsNext(); } +void HttpsClient::httpsGet( + bool bSSL, + std::deque deqSites, + const std::string& strPath, + boost::posix_time::time_duration timeout, + boost::function complete) { + + mComplete = complete; + mTimeout = timeout; + + httpsRequest( + bSSL, + deqSites, + boost::bind(&HttpsClient::makeGet, shared_from_this(), strPath, _1, _2), + timeout, + complete); +} + void HttpsClient::httpsNext() { // std::cerr << "Fetch: " << mDeqSites[0] << std::endl; @@ -150,7 +179,7 @@ void HttpsClient::handleResolve( mSocket.lowest_layer(), itrEndpoint, boost::bind( - &HttpsClient::ShandleConnect, + &HttpsClient::handleConnect, shared_from_this(), boost::asio::placeholders::error)); } @@ -210,14 +239,7 @@ void HttpsClient::handleRequest(const boost::system::error_code& ecResult) else { // std::cerr << "SSL session started." << std::endl; - - std::ostream osRequest(&mRequest); - - osRequest << - "GET " << mStrPath << " HTTP/1.0\r\n" - "Host: " << mDeqSites[0] << "\r\n" - "Accept: */*\r\n" // YYY Do we need this line? - "Connection: close\r\n\r\n"; + mBuild(mRequest, mDeqSites[0]); boost::asio::async_write( mSocket, @@ -282,7 +304,7 @@ void HttpsClient::handleData(const boost::system::error_code& ecResult) } // Call cancel the deadline timer and invoke the completion routine. -void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, std::string strData) +void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, int iStatus, const std::string& strData) { boost::system::error_code ecCancel; @@ -295,11 +317,17 @@ void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, std: mDeqSites.pop_front(); - if (mDeqSites.empty()) + bool bAgain = true; + + if (mDeqSites.empty() || !ecResult) { - mComplete(ecResult ? ecResult : ecCancel, strData); + // ecResult: !0 = had an error, last entry + // iStatus: result, if no error + // strData: data, if no error + bAgain = mComplete(ecResult ? ecResult : ecCancel, iStatus, strData); } - else + + if (!mDeqSites.empty() && bAgain) { httpsNext(); } @@ -315,7 +343,6 @@ void HttpsClient::parseData() boost::smatch smMatch; bool bMatch = boost::regex_match(strData, smMatch, reStatus) // Match status code. - && !smMatch[1].compare("200") && boost::regex_match(strData, smMatch, reBody); // Match body. // std::cerr << "Data:" << strData << std::endl; @@ -326,7 +353,7 @@ void HttpsClient::parseData() { boost::system::error_code noErr; - invokeComplete(noErr, smMatch[1]); + invokeComplete(noErr, lexical_cast_st(smMatch[1]), smMatch[1]); } else { @@ -343,11 +370,11 @@ void HttpsClient::httpsGet( const std::string& strPath, std::size_t responseMax, boost::posix_time::time_duration timeout, - boost::function complete) { + boost::function complete) { - boost::shared_ptr client(new HttpsClient(io_service, port, strPath, responseMax)); + boost::shared_ptr client(new HttpsClient(io_service, port, responseMax)); - client->httpsGet(bSSL, deqSites, timeout, complete); + client->httpsGet(bSSL, deqSites, strPath, timeout, complete); } void HttpsClient::httpsGet( @@ -358,13 +385,30 @@ void HttpsClient::httpsGet( const std::string& strPath, std::size_t responseMax, boost::posix_time::time_duration timeout, - boost::function complete) { + boost::function complete) { std::deque deqSites(1, strSite); - boost::shared_ptr client(new HttpsClient(io_service, port, strPath, responseMax)); + boost::shared_ptr client(new HttpsClient(io_service, port, responseMax)); - client->httpsGet(bSSL, deqSites, timeout, complete); + client->httpsGet(bSSL, deqSites, strPath, timeout, complete); +} + +void HttpsClient::httpsRequest( + bool bSSL, + boost::asio::io_service& io_service, + std::string strSite, + const unsigned short port, + boost::function setRequest, + std::size_t responseMax, + boost::posix_time::time_duration timeout, + boost::function complete) { + + std::deque deqSites(1, strSite); + + boost::shared_ptr client(new HttpsClient(io_service, port, responseMax)); + + client->httpsRequest(bSSL, deqSites, setRequest, timeout, complete); } // vim:ts=4 diff --git a/src/cpp/ripple/HttpsClient.h b/src/cpp/ripple/HttpsClient.h index d9f920fff..9744d176f 100644 --- a/src/cpp/ripple/HttpsClient.h +++ b/src/cpp/ripple/HttpsClient.h @@ -28,9 +28,9 @@ private: boost::shared_ptr mQuery; boost::asio::streambuf mRequest; boost::asio::streambuf mResponse; - const std::string mStrPath; const unsigned short mPort; - boost::function mComplete; + boost::function mBuild; + boost::function mComplete; boost::asio::deadline_timer mDeadline; @@ -69,22 +69,30 @@ private: void parseData(); void httpsNext(); - void invokeComplete(const boost::system::error_code& ecResult, std::string strData = ""); + void invokeComplete(const boost::system::error_code& ecResult, int iStatus = 0, const std::string& strData = ""); + void makeGet(const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost); public: HttpsClient( boost::asio::io_service& io_service, const unsigned short port, - const std::string& strPath, std::size_t responseMax ); + void httpsRequest( + bool bSSL, + std::deque deqSites, + boost::function build, + boost::posix_time::time_duration timeout, + boost::function complete); + void httpsGet( bool bSSL, std::deque deqSites, + const std::string& strPath, boost::posix_time::time_duration timeout, - boost::function complete); + boost::function complete); static void httpsGet( bool bSSL, @@ -94,7 +102,7 @@ public: const std::string& strPath, std::size_t responseMax, boost::posix_time::time_duration timeout, - boost::function complete); + boost::function complete); static void httpsGet( bool bSSL, @@ -104,7 +112,17 @@ public: const std::string& strPath, std::size_t responseMax, boost::posix_time::time_duration timeout, - boost::function complete); + boost::function complete); + + static void httpsRequest( + bool bSSL, + boost::asio::io_service& io_service, + std::string strSite, + const unsigned short port, + boost::function build, + std::size_t responseMax, + boost::posix_time::time_duration timeout, + boost::function complete); }; #endif // vim:ts=4 diff --git a/src/cpp/ripple/RPC.h b/src/cpp/ripple/RPC.h index 475cff649..ea180e5b1 100644 --- a/src/cpp/ripple/RPC.h +++ b/src/cpp/ripple/RPC.h @@ -29,7 +29,7 @@ enum http_status_type extern std::string JSONRPCRequest(const std::string& strMethod, const Json::Value& params, const Json::Value& id); -extern std::string createHTTPPost(const std::string& strPath, const std::string& strMsg, +extern std::string createHTTPPost(const std::string& strHost, const std::string& strPath, const std::string& strMsg, const std::map& mapRequestHeaders); extern int ReadHTTP(std::basic_istream& stream, diff --git a/src/cpp/ripple/UniqueNodeList.cpp b/src/cpp/ripple/UniqueNodeList.cpp index 3b457b7a0..706183ced 100644 --- a/src/cpp/ripple/UniqueNodeList.cpp +++ b/src/cpp/ripple/UniqueNodeList.cpp @@ -795,16 +795,23 @@ int UniqueNodeList::processValidators(const std::string& strSite, const std::str } // Given a section with IPs, parse and persist it for a validator. -void UniqueNodeList::responseIps(const std::string& strSite, const RippleAddress& naNodePublic, const boost::system::error_code& err, const std::string& strIpsFile) +bool UniqueNodeList::responseIps(const std::string& strSite, const RippleAddress& naNodePublic, const boost::system::error_code& err, int iStatus, const std::string& strIpsFile) { - if (!err) - { - section secFile = ParseSection(strIpsFile, true); + bool bReject = !err && iStatus != 200; - processIps(strSite, naNodePublic, sectionEntries(secFile, SECTION_IPS)); + if (!bReject) + { + if (!err) + { + section secFile = ParseSection(strIpsFile, true); + + processIps(strSite, naNodePublic, sectionEntries(secFile, SECTION_IPS)); + } + + fetchFinish(); } - fetchFinish(); + return bReject; } // Process section [ips_url]. @@ -831,7 +838,7 @@ void UniqueNodeList::getIpsUrl(const RippleAddress& naNodePublic, section secSit strPath, NODE_FILE_BYTES_MAX, boost::posix_time::seconds(NODE_FETCH_SECONDS), - boost::bind(&UniqueNodeList::responseIps, this, strDomain, naNodePublic, _1, _2)); + boost::bind(&UniqueNodeList::responseIps, this, strDomain, naNodePublic, _1, _2, _3)); } else { @@ -840,16 +847,23 @@ void UniqueNodeList::getIpsUrl(const RippleAddress& naNodePublic, section secSit } // After fetching a ripple.txt from a web site, given a section with validators, parse and persist it. -void UniqueNodeList::responseValidators(const std::string& strValidatorsUrl, const RippleAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string& strValidatorsFile) +bool UniqueNodeList::responseValidators(const std::string& strValidatorsUrl, const RippleAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, int iStatus, const std::string& strValidatorsFile) { - if (!err) - { - section secFile = ParseSection(strValidatorsFile, true); + bool bReject = !err && iStatus != 200; - processValidators(strSite, strValidatorsUrl, naNodePublic, vsValidator, sectionEntries(secFile, SECTION_VALIDATORS)); + if (!bReject) + { + if (!err) + { + section secFile = ParseSection(strValidatorsFile, true); + + processValidators(strSite, strValidatorsUrl, naNodePublic, vsValidator, sectionEntries(secFile, SECTION_VALIDATORS)); + } + + getIpsUrl(naNodePublic, secSite); } - getIpsUrl(naNodePublic, secSite); + return bReject; } // Process section [validators_url]. @@ -875,7 +889,7 @@ void UniqueNodeList::getValidatorsUrl(const RippleAddress& naNodePublic, section strPath, NODE_FILE_BYTES_MAX, boost::posix_time::seconds(NODE_FETCH_SECONDS), - boost::bind(&UniqueNodeList::responseValidators, this, strValidatorsUrl, naNodePublic, secSite, strDomain, _1, _2)); + boost::bind(&UniqueNodeList::responseValidators, this, strValidatorsUrl, naNodePublic, secSite, strDomain, _1, _2, _3)); } else { @@ -911,118 +925,125 @@ void UniqueNodeList::processFile(const std::string& strDomain, const RippleAddre } // Given a ripple.txt, process it. -void UniqueNodeList::responseFetch(const std::string& strDomain, const boost::system::error_code& err, const std::string& strSiteFile) +bool UniqueNodeList::responseFetch(const std::string& strDomain, const boost::system::error_code& err, int iStatus, const std::string& strSiteFile) { - section secSite = ParseSection(strSiteFile, true); - bool bGood = !err; + bool bReject = !err && iStatus != 200; - if (bGood) + if (!bReject) { - cLog(lsTRACE) << boost::format("Validator: '%s' received " NODE_FILE_NAME ".") % strDomain; - } - else - { - cLog(lsTRACE) - << boost::format("Validator: '%s' unable to retrieve " NODE_FILE_NAME ": %s") - % strDomain - % err.message(); - } + section secSite = ParseSection(strSiteFile, true); + bool bGood = !err; - // - // Verify file domain - // - std::string strSite; - - if (bGood && !sectionSingleB(secSite, SECTION_DOMAIN, strSite)) - { - bGood = false; - - cLog(lsTRACE) - << boost::format("Validator: '%s' bad " NODE_FILE_NAME " missing single entry for " SECTION_DOMAIN ".") - % strDomain; - } - - if (bGood && strSite != strDomain) - { - bGood = false; - - cLog(lsTRACE) - << boost::format("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_DOMAIN " does not match: %s") - % strDomain - % strSite; - } - - // - // Process public key - // - std::string strNodePublicKey; - - if (bGood && !sectionSingleB(secSite, SECTION_PUBLIC_KEY, strNodePublicKey)) - { - // Bad [validation_public_key] section. - bGood = false; - - cLog(lsTRACE) - << boost::format("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_PUBLIC_KEY " does not have single entry.") - % strDomain; - } - - RippleAddress naNodePublic; - - if (bGood && !naNodePublic.setNodePublic(strNodePublicKey)) - { - // Bad public key. - bGood = false; - - cLog(lsTRACE) - << boost::format("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_PUBLIC_KEY " is bad: ") - % strDomain - % strNodePublicKey; - } - - if (bGood) - { -// cLog(lsTRACE) << boost::format("naNodePublic: '%s'") % naNodePublic.humanNodePublic(); - - seedDomain sdCurrent; - - bool bFound = getSeedDomains(strDomain, sdCurrent); - - assert(bFound); - - uint256 iSha256 = Serializer::getSHA512Half(strSiteFile); - bool bChangedB = sdCurrent.iSha256 != iSha256; - - sdCurrent.strDomain = strDomain; - // XXX If the node public key is changing, delete old public key information? - // XXX Only if no other refs to keep it arround, other wise we have an attack vector. - sdCurrent.naPublicKey = naNodePublic; - -// cLog(lsTRACE) << boost::format("sdCurrent.naPublicKey: '%s'") % sdCurrent.naPublicKey.humanNodePublic(); - - sdCurrent.tpFetch = boost::posix_time::second_clock::universal_time(); - sdCurrent.iSha256 = iSha256; - - setSeedDomains(sdCurrent, true); - - if (bChangedB) + if (bGood) { - cLog(lsTRACE) << boost::format("Validator: '%s' processing new " NODE_FILE_NAME ".") % strDomain; - processFile(strDomain, naNodePublic, secSite); + cLog(lsTRACE) << boost::format("Validator: '%s' received " NODE_FILE_NAME ".") % strDomain; } else { - cLog(lsTRACE) << boost::format("Validator: '%s' no change for " NODE_FILE_NAME ".") % strDomain; + cLog(lsTRACE) + << boost::format("Validator: '%s' unable to retrieve " NODE_FILE_NAME ": %s") + % strDomain + % err.message(); + } + + // + // Verify file domain + // + std::string strSite; + + if (bGood && !sectionSingleB(secSite, SECTION_DOMAIN, strSite)) + { + bGood = false; + + cLog(lsTRACE) + << boost::format("Validator: '%s' bad " NODE_FILE_NAME " missing single entry for " SECTION_DOMAIN ".") + % strDomain; + } + + if (bGood && strSite != strDomain) + { + bGood = false; + + cLog(lsTRACE) + << boost::format("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_DOMAIN " does not match: %s") + % strDomain + % strSite; + } + + // + // Process public key + // + std::string strNodePublicKey; + + if (bGood && !sectionSingleB(secSite, SECTION_PUBLIC_KEY, strNodePublicKey)) + { + // Bad [validation_public_key] section. + bGood = false; + + cLog(lsTRACE) + << boost::format("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_PUBLIC_KEY " does not have single entry.") + % strDomain; + } + + RippleAddress naNodePublic; + + if (bGood && !naNodePublic.setNodePublic(strNodePublicKey)) + { + // Bad public key. + bGood = false; + + cLog(lsTRACE) + << boost::format("Validator: '%s' bad " NODE_FILE_NAME " " SECTION_PUBLIC_KEY " is bad: ") + % strDomain + % strNodePublicKey; + } + + if (bGood) + { + // cLog(lsTRACE) << boost::format("naNodePublic: '%s'") % naNodePublic.humanNodePublic(); + + seedDomain sdCurrent; + + bool bFound = getSeedDomains(strDomain, sdCurrent); + + assert(bFound); + + uint256 iSha256 = Serializer::getSHA512Half(strSiteFile); + bool bChangedB = sdCurrent.iSha256 != iSha256; + + sdCurrent.strDomain = strDomain; + // XXX If the node public key is changing, delete old public key information? + // XXX Only if no other refs to keep it arround, other wise we have an attack vector. + sdCurrent.naPublicKey = naNodePublic; + + // cLog(lsTRACE) << boost::format("sdCurrent.naPublicKey: '%s'") % sdCurrent.naPublicKey.humanNodePublic(); + + sdCurrent.tpFetch = boost::posix_time::second_clock::universal_time(); + sdCurrent.iSha256 = iSha256; + + setSeedDomains(sdCurrent, true); + + if (bChangedB) + { + cLog(lsTRACE) << boost::format("Validator: '%s' processing new " NODE_FILE_NAME ".") % strDomain; + processFile(strDomain, naNodePublic, secSite); + } + else + { + cLog(lsTRACE) << boost::format("Validator: '%s' no change for " NODE_FILE_NAME ".") % strDomain; + fetchFinish(); + } + } + else + { + // Failed: Update + + // XXX If we have public key, perhaps try look up in CAS? fetchFinish(); } } - else - { - // Failed: Update - // XXX If we have public key, perhaps try look up in CAS? - fetchFinish(); - } + return bReject; } // Get the ripple.txt and process it. @@ -1046,7 +1067,7 @@ void UniqueNodeList::fetchProcess(std::string strDomain) NODE_FILE_PATH, NODE_FILE_BYTES_MAX, boost::posix_time::seconds(NODE_FETCH_SECONDS), - boost::bind(&UniqueNodeList::responseFetch, this, strDomain, _1, _2)); + boost::bind(&UniqueNodeList::responseFetch, this, strDomain, _1, _2, _3)); } void UniqueNodeList::fetchTimerHandler(const boost::system::error_code& err) @@ -1556,18 +1577,25 @@ bool UniqueNodeList::nodeLoad(boost::filesystem::path pConfig) return true; } -void UniqueNodeList::validatorsResponse(const boost::system::error_code& err, std::string strResponse) +bool UniqueNodeList::validatorsResponse(const boost::system::error_code& err, int iStatus, std::string strResponse) { - cLog(lsTRACE) << "Fetch '" VALIDATORS_FILE_NAME "' complete."; + bool bReject = !err && iStatus != 200; - if (!err) + if (!bReject) { - nodeProcess("network", strResponse, theConfig.VALIDATORS_SITE); - } - else - { - cLog(lsWARNING) << "Error: " << err.message(); + cLog(lsTRACE) << "Fetch '" VALIDATORS_FILE_NAME "' complete."; + + if (!err) + { + nodeProcess("network", strResponse, theConfig.VALIDATORS_SITE); + } + else + { + cLog(lsWARNING) << "Error: " << err.message(); + } } + + return bReject; } void UniqueNodeList::nodeNetwork() @@ -1582,7 +1610,7 @@ void UniqueNodeList::nodeNetwork() theConfig.VALIDATORS_URI, VALIDATORS_FILE_BYTES_MAX, boost::posix_time::seconds(VALIDATORS_FETCH_SECONDS), - boost::bind(&UniqueNodeList::validatorsResponse, this, _1, _2)); + boost::bind(&UniqueNodeList::validatorsResponse, this, _1, _2, _3)); } } diff --git a/src/cpp/ripple/UniqueNodeList.h b/src/cpp/ripple/UniqueNodeList.h index 9cf511d84..fb662c532 100644 --- a/src/cpp/ripple/UniqueNodeList.h +++ b/src/cpp/ripple/UniqueNodeList.h @@ -98,7 +98,7 @@ private: bool scoreRound(std::vector& vsnNodes); - void responseFetch(const std::string& strDomain, const boost::system::error_code& err, const std::string& strSiteFile); + bool responseFetch(const std::string& strDomain, const boost::system::error_code& err, int iStatus, const std::string& strSiteFile); boost::posix_time::ptime mtpScoreNext; // When to start scoring. boost::posix_time::ptime mtpScoreStart; // Time currently started scoring. @@ -122,8 +122,8 @@ private: void getValidatorsUrl(const RippleAddress& naNodePublic, section secSite); void getIpsUrl(const RippleAddress& naNodePublic, section secSite); - void responseIps(const std::string& strSite, const RippleAddress& naNodePublic, const boost::system::error_code& err, const std::string& strIpsFile); - void responseValidators(const std::string& strValidatorsUrl, const RippleAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, const std::string& strValidatorsFile); + bool responseIps(const std::string& strSite, const RippleAddress& naNodePublic, const boost::system::error_code& err, int iStatus, const std::string& strIpsFile); + bool responseValidators(const std::string& strValidatorsUrl, const RippleAddress& naNodePublic, section secSite, const std::string& strSite, const boost::system::error_code& err, int iStatus, const std::string& strValidatorsFile); void processIps(const std::string& strSite, const RippleAddress& naNodePublic, section::mapped_type* pmtVecStrIps); int processValidators(const std::string& strSite, const std::string& strValidatorsSrc, const RippleAddress& naNodePublic, validatorSource vsWhy, section::mapped_type* pmtVecStrValidators); @@ -136,7 +136,7 @@ private: bool getSeedNodes(const RippleAddress& naNodePublic, seedNode& dstSeedNode); void setSeedNodes(const seedNode& snSource, bool bNext); - void validatorsResponse(const boost::system::error_code& err, std::string strResponse); + bool validatorsResponse(const boost::system::error_code& err, int iStatus, const std::string strResponse); void nodeProcess(const std::string& strSite, const std::string& strValidators, const std::string& strSource); public: diff --git a/src/cpp/ripple/rpc.cpp b/src/cpp/ripple/rpc.cpp index 095ed977e..653daaa6c 100644 --- a/src/cpp/ripple/rpc.cpp +++ b/src/cpp/ripple/rpc.cpp @@ -39,7 +39,7 @@ Json::Value JSONRPCError(int code, const std::string& message) // and to be compatible with other JSON-RPC implementations. // -std::string createHTTPPost(const std::string& strPath, const std::string& strMsg, const std::map& mapRequestHeaders) +std::string createHTTPPost(const std::string& strHost, const std::string& strPath, const std::string& strMsg, const std::map& mapRequestHeaders) { std::ostringstream s; @@ -47,7 +47,7 @@ std::string createHTTPPost(const std::string& strPath, const std::string& strMsg << (strPath.empty() ? "/" : strPath) << " HTTP/1.1\r\n" << "User-Agent: " SYSTEM_NAME "-json-rpc/" << FormatFullVersion() << "\r\n" - << "Host: 127.0.0.1\r\n" + << "Host: " << strHost << "\r\n" << "Content-Type: application/json\r\n" << "Content-Length: " << strMsg.size() << "\r\n" << "Accept: application/json\r\n"; From e53e27cfa6315521a18d448f9841be57e24d5292 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 1 Feb 2013 17:06:36 -0800 Subject: [PATCH 4/7] Always provided extended RPC ledger_header info. --- src/cpp/ripple/RPCHandler.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/cpp/ripple/RPCHandler.cpp b/src/cpp/ripple/RPCHandler.cpp index e6a245aad..43a4aefbb 100644 --- a/src/cpp/ripple/RPCHandler.cpp +++ b/src/cpp/ripple/RPCHandler.cpp @@ -2299,11 +2299,8 @@ Json::Value RPCHandler::doLedgerHeader(Json::Value jvRequest) jvResult["ledger_data"] = strHex(s.peekData()); - if (mRole == ADMIN) - { - // As admin, they can trust us, so we provide this information. - lpLedger->addJson(jvResult, 0); - } + // This information isn't verified, they should only use it if they trust us. + lpLedger->addJson(jvResult, 0); return jvResult; } From c834ce4e065691bc201fd25badf51bfa4c8a0e52 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 1 Feb 2013 18:10:53 -0800 Subject: [PATCH 5/7] More work toward http/https client merge. --- src/cpp/ripple/AutoSocket.h | 1 - src/cpp/ripple/CallRPC.cpp | 24 ++++++++++---------- src/cpp/ripple/CallRPC.h | 9 ++++++-- src/cpp/ripple/HttpsClient.cpp | 40 +++++++++++++++++----------------- src/cpp/ripple/HttpsClient.h | 14 +----------- 5 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/cpp/ripple/AutoSocket.h b/src/cpp/ripple/AutoSocket.h index 73883f41f..8b87ec125 100644 --- a/src/cpp/ripple/AutoSocket.h +++ b/src/cpp/ripple/AutoSocket.h @@ -152,7 +152,6 @@ public: boost::asio::async_write(PlainSocket(), buffers, handler); } - template void async_read(const Buf& buffers, Condition cond, Handler handler) { diff --git a/src/cpp/ripple/CallRPC.cpp b/src/cpp/ripple/CallRPC.cpp index a2af5f5cd..16c95727a 100644 --- a/src/cpp/ripple/CallRPC.cpp +++ b/src/cpp/ripple/CallRPC.cpp @@ -625,22 +625,16 @@ int commandLineRPC(const std::vector& vCmd) boost::asio::io_service isService; -// void callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL, - boost::function callbackFuncP) - callRPCAsync( + callRPC( isService, -#if 0 - theConfig.RPC_IP, - theConfig.RPC_PORT, - theConfig.RPC_USER, - theConfig.RPC_PASSWORD, + theConfig.RPC_IP, theConfig.RPC_PORT, + theConfig.RPC_USER, theConfig.RPC_PASSWORD, "", jvRequest.isMember("method") // Allow parser to rewrite method. ? jvRequest["method"].asString() : vCmd[0], jvParams, // Parsed, execute. - boost::bind(callRPCHandler, jvOutput, _1)); -#endif + false, boost::bind(callRPCHandler, &jvOutput, _1)); isService.run(); // This blocks until there is no more outstanding async calls. @@ -749,7 +743,12 @@ void requestRPC(const std::string& strMethod, const Json::Value& jvParams, const mHeaders); } -void callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL, +void callRPC( + boost::asio::io_service& io_service, + const std::string& strIp, const int iPort, + const std::string& strUsername, const std::string& strPassword, + const std::string& strPath, const std::string& strMethod, + const Json::Value& jvParams, const bool bSSL, boost::function callbackFuncP) { // Connect to localhost @@ -774,7 +773,7 @@ void callRPC(const std::string& strIp, const int iPort, const std::string& strUs HttpsClient::httpsRequest( bSSL, - theApp->getIOService(), + io_service, strIp, iPort, boost::bind( @@ -788,5 +787,4 @@ void callRPC(const std::string& strIp, const int iPort, const std::string& strUs boost::bind(&responseRPC, callbackFuncP, _1, _2, _3)); } - // vim:ts=4 diff --git a/src/cpp/ripple/CallRPC.h b/src/cpp/ripple/CallRPC.h index aba9ce6e9..939d37a28 100644 --- a/src/cpp/ripple/CallRPC.h +++ b/src/cpp/ripple/CallRPC.h @@ -48,9 +48,14 @@ public: }; extern int commandLineRPC(const std::vector& vCmd); -extern void void callRPC(const std::string& strIp, const int iPort, const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL, - boost::function callbackFuncP); +extern void callRPC( + boost::asio::io_service& io_service, + const std::string& strIp, const int iPort, + const std::string& strUsername, const std::string& strPassword, + const std::string& strPath, const std::string& strMethod, + const Json::Value& jvParams, const bool bSSL, + boost::function callbackFuncP); #endif // vim:ts=4 diff --git a/src/cpp/ripple/HttpsClient.cpp b/src/cpp/ripple/HttpsClient.cpp index d35111765..2713b3094 100644 --- a/src/cpp/ripple/HttpsClient.cpp +++ b/src/cpp/ripple/HttpsClient.cpp @@ -77,31 +77,31 @@ void HttpsClient::httpsGet( void HttpsClient::httpsNext() { - // std::cerr << "Fetch: " << mDeqSites[0] << std::endl; +std::cerr << "Fetch: " << mDeqSites[0] << std::endl; boost::shared_ptr query(new boost::asio::ip::tcp::resolver::query(mDeqSites[0], boost::lexical_cast(mPort), ip::resolver_query_base::numeric_service)); mQuery = query; mDeadline.expires_from_now(mTimeout, mShutdown); - // std::cerr << "expires_from_now: " << mShutdown.message() << std::endl; +std::cerr << "expires_from_now: " << mShutdown.message() << std::endl; if (!mShutdown) { mDeadline.async_wait( boost::bind( - &HttpsClient::ShandleDeadline, + &HttpsClient::handleDeadline, shared_from_this(), boost::asio::placeholders::error)); } if (!mShutdown) { - // std::cerr << "Resolving: " << mDeqSites[0] << std::endl; +std::cerr << "Resolving: " << mDeqSites[0] << std::endl; mResolver.async_resolve(*mQuery, boost::bind( - &HttpsClient::ShandleResolve, + &HttpsClient::handleResolve, shared_from_this(), boost::asio::placeholders::error, boost::asio::placeholders::iterator)); @@ -116,7 +116,7 @@ void HttpsClient::handleDeadline(const boost::system::error_code& ecResult) if (ecResult == boost::asio::error::operation_aborted) { // Timer canceled because deadline no longer needed. - // std::cerr << "Deadline cancelled." << std::endl; +std::cerr << "Deadline cancelled." << std::endl; nothing(); // Aborter is done. } @@ -167,13 +167,13 @@ void HttpsClient::handleResolve( if (mShutdown) { - // std::cerr << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message() << std::endl; +std::cerr << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message() << std::endl; invokeComplete(mShutdown); } else { - // std::cerr << "Resolve complete." << std::endl; +std::cerr << "Resolve complete." << std::endl; boost::asio::async_connect( mSocket.lowest_layer(), @@ -197,7 +197,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) if (!mShutdown) { - // std::cerr << "Connected." << std::endl; +std::cerr << "Connected." << std::endl; mShutdown = mSocket.verify(mDeqSites[0]); if (mShutdown) @@ -206,7 +206,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) } } - if (!mShutdown) + if (mShutdown) { invokeComplete(mShutdown); } @@ -215,7 +215,7 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) mSocket.async_handshake( AutoSocket::ssl_socket::client, boost::bind( - &HttpsClient::ShandleRequest, + &HttpsClient::handleRequest, shared_from_this(), boost::asio::placeholders::error)); } @@ -238,19 +238,19 @@ void HttpsClient::handleRequest(const boost::system::error_code& ecResult) } else { - // std::cerr << "SSL session started." << std::endl; +std::cerr << "Session started." << std::endl; mBuild(mRequest, mDeqSites[0]); - boost::asio::async_write( - mSocket, + mSocket.async_write( mRequest, - boost::bind(&HttpsClient::ShandleWrite, + boost::bind(&HttpsClient::handleWrite, shared_from_this(), - boost::asio::placeholders::error)); + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); } } -void HttpsClient::handleWrite(const boost::system::error_code& ecResult) +void HttpsClient::handleWrite(const boost::system::error_code& ecResult, std::size_t bytes_transferred) { if (!mShutdown) mShutdown = ecResult; @@ -263,13 +263,13 @@ void HttpsClient::handleWrite(const boost::system::error_code& ecResult) } else { - // std::cerr << "Wrote." << std::endl; +std::cerr << "Wrote." << std::endl; boost::asio::async_read( mSocket, mResponse, boost::asio::transfer_all(), - boost::bind(&HttpsClient::ShandleData, + boost::bind(&HttpsClient::handleData, shared_from_this(), boost::asio::placeholders::error)); } @@ -290,7 +290,7 @@ void HttpsClient::handleData(const boost::system::error_code& ecResult) { if (mShutdown) { - // std::cerr << "Complete." << std::endl; +std::cerr << "Complete." << std::endl; nothing(); } else diff --git a/src/cpp/ripple/HttpsClient.h b/src/cpp/ripple/HttpsClient.h index 9744d176f..1080b50b6 100644 --- a/src/cpp/ripple/HttpsClient.h +++ b/src/cpp/ripple/HttpsClient.h @@ -41,28 +41,16 @@ private: boost::posix_time::time_duration mTimeout; void handleDeadline(const boost::system::error_code& ecResult); - static void ShandleDeadline(pointer This, const boost::system::error_code& ecResult) - { This->handleDeadline(ecResult); } void handleResolve(const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator); - static void ShandleResolve(pointer This, const boost::system::error_code& ecResult, boost::asio::ip::tcp::resolver::iterator endpoint_iterator) - { This->handleResolve(ecResult, endpoint_iterator); } void handleConnect(const boost::system::error_code& ecResult); - static void ShandleConnect(pointer This, const boost::system::error_code& ecResult) - { This->handleConnect(ecResult); } void handleRequest(const boost::system::error_code& ecResult); - static void ShandleRequest(pointer This, const boost::system::error_code& ecResult) - { This->handleRequest(ecResult); } - void handleWrite(const boost::system::error_code& ecResult); - static void ShandleWrite(pointer This, const boost::system::error_code& ecResult) - { This->handleWrite(ecResult); } + void handleWrite(const boost::system::error_code& ecResult, std::size_t bytes_transferred); void handleData(const boost::system::error_code& ecResult); - static void ShandleData(pointer This, const boost::system::error_code& ecResult) - { This->handleData(ecResult); } void handleShutdown(const boost::system::error_code& ecResult); From c25f480cb8ee958b9a85ff4622f6a35b0c9b8347 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 1 Feb 2013 19:02:08 -0800 Subject: [PATCH 6/7] Fixes for https client over AutoSocket. --- src/cpp/ripple/HttpsClient.cpp | 66 +++++++++++++++++++--------------- src/cpp/ripple/HttpsClient.h | 2 +- src/cpp/ripple/rpc.cpp | 2 +- 3 files changed, 39 insertions(+), 31 deletions(-) diff --git a/src/cpp/ripple/HttpsClient.cpp b/src/cpp/ripple/HttpsClient.cpp index 2713b3094..e5b195a64 100644 --- a/src/cpp/ripple/HttpsClient.cpp +++ b/src/cpp/ripple/HttpsClient.cpp @@ -13,6 +13,9 @@ #include #include "Config.h" +#include "Log.h" + +SETUP_LOG(); using namespace boost::system; using namespace boost::asio; @@ -77,14 +80,15 @@ void HttpsClient::httpsGet( void HttpsClient::httpsNext() { -std::cerr << "Fetch: " << mDeqSites[0] << std::endl; + cLog(lsTRACE) << "Fetch: " << mDeqSites[0]; + boost::shared_ptr query(new boost::asio::ip::tcp::resolver::query(mDeqSites[0], boost::lexical_cast(mPort), ip::resolver_query_base::numeric_service)); mQuery = query; mDeadline.expires_from_now(mTimeout, mShutdown); -std::cerr << "expires_from_now: " << mShutdown.message() << std::endl; + cLog(lsTRACE) << "expires_from_now: " << mShutdown.message(); if (!mShutdown) { @@ -97,7 +101,7 @@ std::cerr << "expires_from_now: " << mShutdown.message() << std::endl; if (!mShutdown) { -std::cerr << "Resolving: " << mDeqSites[0] << std::endl; + cLog(lsTRACE) << "Resolving: " << mDeqSites[0]; mResolver.async_resolve(*mQuery, boost::bind( @@ -116,20 +120,20 @@ void HttpsClient::handleDeadline(const boost::system::error_code& ecResult) if (ecResult == boost::asio::error::operation_aborted) { // Timer canceled because deadline no longer needed. -std::cerr << "Deadline cancelled." << std::endl; + cLog(lsTRACE) << "Deadline cancelled."; nothing(); // Aborter is done. } else if (ecResult) { - std::cerr << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message() << std::endl; + cLog(lsTRACE) << "Deadline error: " << mDeqSites[0] << ": " << ecResult.message(); // Can't do anything sound. abort(); } else { - std::cerr << "Deadline arrived." << std::endl; + cLog(lsTRACE) << "Deadline arrived."; // Mark us as shutting down. // XXX Use our own error code. @@ -153,7 +157,7 @@ void HttpsClient::handleShutdown( { if (ecResult) { - std::cerr << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message() << std::endl; + cLog(lsTRACE) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message(); } } @@ -167,13 +171,13 @@ void HttpsClient::handleResolve( if (mShutdown) { -std::cerr << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message() << std::endl; + cLog(lsTRACE) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message(); invokeComplete(mShutdown); } else { -std::cerr << "Resolve complete." << std::endl; + cLog(lsTRACE) << "Resolve complete."; boost::asio::async_connect( mSocket.lowest_layer(), @@ -192,17 +196,18 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult) if (mShutdown) { - std::cerr << "Connect error: " << mShutdown.message() << std::endl; + cLog(lsTRACE) << "Connect error: " << mShutdown.message(); } if (!mShutdown) { -std::cerr << "Connected." << std::endl; + cLog(lsTRACE) << "Connected."; + mShutdown = mSocket.verify(mDeqSites[0]); if (mShutdown) { - std::cerr << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message() << std::endl; + cLog(lsTRACE) << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message(); } } @@ -232,13 +237,14 @@ void HttpsClient::handleRequest(const boost::system::error_code& ecResult) if (mShutdown) { - std::cerr << "Handshake error:" << mShutdown.message() << std::endl; + cLog(lsTRACE) << "Handshake error:" << mShutdown.message(); invokeComplete(mShutdown); } else { -std::cerr << "Session started." << std::endl; + cLog(lsTRACE) << "Session started."; + mBuild(mRequest, mDeqSites[0]); mSocket.async_write( @@ -257,32 +263,32 @@ void HttpsClient::handleWrite(const boost::system::error_code& ecResult, std::si if (mShutdown) { - std::cerr << "Write error: " << mShutdown.message() << std::endl; + cLog(lsTRACE) << "Write error: " << mShutdown.message(); invokeComplete(mShutdown); } else { -std::cerr << "Wrote." << std::endl; + cLog(lsTRACE) << "Wrote."; - boost::asio::async_read( - mSocket, + mSocket.async_read( mResponse, boost::asio::transfer_all(), boost::bind(&HttpsClient::handleData, shared_from_this(), - boost::asio::placeholders::error)); + boost::asio::placeholders::error, + boost::asio::placeholders::bytes_transferred)); } } -void HttpsClient::handleData(const boost::system::error_code& ecResult) +void HttpsClient::handleData(const boost::system::error_code& ecResult, std::size_t bytes_transferred) { if (!mShutdown) mShutdown = ecResult; if (mShutdown && mShutdown != boost::asio::error::eof) { - std::cerr << "Read error: " << mShutdown.message() << std::endl; + cLog(lsTRACE) << "Read error: " << mShutdown.message(); invokeComplete(mShutdown); } @@ -290,13 +296,14 @@ void HttpsClient::handleData(const boost::system::error_code& ecResult) { if (mShutdown) { -std::cerr << "Complete." << std::endl; + cLog(lsTRACE) << "Complete."; + nothing(); } else { // XXX According to boost example code, this is what we should expect for success. - std::cerr << "Complete, no eof." << std::endl; + cLog(lsTRACE) << "Complete, no eof."; } parseData(); @@ -312,7 +319,7 @@ void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, int if (ecCancel) { - std::cerr << "Deadline cancel error: " << ecCancel.message() << std::endl; + cLog(lsTRACE) << "Deadline cancel error: " << ecCancel.message(); } mDeqSites.pop_front(); @@ -340,20 +347,21 @@ void HttpsClient::parseData() static boost::regex reStatus("\\`HTTP/1\\S+ (\\d{3}) .*\\'"); // HTTP/1.1 200 OK static boost::regex reBody("\\`(?:.*?\\r\\n\\r\\n){1}(.*)\\'"); - boost::smatch smMatch; + boost::smatch smStatus; + boost::smatch smBody; - bool bMatch = boost::regex_match(strData, smMatch, reStatus) // Match status code. - && boost::regex_match(strData, smMatch, reBody); // Match body. + bool bMatch = boost::regex_match(strData, smStatus, reStatus) // Match status code. + && boost::regex_match(strData, smBody, reBody); // Match body. // std::cerr << "Data:" << strData << std::endl; // std::cerr << "Match: " << bMatch << std::endl; - // std::cerr << "Body:" << smMatch[1] << std::endl; + // std::cerr << "Body:" << smBody[1] << std::endl; if (bMatch) { boost::system::error_code noErr; - invokeComplete(noErr, lexical_cast_st(smMatch[1]), smMatch[1]); + invokeComplete(noErr, lexical_cast_st(smStatus[1]), smBody[1]); } else { diff --git a/src/cpp/ripple/HttpsClient.h b/src/cpp/ripple/HttpsClient.h index 1080b50b6..41831a61c 100644 --- a/src/cpp/ripple/HttpsClient.h +++ b/src/cpp/ripple/HttpsClient.h @@ -50,7 +50,7 @@ private: void handleWrite(const boost::system::error_code& ecResult, std::size_t bytes_transferred); - void handleData(const boost::system::error_code& ecResult); + void handleData(const boost::system::error_code& ecResult, std::size_t bytes_transferred); void handleShutdown(const boost::system::error_code& ecResult); diff --git a/src/cpp/ripple/rpc.cpp b/src/cpp/ripple/rpc.cpp index 653daaa6c..1353260d5 100644 --- a/src/cpp/ripple/rpc.cpp +++ b/src/cpp/ripple/rpc.cpp @@ -45,7 +45,7 @@ std::string createHTTPPost(const std::string& strHost, const std::string& strPat s << "POST " << (strPath.empty() ? "/" : strPath) - << " HTTP/1.1\r\n" + << " HTTP/1.0\r\n" << "User-Agent: " SYSTEM_NAME "-json-rpc/" << FormatFullVersion() << "\r\n" << "Host: " << strHost << "\r\n" << "Content-Type: application/json\r\n" From 1b9bf68877522e6cca62c0ccb1df78b7c2910160 Mon Sep 17 00:00:00 2001 From: Arthur Britto Date: Fri, 1 Feb 2013 19:25:01 -0800 Subject: [PATCH 7/7] Have RPCSub use new callRPC. --- src/cpp/ripple/CallRPC.cpp | 41 +++++++++++++++++++--------------- src/cpp/ripple/CallRPC.h | 2 +- src/cpp/ripple/HttpsClient.cpp | 2 +- src/cpp/ripple/RPCSub.cpp | 21 ++++++++++++----- src/cpp/ripple/RPCSub.h | 1 + 5 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/cpp/ripple/CallRPC.cpp b/src/cpp/ripple/CallRPC.cpp index 16c95727a..7d8ad67e3 100644 --- a/src/cpp/ripple/CallRPC.cpp +++ b/src/cpp/ripple/CallRPC.cpp @@ -701,31 +701,36 @@ bool responseRPC( boost::function callbackFuncP, const boost::system::error_code& ecResult, int iStatus, const std::string& strData) { - // Receive reply - if (iStatus == 401) - throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); - else if ((iStatus >= 400) && (iStatus != 400) && (iStatus != 404) && (iStatus != 500)) // ? - throw std::runtime_error(strprintf("server returned HTTP error %d", iStatus)); - else if (strData.empty()) - throw std::runtime_error("no response from server"); + if (callbackFuncP) + { + // Only care about the result, if we care to deliver it callbackFuncP. - // Parse reply - cLog(lsDEBUG) << "RPC reply: " << strData << std::endl; + // Receive reply + if (iStatus == 401) + throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)"); + else if ((iStatus >= 400) && (iStatus != 400) && (iStatus != 404) && (iStatus != 500)) // ? + throw std::runtime_error(strprintf("server returned HTTP error %d", iStatus)); + else if (strData.empty()) + throw std::runtime_error("no response from server"); - Json::Reader reader; - Json::Value jvReply; + // Parse reply + cLog(lsDEBUG) << "RPC reply: " << strData << std::endl; - if (!reader.parse(strData, jvReply)) - throw std::runtime_error("couldn't parse reply from server"); + Json::Reader reader; + Json::Value jvReply; - if (jvReply.isNull()) - throw std::runtime_error("expected reply to have result, error and id properties"); + if (!reader.parse(strData, jvReply)) + throw std::runtime_error("couldn't parse reply from server"); - Json::Value jvResult(Json::objectValue); + if (jvReply.isNull()) + throw std::runtime_error("expected reply to have result, error and id properties"); - jvResult["result"] = jvReply; + Json::Value jvResult(Json::objectValue); - (callbackFuncP)(jvResult); + jvResult["result"] = jvReply; + + (callbackFuncP)(jvResult); + } return false; } diff --git a/src/cpp/ripple/CallRPC.h b/src/cpp/ripple/CallRPC.h index 939d37a28..11cf51812 100644 --- a/src/cpp/ripple/CallRPC.h +++ b/src/cpp/ripple/CallRPC.h @@ -55,7 +55,7 @@ extern void callRPC( const std::string& strUsername, const std::string& strPassword, const std::string& strPath, const std::string& strMethod, const Json::Value& jvParams, const bool bSSL, - boost::function callbackFuncP); + boost::function callbackFuncP = 0); #endif // vim:ts=4 diff --git a/src/cpp/ripple/HttpsClient.cpp b/src/cpp/ripple/HttpsClient.cpp index e5b195a64..746e65a92 100644 --- a/src/cpp/ripple/HttpsClient.cpp +++ b/src/cpp/ripple/HttpsClient.cpp @@ -331,7 +331,7 @@ void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, int // ecResult: !0 = had an error, last entry // iStatus: result, if no error // strData: data, if no error - bAgain = mComplete(ecResult ? ecResult : ecCancel, iStatus, strData); + bAgain = mComplete && mComplete(ecResult ? ecResult : ecCancel, iStatus, strData); } if (!mDeqSites.empty() && bAgain) diff --git a/src/cpp/ripple/RPCSub.cpp b/src/cpp/ripple/RPCSub.cpp index e9369d7b2..28daff00e 100644 --- a/src/cpp/ripple/RPCSub.cpp +++ b/src/cpp/ripple/RPCSub.cpp @@ -8,7 +8,7 @@ SETUP_LOG(); RPCSub::RPCSub(const std::string& strUrl, const std::string& strUsername, const std::string& strPassword) - : mUrl(strUrl), mUsername(strUsername), mPassword(strPassword) + : mUrl(strUrl), mSSL(false), mUsername(strUsername), mPassword(strPassword) { std::string strScheme; @@ -16,17 +16,22 @@ RPCSub::RPCSub(const std::string& strUrl, const std::string& strUsername, const { throw std::runtime_error("Failed to parse url."); } + else if (strScheme == "https") + { + mSSL = true; + } else if (strScheme != "http") { - throw std::runtime_error("Only http is supported."); + throw std::runtime_error("Only http and https is supported."); } mSeq = 1; if (mPort < 0) - mPort = 80; + mPort = mSSL ? 443 : 80; } +// XXX Could probably create a bunch of send jobs in a single get of the lock. void RPCSub::sendThread() { Json::Value jvEvent; @@ -59,12 +64,18 @@ void RPCSub::sendThread() // Send outside of the lock. if (bSend) { + // XXX Might not need this in a try. try { cLog(lsDEBUG) << boost::str(boost::format("callRPC calling: %s") % mIp); - // Drop result. -// (void) callRPC(theApp->getIOService(), mIp, mPort, mUsername, mPassword, mPath, "event", jvEvent); + callRPC( + theApp->getIOService(), + mIp, mPort, + mUsername, mPassword, + mPath, "event", + jvEvent, + mSSL); } catch (const std::exception& e) { diff --git a/src/cpp/ripple/RPCSub.h b/src/cpp/ripple/RPCSub.h index 8cca3e7f5..dc2270a6d 100644 --- a/src/cpp/ripple/RPCSub.h +++ b/src/cpp/ripple/RPCSub.h @@ -15,6 +15,7 @@ class RPCSub : public InfoSub std::string mUrl; std::string mIp; int mPort; + bool mSSL; std::string mUsername; std::string mPassword; std::string mPath;