mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Merge branch 'autoclient'
This commit is contained in:
@@ -1056,7 +1056,6 @@ STAmount STAmount::setRate(uint64 rate)
|
|||||||
// <-- saTakerGot: Actual
|
// <-- saTakerGot: Actual
|
||||||
// <-- saTakerIssuerFee: Actual
|
// <-- saTakerIssuerFee: Actual
|
||||||
// <-- saOfferIssuerFee: Actual
|
// <-- saOfferIssuerFee: Actual
|
||||||
// <-- bRemove: remove offer it is either fullfilled or unfunded
|
|
||||||
bool STAmount::applyOffer(
|
bool STAmount::applyOffer(
|
||||||
const uint32 uTakerPaysRate, const uint32 uOfferPaysRate,
|
const uint32 uTakerPaysRate, const uint32 uOfferPaysRate,
|
||||||
const STAmount& saOfferRate,
|
const STAmount& saOfferRate,
|
||||||
|
|||||||
@@ -67,6 +67,18 @@ public:
|
|||||||
std::swap(mSecure, s.mSecure);
|
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)
|
void async_handshake(handshake_type type, callback cbFunc)
|
||||||
{
|
{
|
||||||
if ((type == ssl_socket::client) || (mSecure))
|
if ((type == ssl_socket::client) || (mSecure))
|
||||||
@@ -140,7 +152,6 @@ public:
|
|||||||
boost::asio::async_write(PlainSocket(), buffers, handler);
|
boost::asio::async_write(PlainSocket(), buffers, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename Allocator, typename Handler>
|
template <typename Allocator, typename Handler>
|
||||||
void async_write(boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
|
void async_write(boost::asio::basic_streambuf<Allocator>& buffers, Handler handler)
|
||||||
{
|
{
|
||||||
@@ -150,7 +161,6 @@ public:
|
|||||||
boost::asio::async_write(PlainSocket(), buffers, handler);
|
boost::asio::async_write(PlainSocket(), buffers, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename Buf, typename Condition, typename Handler>
|
template <typename Buf, typename Condition, typename Handler>
|
||||||
void async_read(const Buf& buffers, Condition cond, Handler handler)
|
void async_read(const Buf& buffers, Condition cond, Handler handler)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
|
#include <boost/bind.hpp>
|
||||||
#include <boost/iostreams/concepts.hpp>
|
#include <boost/iostreams/concepts.hpp>
|
||||||
#include <boost/iostreams/stream.hpp>
|
#include <boost/iostreams/stream.hpp>
|
||||||
#include <boost/algorithm/string.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);
|
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)
|
int commandLineRPC(const std::vector<std::string>& vCmd)
|
||||||
{
|
{
|
||||||
Json::Value jvOutput;
|
Json::Value jvOutput;
|
||||||
@@ -615,16 +623,21 @@ int commandLineRPC(const std::vector<std::string>& vCmd)
|
|||||||
if (!theConfig.RPC_ADMIN_PASSWORD.empty())
|
if (!theConfig.RPC_ADMIN_PASSWORD.empty())
|
||||||
jvRequest["admin_password"] = theConfig.RPC_ADMIN_PASSWORD;
|
jvRequest["admin_password"] = theConfig.RPC_ADMIN_PASSWORD;
|
||||||
|
|
||||||
jvOutput = callRPC(
|
boost::asio::io_service isService;
|
||||||
theConfig.RPC_IP,
|
|
||||||
theConfig.RPC_PORT,
|
callRPC(
|
||||||
theConfig.RPC_USER,
|
isService,
|
||||||
theConfig.RPC_PASSWORD,
|
theConfig.RPC_IP, theConfig.RPC_PORT,
|
||||||
|
theConfig.RPC_USER, theConfig.RPC_PASSWORD,
|
||||||
"",
|
"",
|
||||||
jvRequest.isMember("method") // Allow parser to rewrite method.
|
jvRequest.isMember("method") // Allow parser to rewrite method.
|
||||||
? jvRequest["method"].asString()
|
? jvRequest["method"].asString()
|
||||||
: vCmd[0],
|
: 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"))
|
if (jvOutput.isMember("result"))
|
||||||
{
|
{
|
||||||
@@ -681,7 +694,67 @@ int commandLineRPC(const std::vector<std::string>& vCmd)
|
|||||||
return nRet;
|
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
|
// Connect to localhost
|
||||||
if (!theConfig.QUIET)
|
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;
|
// 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
|
// HTTP basic authentication
|
||||||
std::string strUserPass64 = EncodeBase64(strUsername + ":" + strPassword);
|
std::string strUserPass64 = EncodeBase64(strUsername + ":" + strPassword);
|
||||||
|
|
||||||
std::map<std::string, std::string> mapRequestHeaders;
|
std::map<std::string, std::string> mapRequestHeaders;
|
||||||
|
|
||||||
mapRequestHeaders["Authorization"] = std::string("Basic ") + strUserPass64;
|
mapRequestHeaders["Authorization"] = std::string("Basic ") + strUserPass64;
|
||||||
|
|
||||||
// Log(lsDEBUG) << "requesting" << std::endl;
|
|
||||||
|
|
||||||
// Send request
|
// Send request
|
||||||
std::string strRequest = JSONRPCRequest(strMethod, jvParams, Json::Value(1));
|
// Log(lsDEBUG) << "requesting" << std::endl;
|
||||||
// cLog(lsDEBUG) << "send request " << strMethod << " : " << strRequest << std::endl;
|
// cLog(lsDEBUG) << "send request " << strMethod << " : " << strRequest << std::endl;
|
||||||
|
|
||||||
std::string strPost = createHTTPPost(strPath, strRequest, mapRequestHeaders);
|
HttpsClient::httpsRequest(
|
||||||
stream << strPost << std::flush;
|
bSSL,
|
||||||
|
io_service,
|
||||||
// std::cerr << "post " << strPost << std::endl;
|
strIp,
|
||||||
|
iPort,
|
||||||
// Receive reply
|
boost::bind(
|
||||||
std::map<std::string, std::string> mapHeaders;
|
&requestRPC,
|
||||||
std::string strReply;
|
strMethod,
|
||||||
int nStatus = ReadHTTP(stream, mapHeaders, strReply);
|
jvParams,
|
||||||
if (nStatus == 401)
|
mapRequestHeaders,
|
||||||
throw std::runtime_error("incorrect rpcuser or rpcpassword (authorization failed)");
|
"/", _1, _2),
|
||||||
else if ((nStatus >= 400) && (nStatus != 400) && (nStatus != 404) && (nStatus != 500)) // ?
|
RPC_NOTIFY_MAX_BYTES,
|
||||||
throw std::runtime_error(strprintf("server returned HTTP error %d", nStatus));
|
boost::posix_time::seconds(RPC_NOTIFY_SECONDS),
|
||||||
else if (strReply.empty())
|
boost::bind(&responseRPC, callbackFuncP, _1, _2, _3));
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim:ts=4
|
// vim:ts=4
|
||||||
|
|||||||
@@ -48,8 +48,14 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern int commandLineRPC(const std::vector<std::string>& vCmd);
|
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
|
#endif
|
||||||
|
|
||||||
// vim:ts=4
|
// vim:ts=4
|
||||||
|
|||||||
@@ -134,26 +134,31 @@ void Config::setup(const std::string& strConf, bool bTestNet, bool bQuiet)
|
|||||||
if (strXdgConfigHome.empty())
|
if (strXdgConfigHome.empty())
|
||||||
{
|
{
|
||||||
// $XDG_CONFIG_HOME was not set, use default based on $HOME.
|
// $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())
|
if (strXdgDataHome.empty())
|
||||||
{
|
{
|
||||||
// $XDG_DATA_HOME was not set, use default based on $HOME.
|
// $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;
|
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);
|
boost::filesystem::create_directories(CONFIG_DIR, ec);
|
||||||
|
|
||||||
if (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
|
// Update default values
|
||||||
load();
|
load();
|
||||||
|
|
||||||
@@ -164,10 +169,11 @@ void Config::setup(const std::string& strConf, bool bTestNet, bool bQuiet)
|
|||||||
boost::filesystem::create_directories(DATA_DIR, ec);
|
boost::filesystem::create_directories(DATA_DIR, ec);
|
||||||
|
|
||||||
if (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()
|
Config::Config()
|
||||||
|
: SSL_CONTEXT(boost::asio::ssl::context::sslv23)
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Defaults
|
// Defaults
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
#define __CONFIG__
|
#define __CONFIG__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/asio/ssl.hpp>
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@@ -29,7 +31,7 @@
|
|||||||
#define VALIDATORS_FILE_NAME "validators.txt"
|
#define VALIDATORS_FILE_NAME "validators.txt"
|
||||||
|
|
||||||
const int DOMAIN_BYTES_MAX = 256;
|
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_PEER_PORT = 6561;
|
||||||
const int SYSTEM_WEBSOCKET_PORT = 6562;
|
const int SYSTEM_WEBSOCKET_PORT = 6562;
|
||||||
@@ -167,6 +169,8 @@ public:
|
|||||||
uint32 SIGN_VALIDATION;
|
uint32 SIGN_VALIDATION;
|
||||||
uint32 SIGN_PROPOSAL;
|
uint32 SIGN_PROPOSAL;
|
||||||
|
|
||||||
|
boost::asio::ssl::context SSL_CONTEXT; // Generic SSL context.
|
||||||
|
|
||||||
Config();
|
Config();
|
||||||
|
|
||||||
int getSize(SizedItemName);
|
int getSize(SizedItemName);
|
||||||
|
|||||||
@@ -12,73 +12,100 @@
|
|||||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||||
#include <boost/system/error_code.hpp>
|
#include <boost/system/error_code.hpp>
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Log.h"
|
||||||
|
|
||||||
|
SETUP_LOG();
|
||||||
|
|
||||||
using namespace boost::system;
|
using namespace boost::system;
|
||||||
using namespace boost::asio;
|
using namespace boost::asio;
|
||||||
|
|
||||||
HttpsClient::HttpsClient(
|
HttpsClient::HttpsClient(
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
const unsigned short port,
|
const unsigned short port,
|
||||||
const std::string& strPath,
|
|
||||||
std::size_t responseMax
|
std::size_t responseMax
|
||||||
) :
|
) :
|
||||||
mCtx(boost::asio::ssl::context::sslv23),
|
mSocket(io_service, theConfig.SSL_CONTEXT),
|
||||||
mResolver(io_service),
|
mResolver(io_service),
|
||||||
mSocketSsl(io_service, mCtx),
|
|
||||||
mResponse(responseMax),
|
mResponse(responseMax),
|
||||||
mStrPath(strPath),
|
|
||||||
mPort(port),
|
mPort(port),
|
||||||
mDeadline(io_service)
|
mDeadline(io_service)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpsClient::httpsGet(
|
void HttpsClient::makeGet(const std::string& strPath, boost::asio::streambuf& sb, const std::string& strHost)
|
||||||
std::deque<std::string> deqSites,
|
{
|
||||||
boost::posix_time::time_duration timeout,
|
std::ostream osRequest(&sb);
|
||||||
boost::function<void(const boost::system::error_code& ecResult, std::string& strData)> complete) {
|
|
||||||
|
|
||||||
|
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;
|
mDeqSites = deqSites;
|
||||||
|
mBuild = build;
|
||||||
mComplete = complete;
|
mComplete = complete;
|
||||||
mTimeout = timeout;
|
mTimeout = timeout;
|
||||||
|
|
||||||
httpsNext();
|
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()
|
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),
|
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;
|
mQuery = query;
|
||||||
|
|
||||||
mCtx.set_default_verify_paths(mShutdown);
|
mDeadline.expires_from_now(mTimeout, mShutdown);
|
||||||
if (mShutdown)
|
|
||||||
{
|
|
||||||
std::cerr << "set_default_verify_paths: " << mShutdown.message() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mShutdown)
|
cLog(lsTRACE) << "expires_from_now: " << mShutdown.message();
|
||||||
{
|
|
||||||
mDeadline.expires_from_now(mTimeout, mShutdown);
|
|
||||||
|
|
||||||
// std::cerr << "expires_from_now: " << mShutdown.message() << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!mShutdown)
|
if (!mShutdown)
|
||||||
{
|
{
|
||||||
mDeadline.async_wait(
|
mDeadline.async_wait(
|
||||||
boost::bind(
|
boost::bind(
|
||||||
&HttpsClient::ShandleDeadline,
|
&HttpsClient::handleDeadline,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
boost::asio::placeholders::error));
|
boost::asio::placeholders::error));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mShutdown)
|
if (!mShutdown)
|
||||||
{
|
{
|
||||||
// std::cerr << "Resolving: " << mDeqSites[0] << std::endl;
|
cLog(lsTRACE) << "Resolving: " << mDeqSites[0];
|
||||||
|
|
||||||
mResolver.async_resolve(*mQuery,
|
mResolver.async_resolve(*mQuery,
|
||||||
boost::bind(
|
boost::bind(
|
||||||
&HttpsClient::ShandleResolve,
|
&HttpsClient::handleResolve,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
boost::asio::placeholders::error,
|
boost::asio::placeholders::error,
|
||||||
boost::asio::placeholders::iterator));
|
boost::asio::placeholders::iterator));
|
||||||
@@ -93,22 +120,20 @@ void HttpsClient::handleDeadline(const boost::system::error_code& ecResult)
|
|||||||
if (ecResult == boost::asio::error::operation_aborted)
|
if (ecResult == boost::asio::error::operation_aborted)
|
||||||
{
|
{
|
||||||
// Timer canceled because deadline no longer needed.
|
// Timer canceled because deadline no longer needed.
|
||||||
// std::cerr << "Deadline cancelled." << std::endl;
|
cLog(lsTRACE) << "Deadline cancelled.";
|
||||||
|
|
||||||
nothing(); // Aborter is done.
|
nothing(); // Aborter is done.
|
||||||
}
|
}
|
||||||
else if (ecResult)
|
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.
|
// Can't do anything sound.
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
boost::system::error_code ec_shutdown;
|
cLog(lsTRACE) << "Deadline arrived.";
|
||||||
|
|
||||||
std::cerr << "Deadline arrived." << std::endl;
|
|
||||||
|
|
||||||
// Mark us as shutting down.
|
// Mark us as shutting down.
|
||||||
// XXX Use our own error code.
|
// XXX Use our own error code.
|
||||||
@@ -118,15 +143,24 @@ void HttpsClient::handleDeadline(const boost::system::error_code& ecResult)
|
|||||||
mResolver.cancel();
|
mResolver.cancel();
|
||||||
|
|
||||||
// Stop the transaction.
|
// 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(
|
void HttpsClient::handleResolve(
|
||||||
const boost::system::error_code& ecResult,
|
const boost::system::error_code& ecResult,
|
||||||
boost::asio::ip::tcp::resolver::iterator itrEndpoint
|
boost::asio::ip::tcp::resolver::iterator itrEndpoint
|
||||||
@@ -137,19 +171,19 @@ void HttpsClient::handleResolve(
|
|||||||
|
|
||||||
if (mShutdown)
|
if (mShutdown)
|
||||||
{
|
{
|
||||||
// std::cerr << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message() << std::endl;
|
cLog(lsTRACE) << "Resolve error: " << mDeqSites[0] << ": " << mShutdown.message();
|
||||||
|
|
||||||
invokeComplete(mShutdown);
|
invokeComplete(mShutdown);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// std::cerr << "Resolve complete." << std::endl;
|
cLog(lsTRACE) << "Resolve complete.";
|
||||||
|
|
||||||
boost::asio::async_connect(
|
boost::asio::async_connect(
|
||||||
mSocketSsl.lowest_layer(),
|
mSocket.lowest_layer(),
|
||||||
itrEndpoint,
|
itrEndpoint,
|
||||||
boost::bind(
|
boost::bind(
|
||||||
&HttpsClient::ShandleConnect,
|
&HttpsClient::handleConnect,
|
||||||
shared_from_this(),
|
shared_from_this(),
|
||||||
boost::asio::placeholders::error));
|
boost::asio::placeholders::error));
|
||||||
}
|
}
|
||||||
@@ -162,35 +196,38 @@ void HttpsClient::handleConnect(const boost::system::error_code& ecResult)
|
|||||||
|
|
||||||
if (mShutdown)
|
if (mShutdown)
|
||||||
{
|
{
|
||||||
std::cerr << "Connect error: " << mShutdown.message() << std::endl;
|
cLog(lsTRACE) << "Connect error: " << mShutdown.message();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mShutdown)
|
if (!mShutdown)
|
||||||
{
|
{
|
||||||
// std::cerr << "Connected." << std::endl;
|
cLog(lsTRACE) << "Connected.";
|
||||||
|
|
||||||
mSocketSsl.set_verify_mode(boost::asio::ssl::verify_peer);
|
mShutdown = mSocket.verify(mDeqSites[0]);
|
||||||
|
|
||||||
// XXX Verify semantics of RFC 2818 are what we want.
|
|
||||||
mSocketSsl.set_verify_callback(boost::asio::ssl::rfc2818_verification(mDeqSites[0]), mShutdown);
|
|
||||||
|
|
||||||
if (mShutdown)
|
if (mShutdown)
|
||||||
{
|
{
|
||||||
std::cerr << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message() << std::endl;
|
cLog(lsTRACE) << "set_verify_callback: " << mDeqSites[0] << ": " << mShutdown.message();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mShutdown)
|
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
|
|
||||||
{
|
{
|
||||||
invokeComplete(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)
|
void HttpsClient::handleRequest(const boost::system::error_code& ecResult)
|
||||||
@@ -200,64 +237,58 @@ void HttpsClient::handleRequest(const boost::system::error_code& ecResult)
|
|||||||
|
|
||||||
if (mShutdown)
|
if (mShutdown)
|
||||||
{
|
{
|
||||||
std::cerr << "Handshake error:" << mShutdown.message() << std::endl;
|
cLog(lsTRACE) << "Handshake error:" << mShutdown.message();
|
||||||
|
|
||||||
invokeComplete(mShutdown);
|
invokeComplete(mShutdown);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// std::cerr << "SSL session started." << std::endl;
|
cLog(lsTRACE) << "Session started.";
|
||||||
|
|
||||||
std::ostream osRequest(&mRequest);
|
mBuild(mRequest, mDeqSites[0]);
|
||||||
|
|
||||||
osRequest <<
|
mSocket.async_write(
|
||||||
"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,
|
|
||||||
mRequest,
|
mRequest,
|
||||||
boost::bind(&HttpsClient::ShandleWrite,
|
boost::bind(&HttpsClient::handleWrite,
|
||||||
shared_from_this(),
|
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)
|
if (!mShutdown)
|
||||||
mShutdown = ecResult;
|
mShutdown = ecResult;
|
||||||
|
|
||||||
if (mShutdown)
|
if (mShutdown)
|
||||||
{
|
{
|
||||||
std::cerr << "Write error: " << mShutdown.message() << std::endl;
|
cLog(lsTRACE) << "Write error: " << mShutdown.message();
|
||||||
|
|
||||||
invokeComplete(mShutdown);
|
invokeComplete(mShutdown);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// std::cerr << "Wrote." << std::endl;
|
cLog(lsTRACE) << "Wrote.";
|
||||||
|
|
||||||
boost::asio::async_read(
|
mSocket.async_read(
|
||||||
mSocketSsl,
|
|
||||||
mResponse,
|
mResponse,
|
||||||
boost::asio::transfer_all(),
|
boost::asio::transfer_all(),
|
||||||
boost::bind(&HttpsClient::ShandleData,
|
boost::bind(&HttpsClient::handleData,
|
||||||
shared_from_this(),
|
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)
|
if (!mShutdown)
|
||||||
mShutdown = ecResult;
|
mShutdown = ecResult;
|
||||||
|
|
||||||
if (mShutdown && mShutdown != boost::asio::error::eof)
|
if (mShutdown && mShutdown != boost::asio::error::eof)
|
||||||
{
|
{
|
||||||
std::cerr << "Read error: " << mShutdown.message() << std::endl;
|
cLog(lsTRACE) << "Read error: " << mShutdown.message();
|
||||||
|
|
||||||
invokeComplete(mShutdown);
|
invokeComplete(mShutdown);
|
||||||
}
|
}
|
||||||
@@ -265,13 +296,14 @@ void HttpsClient::handleData(const boost::system::error_code& ecResult)
|
|||||||
{
|
{
|
||||||
if (mShutdown)
|
if (mShutdown)
|
||||||
{
|
{
|
||||||
// std::cerr << "Complete." << std::endl;
|
cLog(lsTRACE) << "Complete.";
|
||||||
|
|
||||||
nothing();
|
nothing();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// XXX According to boost example code, this is what we should expect for success.
|
// 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();
|
parseData();
|
||||||
@@ -279,7 +311,7 @@ void HttpsClient::handleData(const boost::system::error_code& ecResult)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Call cancel the deadline timer and invoke the completion routine.
|
// 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;
|
boost::system::error_code ecCancel;
|
||||||
|
|
||||||
@@ -287,16 +319,22 @@ void HttpsClient::invokeComplete(const boost::system::error_code& ecResult, std:
|
|||||||
|
|
||||||
if (ecCancel)
|
if (ecCancel)
|
||||||
{
|
{
|
||||||
std::cerr << "Deadline cancel error: " << ecCancel.message() << std::endl;
|
cLog(lsTRACE) << "Deadline cancel error: " << ecCancel.message();
|
||||||
}
|
}
|
||||||
|
|
||||||
mDeqSites.pop_front();
|
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();
|
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 reStatus("\\`HTTP/1\\S+ (\\d{3}) .*\\'"); // HTTP/1.1 200 OK
|
||||||
static boost::regex reBody("\\`(?:.*?\\r\\n\\r\\n){1}(.*)\\'");
|
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.
|
bool bMatch = boost::regex_match(strData, smStatus, reStatus) // Match status code.
|
||||||
&& !smMatch[1].compare("200")
|
&& boost::regex_match(strData, smBody, reBody); // Match body.
|
||||||
&& boost::regex_match(strData, smMatch, reBody); // Match body.
|
|
||||||
|
|
||||||
// std::cerr << "Data:" << strData << std::endl;
|
// std::cerr << "Data:" << strData << std::endl;
|
||||||
// std::cerr << "Match: " << bMatch << std::endl;
|
// std::cerr << "Match: " << bMatch << std::endl;
|
||||||
// std::cerr << "Body:" << smMatch[1] << std::endl;
|
// std::cerr << "Body:" << smBody[1] << std::endl;
|
||||||
|
|
||||||
if (bMatch)
|
if (bMatch)
|
||||||
{
|
{
|
||||||
boost::system::error_code noErr;
|
boost::system::error_code noErr;
|
||||||
|
|
||||||
invokeComplete(noErr, smMatch[1]);
|
invokeComplete(noErr, lexical_cast_st<int>(smStatus[1]), smBody[1]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -333,33 +371,52 @@ void HttpsClient::parseData()
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HttpsClient::httpsGet(
|
void HttpsClient::httpsGet(
|
||||||
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::deque<std::string> deqSites,
|
std::deque<std::string> deqSites,
|
||||||
const unsigned short port,
|
const unsigned short port,
|
||||||
const std::string& strPath,
|
const std::string& strPath,
|
||||||
std::size_t responseMax,
|
std::size_t responseMax,
|
||||||
boost::posix_time::time_duration timeout,
|
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(
|
void HttpsClient::httpsGet(
|
||||||
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::string strSite,
|
std::string strSite,
|
||||||
const unsigned short port,
|
const unsigned short port,
|
||||||
const std::string& strPath,
|
const std::string& strPath,
|
||||||
std::size_t responseMax,
|
std::size_t responseMax,
|
||||||
boost::posix_time::time_duration timeout,
|
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);
|
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
|
// vim:ts=4
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <boost/function.hpp>
|
#include <boost/function.hpp>
|
||||||
#include <boost/shared_ptr.hpp>
|
#include <boost/shared_ptr.hpp>
|
||||||
|
|
||||||
|
#include "AutoSocket.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// Async https client.
|
// Async https client.
|
||||||
@@ -21,15 +22,15 @@ class HttpsClient : public boost::enable_shared_from_this<HttpsClient>
|
|||||||
private:
|
private:
|
||||||
typedef boost::shared_ptr<HttpsClient> pointer;
|
typedef boost::shared_ptr<HttpsClient> pointer;
|
||||||
|
|
||||||
boost::asio::ssl::context mCtx;
|
bool mSSL;
|
||||||
|
AutoSocket mSocket;
|
||||||
boost::asio::ip::tcp::resolver mResolver;
|
boost::asio::ip::tcp::resolver mResolver;
|
||||||
boost::shared_ptr<boost::asio::ip::tcp::resolver::query> mQuery;
|
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 mRequest;
|
||||||
boost::asio::streambuf mResponse;
|
boost::asio::streambuf mResponse;
|
||||||
const std::string mStrPath;
|
|
||||||
const unsigned short mPort;
|
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;
|
boost::asio::deadline_timer mDeadline;
|
||||||
|
|
||||||
@@ -40,65 +41,76 @@ private:
|
|||||||
boost::posix_time::time_duration mTimeout;
|
boost::posix_time::time_duration mTimeout;
|
||||||
|
|
||||||
void handleDeadline(const boost::system::error_code& ecResult);
|
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);
|
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);
|
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);
|
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);
|
void handleWrite(const boost::system::error_code& ecResult, std::size_t bytes_transferred);
|
||||||
static void ShandleWrite(pointer This, const boost::system::error_code& ecResult)
|
|
||||||
{ This->handleWrite(ecResult); }
|
|
||||||
|
|
||||||
void handleData(const boost::system::error_code& ecResult);
|
void handleData(const boost::system::error_code& ecResult, std::size_t bytes_transferred);
|
||||||
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 parseData();
|
||||||
void httpsNext();
|
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:
|
public:
|
||||||
|
|
||||||
HttpsClient(
|
HttpsClient(
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
const unsigned short port,
|
const unsigned short port,
|
||||||
const std::string& strPath,
|
|
||||||
std::size_t responseMax
|
std::size_t responseMax
|
||||||
);
|
);
|
||||||
|
|
||||||
void httpsGet(
|
void httpsRequest(
|
||||||
|
bool bSSL,
|
||||||
std::deque<std::string> deqSites,
|
std::deque<std::string> deqSites,
|
||||||
|
boost::function<void(boost::asio::streambuf& sb, const std::string& strHost)> build,
|
||||||
boost::posix_time::time_duration timeout,
|
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(
|
static void httpsGet(
|
||||||
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::deque<std::string> deqSites,
|
std::deque<std::string> deqSites,
|
||||||
const unsigned short port,
|
const unsigned short port,
|
||||||
const std::string& strPath,
|
const std::string& strPath,
|
||||||
std::size_t responseMax,
|
std::size_t responseMax,
|
||||||
boost::posix_time::time_duration timeout,
|
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(
|
static void httpsGet(
|
||||||
|
bool bSSL,
|
||||||
boost::asio::io_service& io_service,
|
boost::asio::io_service& io_service,
|
||||||
std::string strSite,
|
std::string strSite,
|
||||||
const unsigned short port,
|
const unsigned short port,
|
||||||
const std::string& strPath,
|
const std::string& strPath,
|
||||||
std::size_t responseMax,
|
std::size_t responseMax,
|
||||||
boost::posix_time::time_duration timeout,
|
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
|
#endif
|
||||||
// vim:ts=4
|
// vim:ts=4
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ TER OfferCreateTransactor::takeOffers(
|
|||||||
STAmount saTakerFunds = mEngine->getNodes().accountFunds(uTakerAccountID, saTakerPays);
|
STAmount saTakerFunds = mEngine->getNodes().accountFunds(uTakerAccountID, saTakerPays);
|
||||||
SLE::pointer sleOfferAccount; // Owner of offer.
|
SLE::pointer sleOfferAccount; // Owner of offer.
|
||||||
|
|
||||||
if (!saOfferFunds.isPositive())
|
if (!saOfferFunds.isPositive()) // Includes zero.
|
||||||
{
|
{
|
||||||
// Offer is unfunded, possibly due to previous balance action.
|
// Offer is unfunded, possibly due to previous balance action.
|
||||||
cLog(lsINFO) << "takeOffers: offer unfunded: delete";
|
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,
|
extern std::string JSONRPCRequest(const std::string& strMethod, const Json::Value& params,
|
||||||
const Json::Value& id);
|
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);
|
const std::map<std::string, std::string>& mapRequestHeaders);
|
||||||
|
|
||||||
extern int ReadHTTP(std::basic_istream<char>& stream,
|
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());
|
jvResult["ledger_data"] = strHex(s.peekData());
|
||||||
|
|
||||||
if (mRole == ADMIN)
|
// This information isn't verified, they should only use it if they trust us.
|
||||||
{
|
lpLedger->addJson(jvResult, 0);
|
||||||
// As admin, they can trust us, so we provide this information.
|
|
||||||
lpLedger->addJson(jvResult, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return jvResult;
|
return jvResult;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
|
||||||
|
#include "Application.h"
|
||||||
#include "RPCSub.h"
|
#include "RPCSub.h"
|
||||||
|
|
||||||
#include "CallRPC.h"
|
#include "CallRPC.h"
|
||||||
@@ -7,7 +8,7 @@
|
|||||||
SETUP_LOG();
|
SETUP_LOG();
|
||||||
|
|
||||||
RPCSub::RPCSub(const std::string& strUrl, const std::string& strUsername, const std::string& strPassword)
|
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;
|
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.");
|
throw std::runtime_error("Failed to parse url.");
|
||||||
}
|
}
|
||||||
|
else if (strScheme == "https")
|
||||||
|
{
|
||||||
|
mSSL = true;
|
||||||
|
}
|
||||||
else if (strScheme != "http")
|
else if (strScheme != "http")
|
||||||
{
|
{
|
||||||
throw std::runtime_error("Only http is supported.");
|
throw std::runtime_error("Only http and https is supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
mSeq = 1;
|
mSeq = 1;
|
||||||
|
|
||||||
if (mPort < 0)
|
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()
|
void RPCSub::sendThread()
|
||||||
{
|
{
|
||||||
Json::Value jvEvent;
|
Json::Value jvEvent;
|
||||||
@@ -58,12 +64,18 @@ void RPCSub::sendThread()
|
|||||||
// Send outside of the lock.
|
// Send outside of the lock.
|
||||||
if (bSend)
|
if (bSend)
|
||||||
{
|
{
|
||||||
|
// XXX Might not need this in a try.
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
cLog(lsDEBUG) << boost::str(boost::format("callRPC calling: %s") % mIp);
|
cLog(lsDEBUG) << boost::str(boost::format("callRPC calling: %s") % mIp);
|
||||||
|
|
||||||
// Drop result.
|
callRPC(
|
||||||
(void) callRPC(mIp, mPort, mUsername, mPassword, mPath, "event", jvEvent);
|
theApp->getIOService(),
|
||||||
|
mIp, mPort,
|
||||||
|
mUsername, mPassword,
|
||||||
|
mPath, "event",
|
||||||
|
jvEvent,
|
||||||
|
mSSL);
|
||||||
}
|
}
|
||||||
catch (const std::exception& e)
|
catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ class RPCSub : public InfoSub
|
|||||||
std::string mUrl;
|
std::string mUrl;
|
||||||
std::string mIp;
|
std::string mIp;
|
||||||
int mPort;
|
int mPort;
|
||||||
|
bool mSSL;
|
||||||
std::string mUsername;
|
std::string mUsername;
|
||||||
std::string mPassword;
|
std::string mPassword;
|
||||||
std::string mPath;
|
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.
|
// 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)
|
bool bReject = !err && iStatus != 200;
|
||||||
{
|
|
||||||
section secFile = ParseSection(strIpsFile, true);
|
|
||||||
|
|
||||||
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].
|
// Process section [ips_url].
|
||||||
@@ -820,13 +827,14 @@ void UniqueNodeList::getIpsUrl(const RippleAddress& naNodePublic, section secSit
|
|||||||
&& strScheme == "https")
|
&& strScheme == "https")
|
||||||
{
|
{
|
||||||
HttpsClient::httpsGet(
|
HttpsClient::httpsGet(
|
||||||
|
true,
|
||||||
theApp->getIOService(),
|
theApp->getIOService(),
|
||||||
strDomain,
|
strDomain,
|
||||||
443,
|
443,
|
||||||
strPath,
|
strPath,
|
||||||
NODE_FILE_BYTES_MAX,
|
NODE_FILE_BYTES_MAX,
|
||||||
boost::posix_time::seconds(NODE_FETCH_SECONDS),
|
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
|
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.
|
// 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)
|
bool bReject = !err && iStatus != 200;
|
||||||
{
|
|
||||||
section secFile = ParseSection(strValidatorsFile, true);
|
|
||||||
|
|
||||||
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].
|
// Process section [validators_url].
|
||||||
@@ -863,13 +878,14 @@ void UniqueNodeList::getValidatorsUrl(const RippleAddress& naNodePublic, section
|
|||||||
&& strScheme == "https")
|
&& strScheme == "https")
|
||||||
{
|
{
|
||||||
HttpsClient::httpsGet(
|
HttpsClient::httpsGet(
|
||||||
|
true,
|
||||||
theApp->getIOService(),
|
theApp->getIOService(),
|
||||||
strDomain,
|
strDomain,
|
||||||
443,
|
443,
|
||||||
strPath,
|
strPath,
|
||||||
NODE_FILE_BYTES_MAX,
|
NODE_FILE_BYTES_MAX,
|
||||||
boost::posix_time::seconds(NODE_FETCH_SECONDS),
|
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
|
else
|
||||||
{
|
{
|
||||||
@@ -905,118 +921,125 @@ void UniqueNodeList::processFile(const std::string& strDomain, const RippleAddre
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Given a ripple.txt, process it.
|
// 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 bReject = !err && iStatus != 200;
|
||||||
bool bGood = !err;
|
|
||||||
|
|
||||||
if (bGood)
|
if (!bReject)
|
||||||
{
|
{
|
||||||
cLog(lsTRACE) << boost::format("Validator: '%s' received " NODE_FILE_NAME ".") % strDomain;
|
section secSite = ParseSection(strSiteFile, true);
|
||||||
}
|
bool bGood = !err;
|
||||||
else
|
|
||||||
{
|
|
||||||
cLog(lsTRACE)
|
|
||||||
<< boost::format("Validator: '%s' unable to retrieve " NODE_FILE_NAME ": %s")
|
|
||||||
% strDomain
|
|
||||||
% err.message();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
if (bGood)
|
||||||
// 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;
|
cLog(lsTRACE) << boost::format("Validator: '%s' received " NODE_FILE_NAME ".") % strDomain;
|
||||||
processFile(strDomain, naNodePublic, secSite);
|
|
||||||
}
|
}
|
||||||
else
|
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();
|
fetchFinish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Failed: Update
|
|
||||||
|
|
||||||
// XXX If we have public key, perhaps try look up in CAS?
|
return bReject;
|
||||||
fetchFinish();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the ripple.txt and process it.
|
// Get the ripple.txt and process it.
|
||||||
@@ -1033,13 +1056,14 @@ void UniqueNodeList::fetchProcess(std::string strDomain)
|
|||||||
deqSites.push_back(strDomain);
|
deqSites.push_back(strDomain);
|
||||||
|
|
||||||
HttpsClient::httpsGet(
|
HttpsClient::httpsGet(
|
||||||
|
true,
|
||||||
theApp->getIOService(),
|
theApp->getIOService(),
|
||||||
deqSites,
|
deqSites,
|
||||||
443,
|
443,
|
||||||
NODE_FILE_PATH,
|
NODE_FILE_PATH,
|
||||||
NODE_FILE_BYTES_MAX,
|
NODE_FILE_BYTES_MAX,
|
||||||
boost::posix_time::seconds(NODE_FETCH_SECONDS),
|
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)
|
void UniqueNodeList::fetchTimerHandler(const boost::system::error_code& err)
|
||||||
@@ -1549,18 +1573,25 @@ bool UniqueNodeList::nodeLoad(boost::filesystem::path pConfig)
|
|||||||
return true;
|
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);
|
cLog(lsTRACE) << "Fetch '" VALIDATORS_FILE_NAME "' complete.";
|
||||||
}
|
|
||||||
else
|
if (!err)
|
||||||
{
|
{
|
||||||
cLog(lsWARNING) << "Error: " << err.message();
|
nodeProcess("network", strResponse, theConfig.VALIDATORS_SITE);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cLog(lsWARNING) << "Error: " << err.message();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return bReject;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UniqueNodeList::nodeNetwork()
|
void UniqueNodeList::nodeNetwork()
|
||||||
@@ -1568,13 +1599,14 @@ void UniqueNodeList::nodeNetwork()
|
|||||||
if (!theConfig.VALIDATORS_SITE.empty())
|
if (!theConfig.VALIDATORS_SITE.empty())
|
||||||
{
|
{
|
||||||
HttpsClient::httpsGet(
|
HttpsClient::httpsGet(
|
||||||
|
true,
|
||||||
theApp->getIOService(),
|
theApp->getIOService(),
|
||||||
theConfig.VALIDATORS_SITE,
|
theConfig.VALIDATORS_SITE,
|
||||||
443,
|
443,
|
||||||
theConfig.VALIDATORS_URI,
|
theConfig.VALIDATORS_URI,
|
||||||
VALIDATORS_FILE_BYTES_MAX,
|
VALIDATORS_FILE_BYTES_MAX,
|
||||||
boost::posix_time::seconds(VALIDATORS_FETCH_SECONDS),
|
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);
|
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 mtpScoreNext; // When to start scoring.
|
||||||
boost::posix_time::ptime mtpScoreStart; // Time currently started scoring.
|
boost::posix_time::ptime mtpScoreStart; // Time currently started scoring.
|
||||||
@@ -122,8 +122,8 @@ private:
|
|||||||
|
|
||||||
void getValidatorsUrl(const RippleAddress& naNodePublic, section secSite);
|
void getValidatorsUrl(const RippleAddress& naNodePublic, section secSite);
|
||||||
void getIpsUrl(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);
|
bool responseIps(const std::string& strSite, const RippleAddress& naNodePublic, const boost::system::error_code& err, int iStatus, 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 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);
|
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);
|
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);
|
bool getSeedNodes(const RippleAddress& naNodePublic, seedNode& dstSeedNode);
|
||||||
void setSeedNodes(const seedNode& snSource, bool bNext);
|
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);
|
void nodeProcess(const std::string& strSite, const std::string& strValidators, const std::string& strSource);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -39,15 +39,15 @@ Json::Value JSONRPCError(int code, const std::string& message)
|
|||||||
// and to be compatible with other JSON-RPC implementations.
|
// 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;
|
std::ostringstream s;
|
||||||
|
|
||||||
s << "POST "
|
s << "POST "
|
||||||
<< (strPath.empty() ? "/" : strPath)
|
<< (strPath.empty() ? "/" : strPath)
|
||||||
<< " HTTP/1.1\r\n"
|
<< " HTTP/1.0\r\n"
|
||||||
<< "User-Agent: " SYSTEM_NAME "-json-rpc/" << FormatFullVersion() << "\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-Type: application/json\r\n"
|
||||||
<< "Content-Length: " << strMsg.size() << "\r\n"
|
<< "Content-Length: " << strMsg.size() << "\r\n"
|
||||||
<< "Accept: application/json\r\n";
|
<< "Accept: application/json\r\n";
|
||||||
|
|||||||
Reference in New Issue
Block a user