diff --git a/Builds/VisualStudio2012/RippleD.vcxproj b/Builds/VisualStudio2012/RippleD.vcxproj index d4aaa82fa6..7190389fa8 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj +++ b/Builds/VisualStudio2012/RippleD.vcxproj @@ -19,6 +19,12 @@ + + true + true + true + true + true true @@ -358,7 +364,7 @@ true true - + true true true @@ -860,12 +866,6 @@ true true - - true - true - true - true - true true @@ -1316,6 +1316,7 @@ + @@ -1391,7 +1392,7 @@ - + @@ -1471,7 +1472,6 @@ - diff --git a/Builds/VisualStudio2012/RippleD.vcxproj.filters b/Builds/VisualStudio2012/RippleD.vcxproj.filters index cd62d5c79f..0fb4c1e93f 100644 --- a/Builds/VisualStudio2012/RippleD.vcxproj.filters +++ b/Builds/VisualStudio2012/RippleD.vcxproj.filters @@ -145,12 +145,6 @@ {febf2e7e-f071-4a6c-9b81-68498fc8ea57} - - {10893147-455d-4a9e-ad3b-ec12d296a03d} - - - {03c077b7-8ae4-4e00-9eb5-78295cfd377d} - @@ -846,11 +840,11 @@ [1] Ripple\ripple_net\basics - - [1] Ripple\ripple_app\_network + + [1] Ripple\ripple_net\basics - - [1] Ripple\ripple_net\client + + [1] Ripple\ripple_app\basics @@ -1578,11 +1572,11 @@ [1] Ripple\ripple_net\basics - - [1] Ripple\ripple_app\_network + + [1] Ripple\ripple_net\basics - - [1] Ripple\ripple_net\client + + [1] Ripple\ripple_app\basics diff --git a/modules/ripple_app/basics/ripple_RPCServer.cpp b/modules/ripple_app/basics/ripple_RPCServer.cpp new file mode 100644 index 0000000000..175bdffbff --- /dev/null +++ b/modules/ripple_app/basics/ripple_RPCServer.cpp @@ -0,0 +1,307 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +SETUP_LOG (RPCServer) + +// VFALCO TODO Make this a language constant +#ifndef RPC_MAXIMUM_QUERY +#define RPC_MAXIMUM_QUERY (1024*1024) +#endif + +class RPCServerImp + : public RPCServer +{ +public: + typedef boost::shared_ptr pointer; + + RPCServerImp ( + boost::asio::io_service& io_service, + boost::asio::ssl::context& context, + NetworkOPs* nopNetwork) + : mNetOps (nopNetwork) + , mSocket (io_service, context) + , mStrand (io_service) + { + mRole = RPCHandler::GUEST; + } + + //-------------------------------------------------------------------------- + +private: + void handle_write (const boost::system::error_code& e) + { + //Log::out() << "async_write complete " << e; + + if (!e) + { + HTTPRequest::Action action = mHTTPRequest.requestDone (false); + + if (action == HTTPRequest::haCLOSE_CONN) + { + mSocket.async_shutdown (mStrand.wrap (boost::bind ( + &RPCServerImp::handle_shutdown, + boost::static_pointer_cast (shared_from_this()), + boost::asio::placeholders::error))); + } + else + { + boost::asio::async_read_until ( + mSocket, + mLineBuffer, + "\r\n", + mStrand.wrap (boost::bind ( + &RPCServerImp::handle_read_line, + boost::static_pointer_cast (shared_from_this()), + boost::asio::placeholders::error))); + } + } + + if (e != boost::asio::error::operation_aborted) + { + //connection_manager_.stop(shared_from_this()); + } + } + + //-------------------------------------------------------------------------- + + void handle_read_line (const boost::system::error_code& e) + { + if (e) + return; + + HTTPRequest::Action action = mHTTPRequest.consume (mLineBuffer); + + if (action == HTTPRequest::haDO_REQUEST) + { + // request with no body + WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body"; + + mSocket.async_shutdown (mStrand.wrap (boost::bind ( + &RPCServerImp::handle_shutdown, + boost::static_pointer_cast (shared_from_this ()), + boost::asio::placeholders::error))); + + return; + } + else if (action == HTTPRequest::haREAD_LINE) + { + boost::asio::async_read_until ( + mSocket, + mLineBuffer, + "\r\n", + mStrand.wrap (boost::bind ( + &RPCServerImp::handle_read_line, + boost::static_pointer_cast (shared_from_this ()), + boost::asio::placeholders::error))); + } + else if (action == HTTPRequest::haREAD_RAW) + { + int rLen = mHTTPRequest.getDataSize (); + + if ((rLen < 0) || (rLen > RPC_MAXIMUM_QUERY)) + { + WriteLog (lsWARNING, RPCServer) << "Illegal RPC request length " << rLen; + + mSocket.async_shutdown (mStrand.wrap (boost::bind ( + &RPCServerImp::handle_shutdown, + boost::static_pointer_cast (shared_from_this ()), + boost::asio::placeholders::error))); + + return; + } + + int alreadyHave = mLineBuffer.size (); + + if (alreadyHave < rLen) + { + mQueryVec.resize (rLen - alreadyHave); + + boost::asio::async_read ( + mSocket, + boost::asio::buffer (mQueryVec), + mStrand.wrap (boost::bind ( + &RPCServerImp::handle_read_req, + boost::static_pointer_cast (shared_from_this ()), + boost::asio::placeholders::error))); + + WriteLog (lsTRACE, RPCServer) << "Waiting for completed request: " << rLen; + } + else + { + // we have the whole thing + mQueryVec.resize (0); + handle_read_req (e); + } + } + else + { + mSocket.async_shutdown (mStrand.wrap (boost::bind ( + &RPCServerImp::handle_shutdown, + boost::static_pointer_cast (shared_from_this ()), + boost::asio::placeholders::error))); + } + } + + //-------------------------------------------------------------------------- + + void handle_read_req (const boost::system::error_code& ec) + { + std::string req; + + if (mLineBuffer.size ()) + { + req.assign (boost::asio::buffer_cast (mLineBuffer.data ()), mLineBuffer.size ()); + mLineBuffer.consume (mLineBuffer.size ()); + } + + req += strCopy (mQueryVec); + + if (!HTTPAuthorized (mHTTPRequest.peekHeaders ())) + mReplyStr = HTTPReply (403, "Forbidden"); + else + mReplyStr = handleRequest (req); + + boost::asio::async_write ( + mSocket, + boost::asio::buffer (mReplyStr), + mStrand.wrap (boost::bind ( + &RPCServerImp::handle_write, + boost::static_pointer_cast (shared_from_this ()), + boost::asio::placeholders::error))); + } + + //-------------------------------------------------------------------------- + + void handle_shutdown (const boost::system::error_code& ec) + { + // nothing to do, we just keep the object alive + } + + //-------------------------------------------------------------------------- + + std::string handleRequest (const std::string& requestStr) + { + WriteLog (lsTRACE, RPCServer) << "handleRequest " << requestStr; + + Json::Value id; + + // Parse request + Json::Value jvRequest; + Json::Reader reader; + + if (!reader.parse (requestStr, jvRequest) || jvRequest.isNull () || !jvRequest.isObject ()) + return (HTTPReply (400, "unable to parse request")); + + // Parse id now so errors from here on will have the id + id = jvRequest["id"]; + + // Parse method + Json::Value valMethod = jvRequest["method"]; + + if (valMethod.isNull ()) + return (HTTPReply (400, "null method")); + + if (!valMethod.isString ()) + return (HTTPReply (400, "method is not string")); + + std::string strMethod = valMethod.asString (); + + // Parse params + Json::Value valParams = jvRequest["params"]; + + if (valParams.isNull ()) + { + valParams = Json::Value (Json::arrayValue); + } + else if (!valParams.isArray ()) + { + return HTTPReply (400, "params unparseable"); + } + + try + { + mRole = iAdminGet (jvRequest, mSocket.PlainSocket ().remote_endpoint ().address ().to_string ()); + } + catch (...) + { + // endpoint already disconnected + return ""; + } + + if (RPCHandler::FORBID == mRole) + { + // XXX This needs rate limiting to prevent brute forcing password. + return HTTPReply (403, "Forbidden"); + } + + RPCHandler mRPCHandler (mNetOps); + + WriteLog (lsINFO, RPCServer) << valParams; + LoadType loadType = LT_RPCReference; + Json::Value result = mRPCHandler.doRpcCommand (strMethod, valParams, mRole, &loadType); + + // VFALCO NOTE We discard loadType since there is no endpoint to punish + + WriteLog (lsINFO, RPCServer) << result; + + std::string strReply = JSONRPCReply (result, Json::Value (), id); + + return HTTPReply (200, strReply); + } + + //-------------------------------------------------------------------------- + + AutoSocket& getSocket () + { + return mSocket; + } + + //-------------------------------------------------------------------------- + + boost::asio::ip::tcp::socket& getRawSocket () + { + return mSocket.PlainSocket (); + } + + //-------------------------------------------------------------------------- + + void connected () + { + //Log::out() << "RPC request"; + boost::asio::async_read_until ( + mSocket, + mLineBuffer, + "\r\n", + mStrand.wrap (boost::bind ( + &RPCServerImp::handle_read_line, + boost::static_pointer_cast (shared_from_this ()), + boost::asio::placeholders::error))); + } + +private: + NetworkOPs* const mNetOps; + + AutoSocket mSocket; + boost::asio::io_service::strand mStrand; + + boost::asio::streambuf mLineBuffer; + Blob mQueryVec; + std::string mReplyStr; + + HTTPRequest mHTTPRequest; + + int mRole; +}; + +//------------------------------------------------------------------------------ + +RPCServer::pointer RPCServer::New ( + boost::asio::io_service& io_service, + boost::asio::ssl::context& context, + NetworkOPs* mNetOps) +{ + return pointer (new RPCServerImp (io_service, context, mNetOps)); +} diff --git a/modules/ripple_app/basics/ripple_RPCServer.h b/modules/ripple_app/basics/ripple_RPCServer.h new file mode 100644 index 0000000000..13a7f1cac6 --- /dev/null +++ b/modules/ripple_app/basics/ripple_RPCServer.h @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +/* + Copyright (c) 2011-2013, OpenCoin, Inc. +*/ +//============================================================================== + +#ifndef RIPPLE_RPCSERVER_H_INCLUDED +#define RIPPLE_RPCSERVER_H_INCLUDED + +// VFALCO NOTE This looks like intrusve shared object? +// +class RPCServer + : public boost::enable_shared_from_this + , LeakChecked +{ +public: + typedef boost::shared_ptr pointer; + +public: + static pointer New ( + boost::asio::io_service& io_service, + boost::asio::ssl::context& context, + NetworkOPs* mNetOps); + + virtual AutoSocket& getSocket () = 0; + + // VFALCO TODO Remove this since it exposes boost + virtual boost::asio::ip::tcp::socket& getRawSocket () = 0; + + virtual void connected () = 0; +}; + +#endif diff --git a/modules/ripple_app/ripple_app.cpp b/modules/ripple_app/ripple_app.cpp index 520c4240d6..09d67fac86 100644 --- a/modules/ripple_app/ripple_app.cpp +++ b/modules/ripple_app/ripple_app.cpp @@ -169,8 +169,6 @@ namespace ripple #include "src/cpp/ripple/PaymentTransactor.h" #include "src/cpp/ripple/PeerDoor.h" #include "src/cpp/ripple/RPC.h" -#include "src/cpp/ripple/RPCServer.h" -#include "src/cpp/ripple/RPCDoor.h" #include "src/cpp/ripple/RPCErr.h" #include "src/cpp/ripple/RPCSub.h" #include "src/cpp/ripple/RegularKeySetTransactor.h" @@ -184,6 +182,9 @@ namespace ripple #include "basics/ripple_Version.h" // VFALCO TODO Should this be private? #include "basics/ripple_BuildVersion.h" // private +#include "basics/ripple_RPCServer.h" + +#include "src/cpp/ripple/RPCDoor.h" // needs RPCServer } @@ -228,6 +229,8 @@ static const uint64 tenTo17m1 = tenTo17 - 1; #if ! defined (RIPPLE_MAIN_PART) || RIPPLE_MAIN_PART == 1 +#include "basics/ripple_RPCServer.cpp" + #include "src/cpp/ripple/Ledger.cpp" #include "src/cpp/ripple/ripple_SHAMapDelta.cpp" #include "src/cpp/ripple/ripple_SHAMapNode.cpp" @@ -312,7 +315,6 @@ static DH* handleTmpDh (SSL* ssl, int is_export, int iKeyLength) #include "src/cpp/ripple/RegularKeySetTransactor.cpp" #include "src/cpp/ripple/ripple_RippleState.cpp" #include "src/cpp/ripple/RPCDoor.cpp" -#include "src/cpp/ripple/RPCServer.cpp" #include "src/cpp/ripple/ScriptData.cpp" #include "src/cpp/ripple/SNTPClient.cpp" #include "src/cpp/ripple/TransactionCheck.cpp" diff --git a/modules/ripple_net/client/ripple_HttpsClient.cpp b/modules/ripple_net/basics/ripple_HttpsClient.cpp similarity index 100% rename from modules/ripple_net/client/ripple_HttpsClient.cpp rename to modules/ripple_net/basics/ripple_HttpsClient.cpp diff --git a/modules/ripple_net/client/ripple_HttpsClient.h b/modules/ripple_net/basics/ripple_HttpsClient.h similarity index 99% rename from modules/ripple_net/client/ripple_HttpsClient.h rename to modules/ripple_net/basics/ripple_HttpsClient.h index ad2f21e989..59920f1426 100644 --- a/modules/ripple_net/client/ripple_HttpsClient.h +++ b/modules/ripple_net/basics/ripple_HttpsClient.h @@ -7,9 +7,10 @@ #ifndef RIPPLE_HTTPSCLIENT_H_INCLUDED #define RIPPLE_HTTPSCLIENT_H_INCLUDED +// VFALCO TODO Make this an abstract interface. +// /** Provides an asynchronous HTTPS client implementation. */ - class HttpsClient : public boost::enable_shared_from_this , LeakChecked diff --git a/modules/ripple_net/ripple_net.cpp b/modules/ripple_net/ripple_net.cpp index e7fe87cd1b..a13d24b9fe 100644 --- a/modules/ripple_net/ripple_net.cpp +++ b/modules/ripple_net/ripple_net.cpp @@ -21,7 +21,6 @@ namespace ripple { #include "basics/ripple_HTTPRequest.cpp" - -#include "client/ripple_HttpsClient.cpp" +#include "basics/ripple_HttpsClient.cpp" } diff --git a/modules/ripple_net/ripple_net.h b/modules/ripple_net/ripple_net.h index 67e6024b57..91758b7029 100644 --- a/modules/ripple_net/ripple_net.h +++ b/modules/ripple_net/ripple_net.h @@ -28,8 +28,7 @@ namespace ripple { #include "basics/ripple_HTTPRequest.h" - -#include "client/ripple_HttpsClient.h" +#include "basics/ripple_HttpsClient.h" } diff --git a/src/cpp/ripple/RPCDoor.cpp b/src/cpp/ripple/RPCDoor.cpp index ae6f115602..1197f51650 100644 --- a/src/cpp/ripple/RPCDoor.cpp +++ b/src/cpp/ripple/RPCDoor.cpp @@ -30,7 +30,7 @@ RPCDoor::~RPCDoor () void RPCDoor::startListening () { - RPCServer::pointer new_connection = RPCServer::create (mAcceptor.get_io_service (), mSSLContext, &getApp().getOPs ()); + RPCServer::pointer new_connection = RPCServer::New (mAcceptor.get_io_service (), mSSLContext, &getApp().getOPs ()); mAcceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true)); mAcceptor.async_accept (new_connection->getRawSocket (), diff --git a/src/cpp/ripple/RPCServer.cpp b/src/cpp/ripple/RPCServer.cpp deleted file mode 100644 index 1113e87131..0000000000 --- a/src/cpp/ripple/RPCServer.cpp +++ /dev/null @@ -1,207 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -#ifndef RPC_MAXIMUM_QUERY -#define RPC_MAXIMUM_QUERY (1024*1024) -#endif - -SETUP_LOG (RPCServer) - -RPCServer::RPCServer (boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* nopNetwork) - : mNetOps (nopNetwork), mSocket (io_service, context), mStrand(io_service) -{ - mRole = RPCHandler::GUEST; -} - -void RPCServer::connected () -{ - //Log::out() << "RPC request"; - boost::asio::async_read_until (mSocket, mLineBuffer, "\r\n", - mStrand.wrap (boost::bind (&RPCServer::handle_read_line, shared_from_this (), boost::asio::placeholders::error))); -} - -void RPCServer::handle_read_req (const boost::system::error_code& e) -{ - std::string req; - - if (mLineBuffer.size ()) - { - req.assign (boost::asio::buffer_cast (mLineBuffer.data ()), mLineBuffer.size ()); - mLineBuffer.consume (mLineBuffer.size ()); - } - - req += strCopy (mQueryVec); - - if (!HTTPAuthorized (mHTTPRequest.peekHeaders ())) - mReplyStr = HTTPReply (403, "Forbidden"); - else - mReplyStr = handleRequest (req); - - boost::asio::async_write (mSocket, boost::asio::buffer (mReplyStr), - mStrand.wrap (boost::bind (&RPCServer::handle_write, shared_from_this (), boost::asio::placeholders::error))); -} - -void RPCServer::handle_read_line (const boost::system::error_code& e) -{ - if (e) - return; - - HTTPRequest::Action action = mHTTPRequest.consume (mLineBuffer); - - if (action == HTTPRequest::haDO_REQUEST) - { - // request with no body - WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body"; - mSocket.async_shutdown (mStrand.wrap (boost::bind (&RPCServer::handle_shutdown, shared_from_this(), boost::asio::placeholders::error))); - return; - } - else if (action == HTTPRequest::haREAD_LINE) - { - boost::asio::async_read_until (mSocket, mLineBuffer, "\r\n", - mStrand.wrap (boost::bind (&RPCServer::handle_read_line, shared_from_this (), - boost::asio::placeholders::error))); - } - else if (action == HTTPRequest::haREAD_RAW) - { - int rLen = mHTTPRequest.getDataSize (); - - if ((rLen < 0) || (rLen > RPC_MAXIMUM_QUERY)) - { - WriteLog (lsWARNING, RPCServer) << "Illegal RPC request length " << rLen; - mSocket.async_shutdown (mStrand.wrap (boost::bind (&RPCServer::handle_shutdown, shared_from_this(), boost::asio::placeholders::error))); - return; - } - - int alreadyHave = mLineBuffer.size (); - - if (alreadyHave < rLen) - { - mQueryVec.resize (rLen - alreadyHave); - boost::asio::async_read (mSocket, boost::asio::buffer (mQueryVec), - mStrand.wrap (boost::bind (&RPCServer::handle_read_req, shared_from_this (), boost::asio::placeholders::error))); - WriteLog (lsTRACE, RPCServer) << "Waiting for completed request: " << rLen; - } - else - { - // we have the whole thing - mQueryVec.resize (0); - handle_read_req (e); - } - } - else - mSocket.async_shutdown (mStrand.wrap (boost::bind (&RPCServer::handle_shutdown, shared_from_this(), boost::asio::placeholders::error))); -} - -std::string RPCServer::handleRequest (const std::string& requestStr) -{ - WriteLog (lsTRACE, RPCServer) << "handleRequest " << requestStr; - - Json::Value id; - - // Parse request - Json::Value jvRequest; - Json::Reader reader; - - if (!reader.parse (requestStr, jvRequest) || jvRequest.isNull () || !jvRequest.isObject ()) - return (HTTPReply (400, "unable to parse request")); - - // Parse id now so errors from here on will have the id - id = jvRequest["id"]; - - // Parse method - Json::Value valMethod = jvRequest["method"]; - - if (valMethod.isNull ()) - return (HTTPReply (400, "null method")); - - if (!valMethod.isString ()) - return (HTTPReply (400, "method is not string")); - - std::string strMethod = valMethod.asString (); - - // Parse params - Json::Value valParams = jvRequest["params"]; - - if (valParams.isNull ()) - { - valParams = Json::Value (Json::arrayValue); - } - else if (!valParams.isArray ()) - { - return HTTPReply (400, "params unparseable"); - } - - try - { - mRole = iAdminGet (jvRequest, mSocket.PlainSocket ().remote_endpoint ().address ().to_string ()); - } - catch (...) - { - // endpoint already disconnected - return ""; - } - - if (RPCHandler::FORBID == mRole) - { - // XXX This needs rate limiting to prevent brute forcing password. - return HTTPReply (403, "Forbidden"); - } - - RPCHandler mRPCHandler (mNetOps); - - WriteLog (lsINFO, RPCServer) << valParams; - LoadType loadType = LT_RPCReference; - Json::Value result = mRPCHandler.doRpcCommand (strMethod, valParams, mRole, &loadType); - - // VFALCO NOTE We discard loadType since there is no endpoint to punish - - WriteLog (lsINFO, RPCServer) << result; - - std::string strReply = JSONRPCReply (result, Json::Value (), id); - return HTTPReply (200, strReply); -} - -#if 0 -// now, expire, n -bool RPCServer::parseAcceptRate (const std::string& sAcceptRate) -{ - if (!sAcceptRate.compare ("expire")) - 0; - - return true; -} -#endif - - -void RPCServer::handle_write (const boost::system::error_code& e) -{ - //Log::out() << "async_write complete " << e; - - if (!e) - { - HTTPRequest::Action action = mHTTPRequest.requestDone (false); - - if (action == HTTPRequest::haCLOSE_CONN) - mSocket.async_shutdown (mStrand.wrap (boost::bind (&RPCServer::handle_shutdown, shared_from_this(), boost::asio::placeholders::error))); - else - { - boost::asio::async_read_until (mSocket, mLineBuffer, "\r\n", - mStrand.wrap (boost::bind (&RPCServer::handle_read_line, shared_from_this (), boost::asio::placeholders::error))); - } - } - - if (e != boost::asio::error::operation_aborted) - { - //connection_manager_.stop(shared_from_this()); - } -} - -// nothing to do, we just keep the object alive -void RPCServer::handle_shutdown (const boost::system::error_code& e) -{ -} - -// vim:ts=4 diff --git a/src/cpp/ripple/RPCServer.h b/src/cpp/ripple/RPCServer.h deleted file mode 100644 index 7f754f6cf1..0000000000 --- a/src/cpp/ripple/RPCServer.h +++ /dev/null @@ -1,67 +0,0 @@ -//------------------------------------------------------------------------------ -/* - Copyright (c) 2011-2013, OpenCoin, Inc. -*/ -//============================================================================== - -#ifndef __RPCSERVER__ -#define __RPCSERVER__ - -class RPCServer - : public boost::enable_shared_from_this - , LeakChecked -{ -public: - - typedef boost::shared_ptr pointer; - -private: - - NetworkOPs* mNetOps; - - AutoSocket mSocket; - boost::asio::io_service::strand mStrand; - - boost::asio::streambuf mLineBuffer; - Blob mQueryVec; - std::string mReplyStr; - - HTTPRequest mHTTPRequest; - - - int mRole; - - RPCServer (boost::asio::io_service& io_service, boost::asio::ssl::context& ssl_context, NetworkOPs* nopNetwork); - - RPCServer (const RPCServer&); // no implementation - RPCServer& operator= (const RPCServer&); // no implementation - - void handle_write (const boost::system::error_code& ec); - void handle_read_line (const boost::system::error_code& ec); - void handle_read_req (const boost::system::error_code& ec); - void handle_shutdown (const boost::system::error_code& ec); - - std::string handleRequest (const std::string& requestStr); - -public: - static pointer create (boost::asio::io_service& io_service, boost::asio::ssl::context& context, NetworkOPs* mNetOps) - { - return pointer (new RPCServer (io_service, context, mNetOps)); - } - - AutoSocket& getSocket () - { - return mSocket; - } - - boost::asio::ip::tcp::socket& getRawSocket () - { - return mSocket.PlainSocket (); - } - - void connected (); -}; - -#endif - -// vim:ts=4