Merge branch 'develop' of github.com:ripple/rippled into develop

This commit is contained in:
David Schwartz
2013-07-25 09:56:42 -07:00
150 changed files with 1112 additions and 1117 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,73 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef __CALLRPC__
#define __CALLRPC__
class RPCParser
{
public:
Json::Value parseCommand (std::string strMethod, Json::Value jvParams);
private:
typedef Json::Value (RPCParser::*parseFuncPtr) (const Json::Value& jvParams);
Json::Value parseAccountRaw (const Json::Value& jvParams, bool bPeer);
Json::Value parseAccountItems (const Json::Value& jvParams);
Json::Value parseAccountLines (const Json::Value& jvParams);
Json::Value parseAccountTransactions (const Json::Value& jvParams);
Json::Value parseAsIs (const Json::Value& jvParams);
Json::Value parseBookOffers (const Json::Value& jvParams);
Json::Value parseConnect (const Json::Value& jvParams);
#if ENABLE_INSECURE
Json::Value parseDataDelete (const Json::Value& jvParams);
Json::Value parseDataFetch (const Json::Value& jvParams);
Json::Value parseDataStore (const Json::Value& jvParams);
#endif
Json::Value parseEvented (const Json::Value& jvParams);
Json::Value parseFeature (const Json::Value& jvParams);
Json::Value parseFetchInfo (const Json::Value& jvParams);
Json::Value parseGetCounts (const Json::Value& jvParams);
Json::Value parseInternal (const Json::Value& jvParams);
Json::Value parseJson (const Json::Value& jvParams);
Json::Value parseLedger (const Json::Value& jvParams);
Json::Value parseLedgerId (const Json::Value& jvParams);
#if ENABLE_INSECURE
Json::Value parseLogin (const Json::Value& jvParams);
#endif
Json::Value parseLogLevel (const Json::Value& jvParams);
Json::Value parseOwnerInfo (const Json::Value& jvParams);
Json::Value parseProofCreate (const Json::Value& jvParams);
Json::Value parseProofSolve (const Json::Value& jvParams);
Json::Value parseProofVerify (const Json::Value& jvParams);
Json::Value parseRandom (const Json::Value& jvParams);
Json::Value parseRipplePathFind (const Json::Value& jvParams);
Json::Value parseSMS (const Json::Value& jvParams);
Json::Value parseSignSubmit (const Json::Value& jvParams);
Json::Value parseTx (const Json::Value& jvParams);
Json::Value parseTxHistory (const Json::Value& jvParams);
Json::Value parseUnlAdd (const Json::Value& jvParams);
Json::Value parseUnlDelete (const Json::Value& jvParams);
Json::Value parseValidationCreate (const Json::Value& jvParams);
Json::Value parseValidationSeed (const Json::Value& jvParams);
Json::Value parseWalletAccounts (const Json::Value& jvParams);
Json::Value parseWalletPropose (const Json::Value& jvParams);
Json::Value parseWalletSeed (const Json::Value& jvParams);
};
extern int commandLineRPC (const std::vector<std::string>& vCmd);
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,
FUNCTION_TYPE<void (const Json::Value& jvInput)> callbackFuncP = FUNCTION_TYPE<void (const Json::Value& jvInput)> ());
#endif
// vim:ts=4

View File

@@ -0,0 +1,36 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_RPC_H_INCLUDED
#define RIPPLE_RPC_H_INCLUDED
// 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,
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 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

View File

