mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-30 16:05:51 +00:00
Merge branch 'autoclient'
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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))
|
||||
@@ -140,7 +152,6 @@ public:
|
||||
boost::asio::async_write(PlainSocket(), buffers, handler);
|
||||
}
|
||||
|
||||
|
||||
template <typename Allocator, typename Handler>
|
||||
void async_write(boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
|
||||
{
|
||||
@@ -150,7 +161,6 @@ public:
|
||||
boost::asio::async_write(PlainSocket(), buffers, handler);
|
||||
}
|
||||
|
||||
|
||||
template <typename Buf, typename Condition, typename Handler>
|
||||
void async_read(const Buf& buffers, Condition cond, Handler handler)
|
||||
{
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <cstdlib>
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/iostreams/concepts.hpp>
|
||||
#include <boost/iostreams/stream.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@@ -573,6 +575,12 @@ Json::Value RPCParser::parseCommand(std::string strMethod, Json::Value jvParams)
|
||||
return (this->*(commandsA[i].pfpFunc))(jvParams);
|
||||
}
|
||||
|
||||
// Place the async result somewhere useful.
|
||||
void callRPCHandler(Json::Value* jvOutput, const Json::Value& jvInput)
|
||||
{
|
||||
(*jvOutput) = jvInput;
|
||||
}
|
||||
|
||||
int commandLineRPC(const std::vector<std::string>& vCmd)
|
||||
{
|
||||
Json::Value jvOutput;
|
||||
@@ -615,16 +623,21 @@ int commandLineRPC(const std::vector<std::string>& vCmd)
|
||||
if (!theConfig.RPC_ADMIN_PASSWORD.empty())
|
||||
jvRequest["admin_password"] = theConfig.RPC_ADMIN_PASSWORD;
|
||||
|
||||
jvOutput = callRPC(
|
||||
theConfig.RPC_IP,
|
||||
theConfig.RPC_PORT,
|
||||
theConfig.RPC_USER,
|
||||
theConfig.RPC_PASSWORD,
|
||||
boost::asio::io_service isService;
|
||||
|
||||
callRPC(
|
||||
isService,
|
||||
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.
|
||||
jvParams, // Parsed, execute.
|
||||
false,
|
||||
boost::bind(callRPCHandler, &jvOutput, _1));
|
||||
|
||||
isService.run(); // This blocks until there is no more outstanding async calls.
|
||||
|
||||
if (jvOutput.isMember("result"))
|
||||
{
|
||||
@@ -681,7 +694,67 @@ int commandLineRPC(const std::vector<std::string>& 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)
|
||||
#define RPC_NOTIFY_MAX_BYTES 8192
|
||||
#define RPC_NOTIFY_SECONDS 10
|
||||
|
||||
bool responseRPC(
|
||||
boost::function<void(const Json::Value& jvInput)> callbackFuncP,
|
||||
const boost::system::error_code& ecResult, int iStatus, const std::string& strData)
|
||||
{
|
||||
if (callbackFuncP)
|
||||
{
|
||||
// Only care about the result, if we care to deliver it callbackFuncP.
|
||||
|
||||
// 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<std::string, std::string>& 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(
|
||||
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<void(const Json::Value& jvInput)> callbackFuncP)
|
||||
{
|
||||
// Connect to localhost
|
||||
if (!theConfig.QUIET)
|
||||
@@ -692,55 +765,31 @@ 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;
|
||||
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<std::string, std::string> 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);
|
||||
stream << strPost << std::flush;
|
||||
|
||||
// std::cerr << "post " << strPost << std::endl;
|
||||
|
||||
// Receive reply
|
||||
std::map<std::string, std::string> mapHeaders;
|
||||
std::string strReply;
|
||||
int 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,
|
||||
io_service,
|
||||
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
|
||||
|
||||
@@ -48,8 +48,14 @@ public:
|
||||
};
|
||||
|
||||
extern int commandLineRPC(const std::vector<std::string>& 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 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<void(const Json::Value& jvInput)> callbackFuncP = 0);
|
||||
#endif
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
#define __CONFIG__
|
||||
|
||||
#include <string>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ssl.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include "types.h"
|
||||
@@ -29,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;
|
||||
@@ -167,6 +169,8 @@ public:
|
||||
uint32 SIGN_VALIDATION;
|
||||
uint32 SIGN_PROPOSAL;
|
||||
|
||||
boost::asio::ssl::context SSL_CONTEXT; // Generic SSL context.
|
||||
|
||||
Config();
|
||||
|
||||
int getSize(SizedItemName);
|
||||
|
||||
@@ -12,73 +12,100 @@
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include "Config.h"
|
||||
#include "Log.h"
|
||||
|
||||
SETUP_LOG();
|
||||
|
||||
using namespace boost::system;
|
||||
using namespace boost::asio;
|
||||
|
||||
HttpsClient::HttpsClient(
|
||||
boost::asio::io_service& io_service,
|
||||
const unsigned short port,
|
||||
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),
|
||||
mDeadline(io_service)
|
||||
{
|
||||
}
|
||||
|
||||
void HttpsClient::httpsGet(
|
||||
std::deque<std::string> deqSites,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> complete) {
|
||||
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<std::string> deqSites,
|
||||
boost::function<void(boost::asio::streambuf& sb, const std::string& strHost)> build,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete)
|
||||
{
|
||||
mSSL = bSSL;
|
||||
mDeqSites = deqSites;
|
||||
mBuild = build;
|
||||
mComplete = complete;
|
||||
mTimeout = timeout;
|
||||
|
||||
httpsNext();
|
||||
}
|
||||
|
||||
void HttpsClient::httpsGet(
|
||||
bool bSSL,
|
||||
std::deque<std::string> deqSites,
|
||||
const std::string& strPath,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> 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;
|
||||
cLog(lsTRACE) << "Fetch: " << mDeqSites[0];
|
||||
|
||||
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> query(new boost::asio::ip::tcp::resolver::query(mDeqSites[0], boost::lexical_cast<std::string>(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;
|
||||
}
|
||||
cLog(lsTRACE) << "expires_from_now: " << mShutdown.message();
|
||||
|
||||
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;
|
||||
cLog(lsTRACE) << "Resolving: " << mDeqSites[0];
|
||||
|
||||
mResolver.async_resolve(*mQuery,
|
||||
boost::bind(
|
||||
&HttpsClient::ShandleResolve,
|
||||
&HttpsClient::handleResolve,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::iterator));
|
||||
@@ -93,22 +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
|
||||
{
|
||||
boost::system::error_code ec_shutdown;
|
||||
|
||||
std::cerr << "Deadline arrived." << std::endl;
|
||||
cLog(lsTRACE) << "Deadline arrived.";
|
||||
|
||||
// Mark us as shutting down.
|
||||
// XXX Use our own error code.
|
||||
@@ -118,15 +143,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)
|
||||
{
|
||||
cLog(lsTRACE) << "Shutdown error: " << mDeqSites[0] << ": " << ecResult.message();
|
||||
}
|
||||
}
|
||||
|
||||
void HttpsClient::handleResolve(
|
||||
const boost::system::error_code& ecResult,
|
||||
boost::asio::ip::tcp::resolver::iterator itrEndpoint
|
||||
@@ -137,19 +171,19 @@ 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
|
||||
else
|
||||
{
|
||||
// std::cerr << "Resolve complete." << std::endl;
|
||||
cLog(lsTRACE) << "Resolve complete.";
|
||||
|
||||
boost::asio::async_connect(
|
||||
mSocketSsl.lowest_layer(),
|
||||
mSocket.lowest_layer(),
|
||||
itrEndpoint,
|
||||
boost::bind(
|
||||
&HttpsClient::ShandleConnect,
|
||||
&HttpsClient::handleConnect,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
@@ -162,35 +196,38 @@ 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.";
|
||||
|
||||
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)
|
||||
{
|
||||
std::cerr << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message() << std::endl;
|
||||
cLog(lsTRACE) << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message();
|
||||
}
|
||||
}
|
||||
|
||||
if (!mShutdown)
|
||||
{
|
||||
mSocketSsl.async_handshake(boost::asio::ssl::stream<boost::asio::ip::tcp::socket>::client,
|
||||
boost::bind(&HttpsClient::ShandleRequest,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
if (mShutdown)
|
||||
{
|
||||
invokeComplete(mShutdown);
|
||||
}
|
||||
else if (mSSL)
|
||||
{
|
||||
mSocket.async_handshake(
|
||||
AutoSocket::ssl_socket::client,
|
||||
boost::bind(
|
||||
&HttpsClient::handleRequest,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error));
|
||||
}
|
||||
else
|
||||
{
|
||||
handleRequest(ecResult);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpsClient::handleRequest(const boost::system::error_code& ecResult)
|
||||
@@ -200,64 +237,58 @@ 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 << "SSL session started." << std::endl;
|
||||
cLog(lsTRACE) << "Session started.";
|
||||
|
||||
std::ostream osRequest(&mRequest);
|
||||
mBuild(mRequest, mDeqSites[0]);
|
||||
|
||||
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";
|
||||
|
||||
boost::asio::async_write(
|
||||
mSocketSsl,
|
||||
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;
|
||||
|
||||
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(
|
||||
mSocketSsl,
|
||||
mSocket.async_read(
|
||||
mResponse,
|
||||
boost::asio::transfer_all(),
|
||||
boost::bind(&HttpsClient::ShandleData,
|
||||
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);
|
||||
}
|
||||
@@ -265,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();
|
||||
@@ -279,7 +311,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;
|
||||
|
||||
@@ -287,16 +319,22 @@ void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, std:
|
||||
|
||||
if (ecCancel)
|
||||
{
|
||||
std::cerr << "Deadline cancel error: " << ecCancel.message() << std::endl;
|
||||
cLog(lsTRACE) << "Deadline cancel error: " << ecCancel.message();
|
||||
}
|
||||
|
||||
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 && mComplete(ecResult ? ecResult : ecCancel, iStatus, strData);
|
||||
}
|
||||
else
|
||||
|
||||
if (!mDeqSites.empty() && bAgain)
|
||||
{
|
||||
httpsNext();
|
||||
}
|
||||
@@ -309,21 +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.
|
||||
&& !smMatch[1].compare("200")
|
||||
&& 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, smMatch[1]);
|
||||
invokeComplete(noErr, lexical_cast_st<int>(smStatus[1]), smBody[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -333,33 +371,52 @@ void HttpsClient::parseData()
|
||||
}
|
||||
|
||||
void HttpsClient::httpsGet(
|
||||
bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
std::deque<std::string> deqSites,
|
||||
const unsigned short port,
|
||||
const std::string& strPath,
|
||||
std::size_t responseMax,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> complete) {
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete) {
|
||||
|
||||
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, strPath, responseMax));
|
||||
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, responseMax));
|
||||
|
||||
client->httpsGet(deqSites, timeout, complete);
|
||||
client->httpsGet(bSSL, deqSites, strPath, timeout, complete);
|
||||
}
|
||||
|
||||
void HttpsClient::httpsGet(
|
||||
bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
std::string strSite,
|
||||
const unsigned short port,
|
||||
const std::string& strPath,
|
||||
std::size_t responseMax,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> complete) {
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete) {
|
||||
|
||||
std::deque<std::string> deqSites(1, strSite);
|
||||
|
||||
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, strPath, responseMax));
|
||||
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, responseMax));
|
||||
|
||||
client->httpsGet(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<void(boost::asio::streambuf& sb, const std::string& strHost)> setRequest,
|
||||
std::size_t responseMax,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete) {
|
||||
|
||||
std::deque<std::string> deqSites(1, strSite);
|
||||
|
||||
boost::shared_ptr<HttpsClient> client(new HttpsClient(io_service, port, responseMax));
|
||||
|
||||
client->httpsRequest(bSSL, deqSites, setRequest, timeout, complete);
|
||||
}
|
||||
|
||||
// vim:ts=4
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include "AutoSocket.h"
|
||||
|
||||
//
|
||||
// Async https client.
|
||||
@@ -21,15 +22,15 @@ class HttpsClient : public boost::enable_shared_from_this<HttpsClient>
|
||||
private:
|
||||
typedef boost::shared_ptr<HttpsClient> pointer;
|
||||
|
||||
boost::asio::ssl::context mCtx;
|
||||
bool mSSL;
|
||||
AutoSocket mSocket;
|
||||
boost::asio::ip::tcp::resolver mResolver;
|
||||
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> mQuery;
|
||||
boost::asio::ssl::stream<boost::asio::ip::tcp::socket> mSocketSsl;
|
||||
boost::asio::streambuf mRequest;
|
||||
boost::asio::streambuf mResponse;
|
||||
const std::string mStrPath;
|
||||
const unsigned short mPort;
|
||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> mComplete;
|
||||
boost::function<void(boost::asio::streambuf& sb, const std::string& strHost)> mBuild;
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> mComplete;
|
||||
|
||||
boost::asio::deadline_timer mDeadline;
|
||||
|
||||
@@ -40,65 +41,76 @@ 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 handleData(const boost::system::error_code& ecResult, std::size_t bytes_transferred);
|
||||
|
||||
void handleShutdown(const boost::system::error_code& ecResult);
|
||||
|
||||
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 httpsGet(
|
||||
void httpsRequest(
|
||||
bool bSSL,
|
||||
std::deque<std::string> deqSites,
|
||||
boost::function<void(boost::asio::streambuf& sb, const std::string& strHost)> build,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> complete);
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||
|
||||
void httpsGet(
|
||||
bool bSSL,
|
||||
std::deque<std::string> deqSites,
|
||||
const std::string& strPath,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||
|
||||
static void httpsGet(
|
||||
bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
std::deque<std::string> deqSites,
|
||||
const unsigned short port,
|
||||
const std::string& strPath,
|
||||
std::size_t responseMax,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> complete);
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||
|
||||
static void httpsGet(
|
||||
bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
std::string strSite,
|
||||
const unsigned short port,
|
||||
const std::string& strPath,
|
||||
std::size_t responseMax,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> complete);
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||
|
||||
static void httpsRequest(
|
||||
bool bSSL,
|
||||
boost::asio::io_service& io_service,
|
||||
std::string strSite,
|
||||
const unsigned short port,
|
||||
boost::function<void(boost::asio::streambuf& sb, const std::string& strHost)> build,
|
||||
std::size_t responseMax,
|
||||
boost::posix_time::time_duration timeout,
|
||||
boost::function<bool(const boost::system::error_code& ecResult, int iStatus, const std::string& strData)> complete);
|
||||
};
|
||||
#endif
|
||||
// vim:ts=4
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<std::string, std::string>& mapRequestHeaders);
|
||||
|
||||
extern int ReadHTTP(std::basic_istream<char>& stream,
|
||||
|
||||
@@ -2304,11 +2304,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;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "Application.h"
|
||||
#include "RPCSub.h"
|
||||
|
||||
#include "CallRPC.h"
|
||||
@@ -7,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;
|
||||
|
||||
@@ -15,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;
|
||||
@@ -58,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(mIp, mPort, mUsername, mPassword, mPath, "event", jvEvent);
|
||||
callRPC(
|
||||
theApp->getIOService(),
|
||||
mIp, mPort,
|
||||
mUsername, mPassword,
|
||||
mPath, "event",
|
||||
jvEvent,
|
||||
mSSL);
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -791,16 +791,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].
|
||||
@@ -820,13 +827,14 @@ void UniqueNodeList::getIpsUrl(const RippleAddress& naNodePublic, section secSit
|
||||
&& strScheme == "https")
|
||||
{
|
||||
HttpsClient::httpsGet(
|
||||
true,
|
||||
theApp->getIOService(),
|
||||
strDomain,
|
||||
443,
|
||||
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
|
||||
{
|
||||
@@ -835,16 +843,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].
|
||||
@@ -863,13 +878,14 @@ void UniqueNodeList::getValidatorsUrl(const RippleAddress& naNodePublic, section
|
||||
&& strScheme == "https")
|
||||
{
|
||||
HttpsClient::httpsGet(
|
||||
true,
|
||||
theApp->getIOService(),
|
||||
strDomain,
|
||||
443,
|
||||
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
|
||||
{
|
||||
@@ -905,118 +921,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.
|
||||
@@ -1033,13 +1056,14 @@ void UniqueNodeList::fetchProcess(std::string strDomain)
|
||||
deqSites.push_back(strDomain);
|
||||
|
||||
HttpsClient::httpsGet(
|
||||
true,
|
||||
theApp->getIOService(),
|
||||
deqSites,
|
||||
443,
|
||||
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)
|
||||
@@ -1549,18 +1573,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()
|
||||
@@ -1568,13 +1599,14 @@ void UniqueNodeList::nodeNetwork()
|
||||
if (!theConfig.VALIDATORS_SITE.empty())
|
||||
{
|
||||
HttpsClient::httpsGet(
|
||||
true,
|
||||
theApp->getIOService(),
|
||||
theConfig.VALIDATORS_SITE,
|
||||
443,
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ private:
|
||||
|
||||
bool scoreRound(std::vector<scoreNode>& 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:
|
||||
|
||||
@@ -39,15 +39,15 @@ 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<std::string, std::string>& mapRequestHeaders)
|
||||
std::string createHTTPPost(const std::string& strHost, const std::string& strPath, const std::string& strMsg, const std::map<std::string, std::string>& mapRequestHeaders)
|
||||
{
|
||||
std::ostringstream s;
|
||||
|
||||
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: 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";
|
||||
|
||||
Reference in New Issue
Block a user