Refactor RPCServer

This commit is contained in:
Vinnie Falco
2013-07-09 15:05:11 -07:00
parent 040c8f4de1
commit b343b0929a
17 changed files with 350 additions and 232 deletions

View File

@@ -19,7 +19,7 @@
</ProjectConfiguration> </ProjectConfiguration>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\modules\ripple_app\basics\ripple_RPCServer.cpp"> <ClCompile Include="..\..\modules\ripple_app\basics\ripple_RPCServerHandler.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
@@ -370,6 +370,12 @@
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild> <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\modules\ripple_net\basics\ripple_RPCServer.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">true</ExcludedFromBuild>
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|x64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\modules\ripple_net\ripple_net.cpp" /> <ClCompile Include="..\..\modules\ripple_net\ripple_net.cpp" />
<ClCompile Include="..\..\modules\ripple_sqlite\ripple_sqlite.c" /> <ClCompile Include="..\..\modules\ripple_sqlite\ripple_sqlite.c" />
<ClCompile Include="..\..\modules\ripple_websocket\autosocket\ripple_AutoSocket.cpp"> <ClCompile Include="..\..\modules\ripple_websocket\autosocket\ripple_AutoSocket.cpp">
@@ -1316,7 +1322,7 @@
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\BeastConfig.h" /> <ClInclude Include="..\..\BeastConfig.h" />
<ClInclude Include="..\..\modules\ripple_app\basics\ripple_BuildVersion.h" /> <ClInclude Include="..\..\modules\ripple_app\basics\ripple_BuildVersion.h" />
<ClInclude Include="..\..\modules\ripple_app\basics\ripple_RPCServer.h" /> <ClInclude Include="..\..\modules\ripple_app\basics\ripple_RPCServerHandler.h" />
<ClInclude Include="..\..\modules\ripple_app\basics\ripple_Version.h" /> <ClInclude Include="..\..\modules\ripple_app\basics\ripple_Version.h" />
<ClInclude Include="..\..\modules\ripple_app\ripple_app.h" /> <ClInclude Include="..\..\modules\ripple_app\ripple_app.h" />
<ClInclude Include="..\..\modules\ripple_basics\containers\ripple_KeyCache.h" /> <ClInclude Include="..\..\modules\ripple_basics\containers\ripple_KeyCache.h" />
@@ -1393,6 +1399,7 @@
<ClInclude Include="..\..\modules\ripple_leveldb\ripple_leveldb.h" /> <ClInclude Include="..\..\modules\ripple_leveldb\ripple_leveldb.h" />
<ClInclude Include="..\..\modules\ripple_net\basics\ripple_HTTPRequest.h" /> <ClInclude Include="..\..\modules\ripple_net\basics\ripple_HTTPRequest.h" />
<ClInclude Include="..\..\modules\ripple_net\basics\ripple_HttpsClient.h" /> <ClInclude Include="..\..\modules\ripple_net\basics\ripple_HttpsClient.h" />
<ClInclude Include="..\..\modules\ripple_net\basics\ripple_RPCServer.h" />
<ClInclude Include="..\..\modules\ripple_net\ripple_net.h" /> <ClInclude Include="..\..\modules\ripple_net\ripple_net.h" />
<ClInclude Include="..\..\modules\ripple_sqlite\ripple_sqlite.h" /> <ClInclude Include="..\..\modules\ripple_sqlite\ripple_sqlite.h" />
<ClInclude Include="..\..\modules\ripple_websocket\autosocket\ripple_AutoSocket.h" /> <ClInclude Include="..\..\modules\ripple_websocket\autosocket\ripple_AutoSocket.h" />

View File