@@ -0,0 +1,101 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (RPCDoor)
RPCDoor::RPCDoor (boost::asio::io_service& io_service, RPCServer::Handler& handler)
: m_rpcServerHandler (handler)
, mAcceptor (io_service,
boost::asio::ip::tcp::endpoint (boost::asio::ip::address::from_string (theConfig.getRpcIP ()), theConfig.getRpcPort ()))
, mDelayTimer (io_service)
, mSSLContext (boost::asio::ssl::context::sslv23)
{
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.getRpcAddress().toRawUTF8() << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
if (theConfig.RPC_SECURE != 0)
{
// VFALCO TODO This could be a method of theConfig
//
basio::SslContext::initializeFromFile (
mSSLContext,
theConfig.RPC_SSL_KEY,
theConfig.RPC_SSL_CERT,
theConfig.RPC_SSL_CHAIN);
}
startListening ();
}
RPCDoor::~RPCDoor ()
{
WriteLog (lsINFO, RPCDoor) << "RPC port: " << theConfig.getRpcAddress().toRawUTF8() << " allow remote: " << theConfig.RPC_ALLOW_REMOTE;
}
void RPCDoor::startListening ()
{
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.async_accept (new_connection->getRawSocket (),
boost::bind (&RPCDoor::handleConnect, this, new_connection,
boost::asio::placeholders::error));
}
bool RPCDoor::isClientAllowed (const std::string& ip)
{
if (theConfig.RPC_ALLOW_REMOTE)
return true;
// VFALCO TODO Represent ip addresses as a structure. Use isLoopback() member here
//
if (ip == "127.0.0.1")
return true;
return false;
}
void RPCDoor::handleConnect (RPCServer::pointer new_connection, const boost::system::error_code& error)
{
bool delay = false;
if (!error)
{
// Restrict callers by IP
try
{
if (! isClientAllowed (new_connection->getRemoteAddressText ()))
{
startListening ();
return;
}
}
catch (...)
{
// client may have disconnected
startListening ();
return;
}
new_connection->getSocket ().async_handshake (AutoSocket::ssl_socket::server,
boost::bind (&RPCServer::connected, new_connection));
}
else
{
if (error == boost::system::errc::too_many_files_open)
delay = true;
WriteLog (lsINFO, RPCDoor) << "RPCDoor::handleConnect Error: " << error;
}
if (delay)
{
mDelayTimer.expires_from_now (boost::posix_time::milliseconds (1000));
mDelayTimer.async_wait (boost::bind (&RPCDoor::startListening, this));
}
else
startListening ();
}
// vim:ts=4

View File

@@ -0,0 +1,35 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_RPCDOOR_H
#define RIPPLE_RPCDOOR_H
/*
Handles incoming connections from people making RPC Requests
*/
class RPCDoor : LeakChecked <RPCDoor>
{
public:
explicit RPCDoor (
boost::asio::io_service& io_service,
RPCServer::Handler& handler);
~RPCDoor ();
private:
RPCServer::Handler& m_rpcServerHandler;
boost::asio::ip::tcp::acceptor mAcceptor;
boost::asio::deadline_timer mDelayTimer;
boost::asio::ssl::context mSSLContext;
void startListening ();
void handleConnect (RPCServer::pointer new_connection,
const boost::system::error_code& error);
bool isClientAllowed (const std::string& ip);
};
#endif

View File

