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";