@@ -843,9 +843,12 @@
<ClCompile Include="..\..\modules\ripple_net\basics\ripple_HttpsClient.cpp"> <ClCompile Include="..\..\modules\ripple_net\basics\ripple_HttpsClient.cpp">
<Filter>[1] Ripple\ripple_net\basics</Filter> <Filter>[1] Ripple\ripple_net\basics</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\modules\ripple_app\basics\ripple_RPCServer.cpp"> <ClCompile Include="..\..\modules\ripple_app\basics\ripple_RPCServerHandler.cpp">
<Filter>[1] Ripple\ripple_app\basics</Filter> <Filter>[1] Ripple\ripple_app\basics</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\modules\ripple_net\basics\ripple_RPCServer.cpp">
<Filter>[1] Ripple\ripple_net\basics</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\Subtrees\sqlite\sqlite3.h"> <ClInclude Include="..\..\Subtrees\sqlite\sqlite3.h">
@@ -1575,9 +1578,12 @@
<ClInclude Include="..\..\modules\ripple_net\basics\ripple_HttpsClient.h"> <ClInclude Include="..\..\modules\ripple_net\basics\ripple_HttpsClient.h">
<Filter>[1] Ripple\ripple_net\basics</Filter> <Filter>[1] Ripple\ripple_net\basics</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\modules\ripple_app\basics\ripple_RPCServer.h"> <ClInclude Include="..\..\modules\ripple_app\basics\ripple_RPCServerHandler.h">
<Filter>[1] Ripple\ripple_app\basics</Filter> <Filter>[1] Ripple\ripple_app\basics</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="..\..\modules\ripple_net\basics\ripple_RPCServer.h">
<Filter>[1] Ripple\ripple_net\basics</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<CustomBuild Include="..\..\src\cpp\ripple\ripple.proto" /> <CustomBuild Include="..\..\src\cpp\ripple\ripple.proto" />

View File

@@ -2,6 +2,8 @@
RIPPLE TODO RIPPLE TODO
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
- Tidy up convenience functions in RPC.h
- Maybe rename RPCServer to RPCClientServicer - Maybe rename RPCServer to RPCClientServicer
- Take away the "I" prefix from abstract interface classes, in both the class - Take away the "I" prefix from abstract interface classes, in both the class

View File

@@ -1,39 +0,0 @@
//------------------------------------------------------------------------------
/*
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 <RPCServer>
, LeakChecked <RPCServer>
{
public:
typedef boost::shared_ptr <RPCServer> 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;
/** Retrieve the remote address as a string.
@return A std::string representing the remote address.
*/
virtual std::string getRemoteAddressText () = 0;
};
#endif

View File

@@ -0,0 +1,98 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
RPCServerHandler::RPCServerHandler (NetworkOPs& networkOPs)
: m_networkOPs (networkOPs)
{
}
std::string RPCServerHandler::createResponse (
int statusCode,
std::string const& description)
{
return HTTPReply (statusCode, description);
}
bool RPCServerHandler::isAuthorized (
std::map <std::string, std::string> const& headers)
{
return HTTPAuthorized (headers);
}
std::string RPCServerHandler::processRequest (std::string const& request, std::string const& remoteAddress)
{
Json::Value jvRequest;
{
Json::Reader reader;
if (! reader.parse (request, jvRequest) ||
jvRequest.isNull () ||
! jvRequest.isObject ())
{
return createResponse (400, "Unable to parse request");
}
}
int role = iAdminGet (jvRequest, remoteAddress);
// Parse id now so errors from here on will have the id
//
// VFALCO NOTE Except that "id" isn't included in the following errors...
//
Json::Value const id = jvRequest ["id"];
Json::Value const method = jvRequest ["method"];
if (method.isNull ())
{
return createResponse (400, "Null method");
}
else if (! method.isString ())
{
return createResponse (400, "method is not string");
}
std::string strMethod = method.asString ();
// Parse params
Json::Value params = jvRequest ["params"];
if (params.isNull ())
{
params = Json::Value (Json::arrayValue);
}
else if (!params.isArray ())
{
return HTTPReply (400, "params unparseable");
}
// VFALCO TODO Shouldn't we handle this earlier?
//
if (role == RPCHandler::FORBID)
{
// VFALCO TODO Needs implementing
// FIXME Needs implementing
// XXX This needs rate limiting to prevent brute forcing password.
return HTTPReply (403, "Forbidden");
}
std::string response;
WriteLog (lsINFO, RPCServer) << params;
RPCHandler rpcHandler (&m_networkOPs);
LoadType loadType = LT_RPCReference;
Json::Value const result = rpcHandler.doRpcCommand (strMethod, params, role, &loadType);
// VFALCO NOTE We discard loadType since there is no endpoint to punish
WriteLog (lsINFO, RPCServer) << result;
response = JSONRPCReply (result, Json::Value (), id);
return createResponse (200, response);
}