@@ -0,0 +1,106 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
struct RPCErr; // for Log
SETUP_LOG (RPCErr)
Json::Value rpcError (int iError, Json::Value jvResult)
{
static struct
{
int iError;
const char* pToken;
const char* pMessage;
} errorInfoA[] =
{
{ rpcACT_BITCOIN, "actBitcoin", "Account is bitcoin address." },
{ rpcACT_EXISTS, "actExists", "Account already exists." },
{ rpcACT_MALFORMED, "actMalformed", "Account malformed." },
{ rpcACT_NOT_FOUND, "actNotFound", "Account not found." },
{ rpcBAD_BLOB, "badBlob", "Blob must be a non-empty hex string." },
{ rpcBAD_FEATURE, "badFeature", "Feature unknown or invalid." },
{ rpcBAD_ISSUER, "badIssuer", "Issuer account malformed." },
{ rpcBAD_MARKET, "badMarket", "No such market." },
{ rpcBAD_SECRET, "badSecret", "Secret does not match account." },
{ rpcBAD_SEED, "badSeed", "Disallowed seed." },
{ rpcBAD_SYNTAX, "badSyntax", "Syntax error." },
{ rpcCOMMAND_MISSING, "commandMissing", "Missing command entry." },
{ rpcDST_ACT_MALFORMED, "dstActMalformed", "Destination account is malformed." },
{ rpcDST_ACT_MISSING, "dstActMissing", "Destination account does not exist." },
{ rpcDST_AMT_MALFORMED, "dstAmtMalformed", "Destination amount/currency/issuer is malformed." },
{ rpcDST_ISR_MALFORMED, "dstIsrMalformed", "Destination issuer is malformed." },
{ rpcFORBIDDEN, "forbidden", "Bad credentials." },
{ rpcFAIL_GEN_DECRPYT, "failGenDecrypt", "Failed to decrypt generator." },
{ rpcGETS_ACT_MALFORMED, "getsActMalformed", "Gets account malformed." },
{ rpcGETS_AMT_MALFORMED, "getsAmtMalformed", "Gets amount malformed." },
{ rpcHOST_IP_MALFORMED, "hostIpMalformed", "Host IP is malformed." },
{ rpcINSUF_FUNDS, "insufFunds", "Insufficient funds." },
{ rpcINTERNAL, "internal", "Internal error." },
{ rpcINVALID_PARAMS, "invalidParams", "Invalid parameters." },
{ rpcJSON_RPC, "json_rpc", "JSON-RPC transport error." },
{ rpcLGR_IDXS_INVALID, "lgrIdxsInvalid", "Ledger indexes invalid." },
{ rpcLGR_IDX_MALFORMED, "lgrIdxMalformed", "Ledger index malformed." },
{ rpcLGR_NOT_FOUND, "lgrNotFound", "Ledger not found." },
{ rpcNICKNAME_MALFORMED, "nicknameMalformed", "Nickname is malformed." },
{ rpcNICKNAME_MISSING, "nicknameMissing", "Nickname does not exist." },
{ rpcNICKNAME_PERM, "nicknamePerm", "Account does not control nickname." },
{ rpcNOT_IMPL, "notImpl", "Not implemented." },
{ rpcNO_ACCOUNT, "noAccount", "No such account." },
{ rpcNO_CLOSED, "noClosed", "Closed ledger is unavailable." },
{ rpcNO_CURRENT, "noCurrent", "Current ledger is unavailable." },
{ rpcNO_EVENTS, "noEvents", "Current transport does not support events." },
{ rpcNO_GEN_DECRPYT, "noGenDectypt", "Password failed to decrypt master public generator." },
{ rpcNO_NETWORK, "noNetwork", "Network not available." },
{ rpcNO_PATH, "noPath", "Unable to find a ripple path." },
{ rpcNO_PERMISSION, "noPermission", "You don't have permission for this command." },
{ rpcNO_PF_REQUEST, "noPathRequest", "No pathfinding request in progress." },
{ rpcNOT_STANDALONE, "notStandAlone", "Operation valid in debug mode only." },
{ rpcNOT_SUPPORTED, "notSupported", "Operation not supported." },
{ rpcPASSWD_CHANGED, "passwdChanged", "Wrong key, password changed." },
{ rpcPAYS_ACT_MALFORMED, "paysActMalformed", "Pays account malformed." },
{ rpcPAYS_AMT_MALFORMED, "paysAmtMalformed", "Pays amount malformed." },
{ rpcPORT_MALFORMED, "portMalformed", "Port is malformed." },
{ rpcPUBLIC_MALFORMED, "publicMalformed", "Public key is malformed." },
{ rpcQUALITY_MALFORMED, "qualityMalformed", "Quality malformed." },
{ rpcSRC_ACT_MALFORMED, "srcActMalformed", "Source account is malformed." },
{ rpcSRC_ACT_MISSING, "srcActMissing", "Source account not provided." },
{ rpcSRC_ACT_NOT_FOUND, "srcActNotFound", "Source account not found." },
{ rpcSRC_AMT_MALFORMED, "srcAmtMalformed", "Source amount/currency/issuer is malformed." },
{ rpcSRC_CUR_MALFORMED, "srcCurMalformed", "Source currency is malformed." },
{ rpcSRC_ISR_MALFORMED, "srcIsrMalformed", "Source issuer is malformed." },
{ rpcSRC_UNCLAIMED, "srcUnclaimed", "Source account is not claimed." },
{ rpcTXN_NOT_FOUND, "txnNotFound", "Transaction not found." },
{ rpcUNKNOWN_COMMAND, "unknownCmd", "Unknown method." },
{ rpcWRONG_SEED, "wrongSeed", "The regular key does not point as the master key." },
{ rpcTOO_BUSY, "tooBusy", "The server is too busy to help you now." },
{ rpcSLOW_DOWN, "slowDown", "You are placing too much load on the server." },
};
int i;
for (i = NUMBER (errorInfoA); i-- && errorInfoA[i].iError != iError;)
;
jvResult["error"] = i >= 0 ? errorInfoA[i].pToken : lexical_cast_i (iError);
jvResult["error_message"] = i >= 0 ? errorInfoA[i].pMessage : lexical_cast_i (iError);
jvResult["error_code"] = iError;
if (i >= 0)
{
WriteLog (lsDEBUG, RPCErr) << "rpcError: "
<< errorInfoA[i].pToken << ": " << errorInfoA[i].pMessage << std::endl;
}
return jvResult;
}
bool isRpcError (Json::Value jvResult)
{
return jvResult.isObject () && jvResult.isMember ("error");
}
// vim:ts=4

View File

@@ -0,0 +1,97 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef __RPCERR__
#define __RPCERR__
enum
{
rpcSUCCESS = 0,
rpcBAD_SYNTAX, // Must be 1 to print usage to command line.
rpcJSON_RPC,
rpcFORBIDDEN,
// Error numbers beyond this line are not stable between versions.
// Programs should use error tokens.
// Misc failure
rpcLOAD_FAILED,
rpcNO_PERMISSION,
rpcNO_EVENTS,
rpcNOT_STANDALONE,
rpcTOO_BUSY,
rpcSLOW_DOWN,
// Networking
rpcNO_CLOSED,
rpcNO_CURRENT,
rpcNO_NETWORK,
// Ledger state
rpcACT_EXISTS,
rpcACT_NOT_FOUND,
rpcINSUF_FUNDS,
rpcLGR_NOT_FOUND,
rpcNICKNAME_MISSING,
rpcNO_ACCOUNT,
rpcNO_PATH,
rpcPASSWD_CHANGED,
rpcSRC_MISSING,
rpcSRC_UNCLAIMED,
rpcTXN_NOT_FOUND,
rpcWRONG_SEED,
// Malformed command
rpcINVALID_PARAMS,
rpcUNKNOWN_COMMAND,
rpcNO_PF_REQUEST,
// Bad parameter
rpcACT_BITCOIN,
rpcACT_MALFORMED,
rpcQUALITY_MALFORMED,
rpcBAD_BLOB,
rpcBAD_FEATURE,
rpcBAD_ISSUER,
rpcBAD_MARKET,
rpcBAD_SECRET,
rpcBAD_SEED,
rpcCOMMAND_MISSING,
rpcDST_ACT_MALFORMED,
rpcDST_ACT_MISSING,
rpcDST_AMT_MALFORMED,
rpcDST_ISR_MALFORMED,
rpcGETS_ACT_MALFORMED,
rpcGETS_AMT_MALFORMED,
rpcHOST_IP_MALFORMED,
rpcLGR_IDXS_INVALID,
rpcLGR_IDX_MALFORMED,
rpcNICKNAME_MALFORMED,
rpcNICKNAME_PERM,
rpcPAYS_ACT_MALFORMED,
rpcPAYS_AMT_MALFORMED,
rpcPORT_MALFORMED,
rpcPUBLIC_MALFORMED,
rpcSRC_ACT_MALFORMED,
rpcSRC_ACT_MISSING,
rpcSRC_ACT_NOT_FOUND,
rpcSRC_AMT_MALFORMED,
rpcSRC_CUR_MALFORMED,
rpcSRC_ISR_MALFORMED,
// Internal error (should never happen)
rpcINTERNAL, // Generic internal error.
rpcFAIL_GEN_DECRPYT,
rpcNOT_IMPL,
rpcNOT_SUPPORTED,
rpcNO_GEN_DECRPYT,
};
bool isRpcError (Json::Value jvResult);
Json::Value rpcError (int iError, Json::Value jvResult = Json::Value (Json::objectValue));
#endif
// vim:ts=4

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,191 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef __RPCHANDLER__
#define __RPCHANDLER__
#define LEDGER_CURRENT -1
#define LEDGER_CLOSED -2
#define LEDGER_VALIDATED -3
// used by the RPCServer or WSDoor to carry out these RPC commands
class NetworkOPs;
class InfoSub;
// VFALCO TODO Refactor to abstract interface IRPCHandler
//
class RPCHandler
{
public:
enum
{
GUEST,
USER,
ADMIN,
FORBID
};
explicit RPCHandler (NetworkOPs* netOps);
RPCHandler (NetworkOPs* netOps, InfoSub::pointer infoSub);
Json::Value doCommand (const Json::Value& jvRequest, int role, LoadType* loadType);
Json::Value doRpcCommand (const std::string& strCommand, Json::Value const& jvParams, int iRole, LoadType* loadType);
private:
typedef Json::Value (RPCHandler::*doFuncPtr) (
Json::Value params,
LoadType* loadType,
Application::ScopedLockType& MasterLockHolder);
// VFALCO TODO Document these and give the enumeration a label.
enum
{
optNone = 0,
optNetwork = 1, // Need network
optCurrent = 2 + optNetwork, // Need current ledger
optClosed = 4 + optNetwork, // Need closed ledger
};
// Utilities
void addSubmitPath (Json::Value& txJSON);
boost::unordered_set <RippleAddress> parseAccountIds (const Json::Value& jvArray);
Json::Value transactionSign (Json::Value jvRequest, bool bSubmit, bool bFailHard, Application::ScopedLockType& mlh);
Json::Value lookupLedger (Json::Value jvRequest, Ledger::pointer& lpLedger);
Json::Value getMasterGenerator (
Ledger::ref lrLedger,
const RippleAddress& naRegularSeed,
RippleAddress& naMasterGenerator);
Json::Value authorize (
Ledger::ref lrLedger,
const RippleAddress& naRegularSeed,
const RippleAddress& naSrcAccountID,
RippleAddress& naAccountPublic,
RippleAddress& naAccountPrivate,
STAmount& saSrcBalance,
const STAmount& saFee,
AccountState::pointer& asSrc,
const RippleAddress& naVerifyGenerator);
Json::Value accounts (
Ledger::ref lrLedger,
const RippleAddress& naMasterGenerator);
Json::Value accountFromString (
Ledger::ref lrLedger,
RippleAddress& naAccount,
bool& bIndex,
const std::string& strIdent,
const int iIndex,
const bool bStrict);
Json::Value doAccountInfo (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doAccountLines (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doAccountOffers (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doAccountTransactions (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doBookOffers (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doConnect (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doConsensusInfo (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doFeature (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doFetchInfo (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doGetCounts (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doInternal (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLedger (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLedgerAccept (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLedgerClosed (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLedgerCurrent (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLedgerEntry (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLedgerHeader (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLogLevel (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLogRotate (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doNicknameInfo (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doOwnerInfo (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doPathFind (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doPeers (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doPing (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doProfile (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doProofCreate (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doProofSolve (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doProofVerify (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doRandom (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doRipplePathFind (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doSMS (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doServerInfo (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); // for humans
Json::Value doServerState (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh); // for machines
Json::Value doSessionClose (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doSessionOpen (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doSign (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doStop (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doSubmit (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doSubscribe (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doTransactionEntry (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doTx (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doTxHistory (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlAdd (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlDelete (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlFetch (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlList (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlLoad (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlNetwork (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlReset (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnlScore (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doUnsubscribe (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doValidationCreate (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doValidationSeed (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doWalletAccounts (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doWalletLock (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doWalletPropose (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doWalletSeed (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doWalletUnlock (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doWalletVerify (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
#if ENABLE_INSECURE
Json::Value doDataDelete (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doDataFetch (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doDataStore (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
Json::Value doLogin (Json::Value params, LoadType* loadType, Application::ScopedLockType& mlh);
#endif
private:
NetworkOPs* mNetOps;
InfoSub::pointer mInfoSub;
// VFALCO TODO Create an enumeration for this.
int mRole;
};
class RPCInternalHandler
{
public:
typedef Json::Value (*handler_t) (const Json::Value&);
public:
RPCInternalHandler (const std::string& name, handler_t handler);
static Json::Value runHandler (const std::string& name, const Json::Value& params);
private:
// VFALCO TODO Replace with a singleton with a well defined interface and
// a lock free stack (if necessary).
//
static RPCInternalHandler* sHeadHandler;
RPCInternalHandler* mNextHandler;
std::string mName;
handler_t mHandler;
};
// VFALCO TODO tidy up this loose function
int iAdminGet (const Json::Value& jvRequest, const std::string& strRemoteIp);
#endif
// vim:ts=4

View File

@@ -0,0 +1,119 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (RPCSub)
RPCSub::RPCSub (const std::string& strUrl, const std::string& strUsername, const std::string& strPassword)
: mUrl (strUrl), mSSL (false), mUsername (strUsername), mPassword (strPassword), mSending (false)
{
std::string strScheme;
if (!parseUrl (strUrl, strScheme, mIp, mPort, mPath))
{
throw std::runtime_error ("Failed to parse url.");
}
else if (strScheme == "https")
{
mSSL = true;
}
else if (strScheme != "http")
{
throw std::runtime_error ("Only http and https is supported.");
}
mSeq = 1;
if (mPort < 0)
mPort = mSSL ? 443 : 80;
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC sub: ip='%s' port=%d ssl=%d path='%s'")
% mIp
% mPort
% mSSL
% mPath);
}
// XXX Could probably create a bunch of send jobs in a single get of the lock.
void RPCSub::sendThread ()
{
Json::Value jvEvent;
bool bSend;
do
{
{
// Obtain the lock to manipulate the queue and change sending.
boost::mutex::scoped_lock sl (mLockInfo);
if (mDeque.empty ())
{
mSending = false;
bSend = false;
}
else
{
std::pair<int, Json::Value> pEvent = mDeque.front ();
mDeque.pop_front ();
jvEvent = pEvent.second;
jvEvent["seq"] = pEvent.first;
bSend = true;
}
}
// Send outside of the lock.
if (bSend)
{
// XXX Might not need this in a try.
try
{
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC calling: %s") % mIp);
callRPC (
getApp().getIOService (),
mIp, mPort,
mUsername, mPassword,
mPath, "event",
jvEvent,
mSSL);
}
catch (const std::exception& e)
{
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC exception: %s") % e.what ());
}
}
}
while (bSend);
}
void RPCSub::send (const Json::Value& jvObj, bool broadcast)
{
boost::mutex::scoped_lock sl (mLockInfo);
if (RPC_EVENT_QUEUE_MAX == mDeque.size ())
{
// Drop the previous event.
WriteLog (lsWARNING, RPCSub) << boost::str (boost::format ("callRPC drop"));
mDeque.pop_back ();
}
WriteLog (broadcast ? lsDEBUG : lsINFO, RPCSub) << boost::str (boost::format ("callRPC push: %s") % jvObj);
mDeque.push_back (std::make_pair (mSeq++, jvObj));
if (!mSending)
{
// Start a sending thread.
mSending = true;
WriteLog (lsINFO, RPCSub) << boost::str (boost::format ("callRPC start"));
boost::thread (BIND_TYPE (&RPCSub::sendThread, this)).detach ();
}
}
// vim:ts=4

View File

@@ -0,0 +1,65 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef __RPCSUB__
#define __RPCSUB__
#define RPC_EVENT_QUEUE_MAX 32
// Subscription object for JSON-RPC
class RPCSub
: public InfoSub
, LeakChecked <RPCSub>
{
public:
typedef boost::shared_ptr<RPCSub> pointer;
typedef const pointer& ref;
RPCSub (const std::string& strUrl, const std::string& strUsername, const std::string& strPassword);
virtual ~RPCSub ()
{
;
}
// Implement overridden functions from base class:
void send (const Json::Value& jvObj, bool broadcast);
void setUsername (const std::string& strUsername)
{
boost::mutex::scoped_lock sl (mLockInfo);
mUsername = strUsername;
}
void setPassword (const std::string& strPassword)
{
boost::mutex::scoped_lock sl (mLockInfo);
mPassword = strPassword;
}
protected:
void sendThread ();
private:
std::string mUrl;
std::string mIp;
int mPort;
bool mSSL;
std::string mUsername;
std::string mPassword;
std::string mPath;
int mSeq; // Next id to allocate.
bool mSending; // Sending threead is active.
std::deque<std::pair<int, Json::Value> > mDeque;
};
#endif
// vim:ts=4

View File

@@ -0,0 +1,281 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
// Used for logging
struct RPC;
SETUP_LOG (RPC)
unsigned int const gMaxHTTPHeaderSize = 0x02000000;
std::string gFormatStr ("v1");
// VFALCO TODO clean up this nonsense
std::string FormatFullVersion ()
{
return (gFormatStr);
}
Json::Value JSONRPCError (int code, const std::string& message)
{
Json::Value error (Json::objectValue);
error["code"] = Json::Value (code);
error["message"] = Json::Value (message);
return error;
}
//
// HTTP protocol
//
// This ain't Apache. We're just using HTTP header for the length field
// and to be compatible with other JSON-RPC implementations.
//
std::string createHTTPPost (const std::string& strHost, const std::string& strPath, const std::string& strMsg, const std::map<std::string, std::string>& mapRequestHeaders)
{
std::ostringstream s;
s << "POST "
<< (strPath.empty () ? "/" : strPath)
<< " HTTP/1.0\r\n"
<< "User-Agent: " SYSTEM_NAME "-json-rpc/" << FormatFullVersion () << "\r\n"
<< "Host: " << strHost << "\r\n"
<< "Content-Type: application/json\r\n"
<< "Content-Length: " << strMsg.size () << "\r\n"
<< "Accept: application/json\r\n";
typedef std::map<std::string, std::string>::value_type HeaderType;
BOOST_FOREACH (const HeaderType & item, mapRequestHeaders)
s << item.first << ": " << item.second << "\r\n";
s << "\r\n" << strMsg;
return s.str ();
}
std::string rfc1123Time ()
{
char buffer[64];
time_t now;
time (&now);
struct tm* now_gmt = gmtime (&now);
std::string locale (setlocale (LC_TIME, NULL));
setlocale (LC_TIME, "C"); // we want posix (aka "C") weekday/month strings
strftime (buffer, sizeof (buffer), "%a, %d %b %Y %H:%M:%S +0000", now_gmt);
setlocale (LC_TIME, locale.c_str ());
return std::string (buffer);
}
std::string HTTPReply (int nStatus, const std::string& strMsg)
{
WriteLog (lsTRACE, RPC) << "HTTP Reply " << nStatus << " " << strMsg;
if (nStatus == 401)
return strprintf ("HTTP/1.0 401 Authorization Required\r\n"
"Date: %s\r\n"
"Server: " SYSTEM_NAME "-json-rpc/%s\r\n"
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 296\r\n"
"\r\n"
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\r\n"
"\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd\">\r\n"
"<HTML>\r\n"
"<HEAD>\r\n"
"<TITLE>Error</TITLE>\r\n"
"<META HTTP-EQUIV='Content-Type' CONTENT='text/html; charset=ISO-8859-1'>\r\n"
"</HEAD>\r\n"
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n"
"</HTML>\r\n", rfc1123Time ().c_str (), FormatFullVersion ().c_str ());
std::string strStatus;
if (nStatus == 200) strStatus = "OK";
else if (nStatus == 400) strStatus = "Bad Request";
else if (nStatus == 403) strStatus = "Forbidden";
else if (nStatus == 404) strStatus = "Not Found";
else if (nStatus == 500) strStatus = "Internal Server Error";
std::string access;
if (theConfig.RPC_ALLOW_REMOTE) access = "Access-Control-Allow-Origin: *\r\n";
else access = "";
return strprintf (
"HTTP/1.1 %d %s\r\n"
"Date: %s\r\n"
"Connection: Keep-Alive\r\n"
"%s"
"Content-Length: %d\r\n"
"Content-Type: application/json; charset=UTF-8\r\n"
"Server: " SYSTEM_NAME "-json-rpc/%s\r\n"
"\r\n"
"%s\r\n",
nStatus,
strStatus.c_str (),
rfc1123Time ().c_str (),
access.c_str (),
strMsg.size () + 2,
SERVER_VERSION,
strMsg.c_str ());
}
int ReadHTTPStatus (std::basic_istream<char>& stream)
{
std::string str;
getline (stream, str);
std::vector<std::string> vWords;
boost::split (vWords, str, boost::is_any_of (" "));
if (vWords.size () < 2)
return 500;
return atoi (vWords[1].c_str ());
}
int ReadHTTPHeader (std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet)
{
int nLen = 0;
for (;;)
{
std::string str;
std::getline (stream, str);
if (str.empty () || str == "\r")
break;
std::string::size_type nColon = str.find (":");
if (nColon != std::string::npos)
{
std::string strHeader = str.substr (0, nColon);
boost::trim (strHeader);
boost::to_lower (strHeader);
std::string strValue = str.substr (nColon + 1);
boost::trim (strValue);
mapHeadersRet[strHeader] = strValue;
if (strHeader == "content-length")
nLen = atoi (strValue.c_str ());
}
}
return nLen;
}
int ReadHTTP (std::basic_istream<char>& stream, std::map<std::string, std::string>& mapHeadersRet,
std::string& strMessageRet)
{
mapHeadersRet.clear ();
strMessageRet = "";
// Read status
int nStatus = ReadHTTPStatus (stream);
// Read header
int nLen = ReadHTTPHeader (stream, mapHeadersRet);
if (nLen < 0 || nLen > gMaxHTTPHeaderSize)
return 500;
// Read message
if (nLen > 0)
{
std::vector<char> vch (nLen);
stream.read (&vch[0], nLen);
strMessageRet = std::string (vch.begin (), vch.end ());
}
return nStatus;
}
std::string DecodeBase64 (std::string s)
{
// FIXME: This performs badly
BIO* b64, *bmem;
char* buffer = static_cast<char*> (calloc (s.size (), sizeof (char)));
b64 = BIO_new (BIO_f_base64 ());
BIO_set_flags (b64, BIO_FLAGS_BASE64_NO_NL);
bmem = BIO_new_mem_buf (const_cast<char*> (s.data ()), s.size ());
bmem = BIO_push (b64, bmem);
BIO_read (bmem, buffer, s.size ());
BIO_free_all (bmem);
std::string result (buffer);
free (buffer);
return result;
}
bool HTTPAuthorized (const std::map<std::string, std::string>& mapHeaders)
{
std::map<std::string, std::string>::const_iterator it = mapHeaders.find ("authorization");
if ((it == mapHeaders.end ()) || (it->second.substr (0, 6) != "Basic "))
return theConfig.RPC_USER.empty () && theConfig.RPC_PASSWORD.empty ();
std::string strUserPass64 = it->second.substr (6);
boost::trim (strUserPass64);
std::string strUserPass = DecodeBase64 (strUserPass64);
std::string::size_type nColon = strUserPass.find (":");
if (nColon == std::string::npos)
return false;
std::string strUser = strUserPass.substr (0, nColon);
std::string strPassword = strUserPass.substr (nColon + 1);
return (strUser == theConfig.RPC_USER) && (strPassword == theConfig.RPC_PASSWORD);
}
//
// JSON-RPC protocol. Bitcoin speaks version 1.0 for maximum compatibility,
// but uses JSON-RPC 1.1/2.0 standards for parts of the 1.0 standard that were
// unspecified (HTTP errors and contents of 'error').
//
// 1.0 spec: http://json-rpc.org/wiki/specification
// 1.2 spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
//
std::string JSONRPCRequest (const std::string& strMethod, const Json::Value& params, const Json::Value& id)
{
Json::Value request;
request["method"] = strMethod;
request["params"] = params;
request["id"] = id;
Json::FastWriter writer;
return writer.write (request) + "\n";
}
std::string JSONRPCReply (const Json::Value& result, const Json::Value& error, const Json::Value& id)
{
Json::Value reply (Json::objectValue);
reply["result"] = result;
//reply["error"]=error;
//reply["id"]=id;
Json::FastWriter writer;
return writer.write (reply) + "\n";
}
void ErrorReply (std::ostream& stream, const Json::Value& objError, const Json::Value& id)
{
// Send error reply from json-rpc error object
int nStatus = 500;
int code = objError["code"].asInt ();
if (code == -32600) nStatus = 400;
else if (code == -32601) nStatus = 404;
std::string strReply = JSONRPCReply (Json::Value (), objError, id);
stream << HTTPReply (nStatus, strReply) << std::flush;
}
// vim:ts=4