View File

@@ -0,0 +1,27 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_RPCSERVERHANDLER_H_INCLUDED
#define RIPPLE_RPCSERVERHANDLER_H_INCLUDED
/** Handles RPC requests.
*/
class RPCServerHandler : public RPCServer::Handler
{
public:
explicit RPCServerHandler (NetworkOPs& networkOPs);
std::string createResponse (int statusCode, std::string const& description);
bool isAuthorized (std::map <std::string, std::string> const& headers);
std::string processRequest (std::string const& request, std::string const& remoteAddress);
private:
NetworkOPs& m_networkOPs;
};
#endif

View File

@@ -182,7 +182,7 @@ namespace ripple
#include "basics/ripple_Version.h" // VFALCO TODO Should this be private? #include "basics/ripple_Version.h" // VFALCO TODO Should this be private?
#include "basics/ripple_BuildVersion.h" // private #include "basics/ripple_BuildVersion.h" // private
#include "basics/ripple_RPCServer.h" #include "basics/ripple_RPCServerHandler.h"
#include "src/cpp/ripple/RPCDoor.h" // needs RPCServer #include "src/cpp/ripple/RPCDoor.h" // needs RPCServer
@@ -229,7 +229,7 @@ static const uint64 tenTo17m1 = tenTo17 - 1;
#if ! defined (RIPPLE_MAIN_PART) || RIPPLE_MAIN_PART == 1 #if ! defined (RIPPLE_MAIN_PART) || RIPPLE_MAIN_PART == 1
#include "basics/ripple_RPCServer.cpp" #include "basics/ripple_RPCServerHandler.cpp"
#include "src/cpp/ripple/Ledger.cpp" #include "src/cpp/ripple/Ledger.cpp"
#include "src/cpp/ripple/ripple_SHAMapDelta.cpp" #include "src/cpp/ripple/ripple_SHAMapDelta.cpp"

View File

@@ -6,35 +6,42 @@
SETUP_LOG (RPCServer) SETUP_LOG (RPCServer)
// VFALCO TODO Make this a language constant class RPCServerImp : public RPCServer, LeakChecked <RPCServerImp>
#ifndef RPC_MAXIMUM_QUERY
#define RPC_MAXIMUM_QUERY (1024*1024)
#endif
class RPCServerImp
: public RPCServer
{ {
public: public:
typedef boost::shared_ptr<RPCServer> pointer;
RPCServerImp ( RPCServerImp (
boost::asio::io_service& io_service, boost::asio::io_service& io_service,
boost::asio::ssl::context& context, boost::asio::ssl::context& context,
NetworkOPs* nopNetwork) Handler& handler)
: mNetOps (nopNetwork) : m_handler (handler)
, mSocket (io_service, context) , mSocket (io_service, context)
, mStrand (io_service) , mStrand (io_service)
{ {
mRole = RPCHandler::GUEST; }
//--------------------------------------------------------------------------
private:
enum
{
maxQueryBytes = 1024 * 1024
};
void connected ()
{
boost::asio::async_read_until (
mSocket,
mLineBuffer,
"\r\n",
mStrand.wrap (boost::bind (
&RPCServerImp::handle_read_line,
boost::static_pointer_cast <RPCServerImp> (shared_from_this ()),
boost::asio::placeholders::error)));
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
private:
void handle_write (const boost::system::error_code& e) void handle_write (const boost::system::error_code& e)
{ {
//Log::out() << "async_write complete " << e;
if (!e) if (!e)
{ {
HTTPRequest::Action action = mHTTPRequest.requestDone (false); HTTPRequest::Action action = mHTTPRequest.requestDone (false);
@@ -61,7 +68,9 @@ private:
if (e != boost::asio::error::operation_aborted) if (e != boost::asio::error::operation_aborted)
{ {
//connection_manager_.stop(shared_from_this()); // VFALCO TODO What is this for? It was commented out.
//
//connection_manager_.stop (shared_from_this ());
} }
} }
@@ -69,80 +78,79 @@ private:
void handle_read_line (const boost::system::error_code& e) void handle_read_line (const boost::system::error_code& e)
{ {
if (e) if (! e)
return;
HTTPRequest::Action action = mHTTPRequest.consume (mLineBuffer);
if (action == HTTPRequest::haDO_REQUEST)
{ {
// request with no body HTTPRequest::Action action = mHTTPRequest.consume (mLineBuffer);
WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body";
mSocket.async_shutdown (mStrand.wrap (boost::bind ( if (action == HTTPRequest::haDO_REQUEST)
&RPCServerImp::handle_shutdown,
boost::static_pointer_cast <RPCServerImp> (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 <RPCServerImp> (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; // request with no body
WriteLog (lsWARNING, RPCServer) << "RPC HTTP request with no body";
mSocket.async_shutdown (mStrand.wrap (boost::bind ( mSocket.async_shutdown (mStrand.wrap (boost::bind (
&RPCServerImp::handle_shutdown, &RPCServerImp::handle_shutdown,
boost::static_pointer_cast <RPCServerImp> (shared_from_this ()), boost::static_pointer_cast <RPCServerImp> (shared_from_this ()),
boost::asio::placeholders::error))); boost::asio::placeholders::error)));
return;
} }
else if (action == HTTPRequest::haREAD_LINE)
int alreadyHave = mLineBuffer.size ();
if (alreadyHave < rLen)
{ {
mQueryVec.resize (rLen - alreadyHave); boost::asio::async_read_until (
boost::asio::async_read (
mSocket, mSocket,
boost::asio::buffer (mQueryVec), mLineBuffer,
"\r\n",
mStrand.wrap (boost::bind ( mStrand.wrap (boost::bind (
&RPCServerImp::handle_read_req, &RPCServerImp::handle_read_line,
boost::static_pointer_cast <RPCServerImp> (shared_from_this ()), boost::static_pointer_cast <RPCServerImp> (shared_from_this ()),
boost::asio::placeholders::error))); boost::asio::placeholders::error)));
}
else if (action == HTTPRequest::haREAD_RAW)
{
int rLen = mHTTPRequest.getDataSize ();
WriteLog (lsTRACE, RPCServer) << "Waiting for completed request: " << rLen; if ((rLen < 0) || (rLen > maxQueryBytes))
{
WriteLog (lsWARNING, RPCServer) << "Illegal RPC request length " << rLen;
mSocket.async_shutdown (mStrand.wrap (boost::bind (
&RPCServerImp::handle_shutdown,
boost::static_pointer_cast <RPCServerImp> (shared_from_this ()),
boost::asio::placeholders::error)));
}
else
{
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 <RPCServerImp> (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 else
{ {
// we have the whole thing mSocket.async_shutdown (mStrand.wrap (boost::bind (
mQueryVec.resize (0); &RPCServerImp::handle_shutdown,
handle_read_req (e); boost::static_pointer_cast <RPCServerImp> (shared_from_this ()),
boost::asio::placeholders::error)));
} }
} }
else
{
mSocket.async_shutdown (mStrand.wrap (boost::bind (
&RPCServerImp::handle_shutdown,
boost::static_pointer_cast <RPCServerImp> (shared_from_this ()),
boost::asio::placeholders::error)));
}
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -153,16 +161,21 @@ private:
if (mLineBuffer.size ()) if (mLineBuffer.size ())
{ {
req.assign (boost::asio::buffer_cast<const char*> (mLineBuffer.data ()), mLineBuffer.size ()); req.assign (boost::asio::buffer_cast <const char*> (mLineBuffer.data ()), mLineBuffer.size ());
mLineBuffer.consume (mLineBuffer.size ()); mLineBuffer.consume (mLineBuffer.size ());
} }
req += strCopy (mQueryVec); req += strCopy (mQueryVec);
if (!HTTPAuthorized (mHTTPRequest.peekHeaders ())) if (! m_handler.isAuthorized (mHTTPRequest.peekHeaders ()))
mReplyStr = HTTPReply (403, "Forbidden"); {
mReplyStr = m_handler.createResponse (403, "Forbidden");
}
else else
{
mReplyStr = handleRequest (req); mReplyStr = handleRequest (req);
}
boost::asio::async_write ( boost::asio::async_write (
mSocket, mSocket,
@@ -182,48 +195,20 @@ private:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
std::string handleRequest (const std::string& requestStr) // JSON-RPC request must contain "method", "params", and "id" fields.
//
std::string handleRequest (const std::string& request)
{ {
WriteLog (lsTRACE, RPCServer) << "handleRequest " << requestStr; WriteLog (lsTRACE, RPCServer) << "handleRequest " << request;
Json::Value id; // Figure out the remote address.
// VFALCO TODO Clean up this try/catch nonsense.
// Parse request //
Json::Value jvRequest; std::string remoteAddress;
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 try
{ {
mRole = iAdminGet (jvRequest, mSocket.PlainSocket ().remote_endpoint ().address ().to_string ()); remoteAddress = mSocket.PlainSocket ().remote_endpoint ().address ().to_string ();
} }
catch (...) catch (...)
{ {
@@ -231,25 +216,7 @@ private:
return ""; return "";
} }
if (RPCHandler::FORBID == mRole) return m_handler.processRequest (request, remoteAddress);
{
// 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);
} }
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
@@ -268,21 +235,6 @@ private:
//-------------------------------------------------------------------------- //--------------------------------------------------------------------------
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 <RPCServerImp> (shared_from_this ()),
boost::asio::placeholders::error)));
}
//--------------------------------------------------------------------------
std::string getRemoteAddressText () std::string getRemoteAddressText ()
{ {
std::string address; std::string address;
@@ -293,7 +245,7 @@ private:
} }
private: private:
NetworkOPs* const mNetOps; Handler& m_handler;
AutoSocket mSocket; AutoSocket mSocket;
boost::asio::io_service::strand mStrand; boost::asio::io_service::strand mStrand;
@@ -303,8 +255,6 @@ private:
std::string mReplyStr; std::string mReplyStr;
HTTPRequest mHTTPRequest; HTTPRequest mHTTPRequest;
int mRole;
}; };
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
@@ -312,7 +262,7 @@ private:
RPCServer::pointer RPCServer::New ( RPCServer::pointer RPCServer::New (
boost::asio::io_service& io_service, boost::asio::io_service& io_service,
boost::asio::ssl::context& context, boost::asio::ssl::context& context,
NetworkOPs* mNetOps) Handler& handler)
{ {
return pointer (new RPCServerImp (io_service, context, mNetOps)); return pointer (new RPCServerImp (io_service, context, handler));
} }

View File

@@ -0,0 +1,68 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_RPCSERVER_H_INCLUDED
#define RIPPLE_RPCSERVER_H_INCLUDED
/** Provides RPC services to a client.
Each client has a separate instance of this object.
*/
// VFALCO NOTE This looks like intrusve shared object?
//
class RPCServer : public boost::enable_shared_from_this <RPCServer>
{
public:
typedef boost::shared_ptr <RPCServer> pointer;
public:
/** Handles a RPC client request.
*/
class Handler
{
public:
virtual ~Handler () { }
/** Construct a HTTP response string.
*/
virtual std::string createResponse (int statusCode, std::string const& description) = 0;
/** Determine if the connection is authorized.
*/
virtual bool isAuthorized (std::map <std::string, std::string> const& headers) = 0;
/** Produce a response for a given request.
@param request The RPC request string.
@return The server's response.
*/
virtual std::string processRequest (std::string const& request, std::string const& remoteAddress) = 0;
};
static pointer New (
boost::asio::io_service& io_service,
boost::asio::ssl::context& context,
Handler& handler);
/** Called when the connection is established.
*/
virtual void connected () = 0;
// VFALCO TODO AutoSocket exposes all sorts of boost::asio interface
virtual AutoSocket& getSocket () = 0;
// VFALCO TODO Remove this since it exposes boost
virtual boost::asio::ip::tcp::socket& getRawSocket () = 0;
/** Retrieve the remote address as a string.
@return A std::string representing the remote address.
*/
// VFALCO TODO Replace the return type with a dedicated class.
virtual std::string getRemoteAddressText () = 0;
};
#endif

View File

@@ -22,5 +22,6 @@ namespace ripple
#include "basics/ripple_HTTPRequest.cpp" #include "basics/ripple_HTTPRequest.cpp"
#include "basics/ripple_HttpsClient.cpp" #include "basics/ripple_HttpsClient.cpp"
#include "basics/ripple_RPCServer.cpp"
} }

View File

@@ -29,6 +29,7 @@ namespace ripple
#include "basics/ripple_HTTPRequest.h" #include "basics/ripple_HTTPRequest.h"
#include "basics/ripple_HttpsClient.h" #include "basics/ripple_HttpsClient.h"
#include "basics/ripple_RPCServer.h"
} }

View File

@@ -4,44 +4,33 @@
*/ */
//============================================================================== //==============================================================================
#ifndef __RPC_h__ #ifndef RIPPLE_RPC_H_INCLUDED
#define __RPC_h__ #define RIPPLE_RPC_H_INCLUDED
enum http_status_type
{
ok = 200,
created = 201,
accepted = 202,
no_content = 204,
multiple_choices = 300,
moved_permanently = 301,
moved_temporarily = 302,
not_modified = 304,
bad_request = 400,
unauthorized = 401,
forbidden = 403,
not_found = 404,
internal_server_error = 500,
not_implemented = 501,
bad_gateway = 502,
service_unavailable = 503
};
// VFALCO TODO Wrap these up into a class. It looks like they just do some
// convenience packaging of JSON data from the pieces. It looks
// Ripple client protocol-specific.
//
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& 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,
std::map<std::string, std::string>& mapHeadersRet, std::string& strMessageRet);
extern std::string HTTPReply (int nStatus, const std::string& strMsg);
extern std::string JSONRPCReply (const Json::Value& result, const Json::Value& error, const Json::Value& id); extern std::string JSONRPCReply (const Json::Value& result, const Json::Value& error, const Json::Value& id);
extern Json::Value JSONRPCError (int code, const std::string& message); extern Json::Value JSONRPCError (int code, const std::string& message);
extern bool HTTPAuthorized (const std::map<std::string, std::string>& mapHeaders); 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 std::string HTTPReply (int nStatus, const std::string& strMsg);
// VFALCO TODO Create a HTTPHeaders class with a nice interface instead of the std::map
//
extern bool HTTPAuthorized (std::map <std::string, std::string> const& mapHeaders);
// VFALCO NOTE This one looks like it does some sort of stream i/o
//
extern int ReadHTTP (std::basic_istream<char>& stream,
std::map<std::string, std::string>& mapHeadersRet,
std::string& strMessageRet);
#endif #endif

View File

@@ -6,11 +6,14 @@
SETUP_LOG (RPCDoor) SETUP_LOG (RPCDoor)
// VFALCO TODO Clean up this loose extern
//
extern void initSSLContext (boost::asio::ssl::context& context, extern void initSSLContext (boost::asio::ssl::context& context,
std::string key_file, std::string cert_file, std::string chain_file); std::string key_file, std::string cert_file, std::string chain_file);
RPCDoor::RPCDoor (boost::asio::io_service& io_service) RPCDoor::RPCDoor (boost::asio::io_service& io_service, RPCServer::Handler& handler)
: mAcceptor (io_service, : m_rpcServerHandler (handler)
, mAcceptor (io_service,
boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string (theConfig.getRpcIP ()), theConfig.getRpcPort ())) boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string (theConfig.getRpcIP ()), theConfig.getRpcPort ()))
, mDelayTimer (io_service) , mDelayTimer (io_service)
, mSSLContext (boost::asio::ssl::context::sslv23) , mSSLContext (boost::asio::ssl::context::sslv23)
@@ -30,7 +33,7 @@ RPCDoor::~RPCDoor ()
void RPCDoor::startListening () void RPCDoor::startListening ()
{ {
RPCServer::pointer new_connection = RPCServer::New (mAcceptor.get_io_service (), mSSLContext, &getApp().getOPs ()); RPCServer::pointer new_connection = RPCServer::New (mAcceptor.get_io_service (), mSSLContext, m_rpcServerHandler);
mAcceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true)); mAcceptor.set_option (boost::asio::ip::tcp::acceptor::reuse_address (true));
mAcceptor.async_accept (new_connection->getRawSocket (), mAcceptor.async_accept (new_connection->getRawSocket (),

View File

@@ -14,10 +14,13 @@ Handles incoming connections from people making RPC Requests
class RPCDoor : LeakChecked <RPCDoor> class RPCDoor : LeakChecked <RPCDoor>
{ {
public: public:
explicit RPCDoor (boost::asio::io_service& io_service); explicit RPCDoor (
boost::asio::io_service& io_service,
RPCServer::Handler& handler);
~RPCDoor (); ~RPCDoor ();
private: private:
RPCServer::Handler& m_rpcServerHandler;
boost::asio::ip::tcp::acceptor mAcceptor; boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::deadline_timer mDelayTimer; boost::asio::deadline_timer mDelayTimer;
boost::asio::ssl::context mSSLContext; boost::asio::ssl::context mSSLContext;

View File

@@ -3520,7 +3520,7 @@ Json::Value RPCHandler::doUnsubscribe (Json::Value params, LoadType* loadType, S
// //
// JSON-RPC provides a method and an array of params. JSON-RPC is used as a transport for a command and a request object. The // JSON-RPC provides a method and an array of params. JSON-RPC is used as a transport for a command and a request object. The
// command is the method. The request object is supplied as the first element of the params. // command is the method. The request object is supplied as the first element of the params.
Json::Value RPCHandler::doRpcCommand (const std::string& strMethod, Json::Value& jvParams, int iRole, LoadType* loadType) Json::Value RPCHandler::doRpcCommand (const std::string& strMethod, Json::Value const& jvParams, int iRole, LoadType* loadType)
{ {
WriteLog (lsTRACE, RPCHandler) << "doRpcCommand:" << strMethod << ":" << jvParams; WriteLog (lsTRACE, RPCHandler) << "doRpcCommand:" << strMethod << ":" << jvParams;

View File

@@ -34,7 +34,7 @@ public:
Json::Value doCommand (const Json::Value& jvRequest, int role, LoadType* loadType); Json::Value doCommand (const Json::Value& jvRequest, int role, LoadType* loadType);
Json::Value doRpcCommand (const std::string& strCommand, Json::Value& jvParams, int iRole, LoadType* loadType); Json::Value doRpcCommand (const std::string& strCommand, Json::Value const& jvParams, int iRole, LoadType* loadType);
private: private:
typedef Json::Value (RPCHandler::*doFuncPtr) ( typedef Json::Value (RPCHandler::*doFuncPtr) (

View File

@@ -221,6 +221,7 @@ private:
InboundLedgers m_inboundLedgers; InboundLedgers m_inboundLedgers;
TransactionMaster mMasterTransaction; TransactionMaster mMasterTransaction;
NetworkOPs mNetOps; NetworkOPs mNetOps;
RPCServerHandler m_rpcServerHandler;
NodeCache mTempNodeCache; NodeCache mTempNodeCache;
HashedObjectStore mHashedObjectStore; HashedObjectStore mHashedObjectStore;
SLECache mSLECache; SLECache mSLECache;
@@ -281,6 +282,7 @@ Application::Application ()
, mIOService ((theConfig.NODE_SIZE >= 2) ? 2 : 1) , mIOService ((theConfig.NODE_SIZE >= 2) ? 2 : 1)
, mIOWork (mIOService) , mIOWork (mIOService)
, mNetOps (&mLedgerMaster) , mNetOps (&mLedgerMaster)
, m_rpcServerHandler (mNetOps)
, mTempNodeCache ("NodeCache", 16384, 90) , mTempNodeCache ("NodeCache", 16384, 90)
, mHashedObjectStore (16384, 300) , mHashedObjectStore (16384, 300)
, mSLECache ("LedgerEntryCache", 4096, 120) , mSLECache ("LedgerEntryCache", 4096, 120)
@@ -589,7 +591,7 @@ void Application::setup ()
{ {
try try
{ {
mRPCDoor = new RPCDoor (mIOService); mRPCDoor = new RPCDoor (mIOService, m_rpcServerHandler);
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {