void startServer () { // // Execute start up rpc commands. // if (getConfig ().RPC_STARTUP.isArray ()) { for (int i = 0; i != getConfig ().RPC_STARTUP.size (); ++i) { const Json::Value& jvCommand = getConfig ().RPC_STARTUP[i]; if (!getConfig ().QUIET) Log::out() << "Startup RPC: " << jvCommand; RPCHandler rhHandler (&getApp().getOPs ()); Resource::Charge loadType = Resource::feeReferenceRPC; Json::Value jvResult = rhHandler.doCommand (jvCommand, Config::ADMIN, loadType); if (!getConfig ().QUIET) Log::out() << "Result: " << jvResult; } } getApp().run (); // Blocks till we get a stop RPC. }
void startServer () { // // Execute start up rpc commands. // if (getConfig ().RPC_STARTUP.isArray ()) { for (int i = 0; i != getConfig ().RPC_STARTUP.size (); ++i) { const Json::Value& jvCommand = getConfig ().RPC_STARTUP[i]; if (!getConfig ().QUIET) Log::out() << "Startup RPC: " << jvCommand; RPCHandler rhHandler (&getApp().getOPs ()); // VFALCO TODO Clean up this magic number LoadType loadType = LT_RPCReference; Json::Value jvResult = rhHandler.doCommand (jvCommand, RPCHandler::ADMIN, &loadType); if (!getConfig ().QUIET) Log::out() << "Result: " << jvResult; } } getApp().run (); // Blocks till we get a stop RPC. }
void startServer () { // // Execute start up rpc commands. // if (theConfig.RPC_STARTUP.isArray ()) { for (int i = 0; i != theConfig.RPC_STARTUP.size (); ++i) { const Json::Value& jvCommand = theConfig.RPC_STARTUP[i]; if (!theConfig.QUIET) std::cerr << "Startup RPC: " << jvCommand << std::endl; RPCHandler rhHandler (&theApp->getOPs ()); // VFALCO TODO Clean up this magic number LoadType loadType = LT_RPCReference; Json::Value jvResult = rhHandler.doCommand (jvCommand, RPCHandler::ADMIN, &loadType); if (!theConfig.QUIET) std::cerr << "Result: " << jvResult << std::endl; } } theApp->run (); // Blocks till we get a stop RPC. }
void RPCHandlerIntermediary::down(MessageContext * context) throw (IntermediaryException,ResponseException) { // Get Qualifier //-------------------- string qualifier = context->getMessage()->getQualifier(); // No Qualifier -> fail //----------------- if (qualifier.length()==0) { stringstream ss; ss << "The input message did not have a qualifier. This is required to find a handler factory"; Logging::getLogger("wsb.libremote.intermediary.rpchandler")->errorStream() << ss.str(); throw ss.str(); } // No Matching Factory -> fail //----------------- else if (this->handlerFactories.count(qualifier)==0) { stringstream ss; ss << "The input qualifier has no registered Factory. This is required to handle the message"; Logging::getLogger("wsb.libremote.intermediary.rpchandler")->errorStream() << ss.str(); throw ss.str(); } // There is a Factory -> Proceed //-------------------- RPCHandlerFactory * factory = this->handlerFactories[qualifier]; //-- Instanciate handler RPCHandler * handler = factory->newInstance(context); Message * response = handler->handle(context); // If there is a response -> trigger //----------------- if (response != NULL) { throw ResponseException(response); } }
// VFALCO ARGH! returning a single std::string for the entire response? std::string ServerHandlerImp::processRequest (std::string const& request, beast::IP::Endpoint const& remoteIPAddress) { Json::Value jvRequest; { Json::Reader reader; if ((request.size () > 1000000) || ! reader.parse (request, jvRequest) || jvRequest.isNull () || ! jvRequest.isObject ()) { return createResponse (400, "Unable to parse request"); } } auto const role = getConfig ().getAdminRole (jvRequest, remoteIPAddress); Resource::Consumer usage; if (role == Config::ADMIN) usage = m_resourceManager.newAdminEndpoint (remoteIPAddress.to_string()); else usage = m_resourceManager.newInboundEndpoint(remoteIPAddress); if (usage.disconnect ()) return createResponse (503, "Server is overloaded"); // 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"); if (! method.isString ()) return createResponse (400, "method is not string"); std::string strMethod = method.asString (); if (strMethod.empty()) return createResponse (400, "method is empty"); // 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 == Config::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; RPCHandler rpcHandler (m_networkOPs); Resource::Charge loadType = Resource::feeReferenceRPC; m_journal.debug << "Query: " << strMethod << params; Json::Value const result (rpcHandler.doRpcCommand ( strMethod, params, role, loadType)); m_journal.debug << "Reply: " << result; usage.charge (loadType); response = JSONRPCReply (result, Json::Value (), id); return createResponse (200, response); }
// Stolen directly from RPCServerHandler std::string 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"); } } Config::Role const role (getConfig ().getAdminRole (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 == Config::FORBID) { // VFALCO TODO Needs implementing // FIXME Needs implementing // XXX This needs rate limiting to prevent brute forcing password. return HTTPReply (403, "Forbidden"); } // This code does all the work on the io_service thread and // has no rate-limiting based on source IP or anything. // This is a temporary safety if ((role != Config::ADMIN) && (getApp().getFeeTrack().isLoadedLocal())) { return HTTPReply (503, "Unable to service at this time"); } std::string response; m_journal.debug << "Query: " << strMethod << 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 m_journal.debug << "Reply: " << result; response = JSONRPCReply (result, Json::Value (), id); return createResponse (200, response); }
Json::Value WSConnection::invokeCommand (Json::Value& jvRequest) { if (getConsumer().disconnect ()) { disconnect (); return rpcError (rpcSLOW_DOWN); } // Requests without "command" are invalid. // if (!jvRequest.isMember (jss::command)) { Json::Value jvResult (Json::objectValue); jvResult[jss::type] = jss::response; jvResult[jss::status] = jss::error; jvResult[jss::error] = jss::missingCommand; jvResult[jss::request] = jvRequest; if (jvRequest.isMember (jss::id)) { jvResult[jss::id] = jvRequest[jss::id]; } getConsumer().charge (Resource::feeInvalidRPC); return jvResult; } Resource::Charge loadType = Resource::feeReferenceRPC; RPCHandler mRPCHandler (m_netOPs, std::dynamic_pointer_cast<InfoSub> (this->shared_from_this ())); Json::Value jvResult (Json::objectValue); Config::Role const role = m_isPublic ? Config::GUEST // Don't check on the public interface. : getConfig ().getAdminRole ( jvRequest, m_remoteAddress); if (Config::FORBID == role) { jvResult[jss::result] = rpcError (rpcFORBIDDEN); } else { jvResult[jss::result] = mRPCHandler.doCommand (jvRequest, role, loadType); } getConsumer().charge (loadType); if (getConsumer().warn ()) { jvResult[jss::warning] = jss::load; } // Currently we will simply unwrap errors returned by the RPC // API, in the future maybe we can make the responses // consistent. // // Regularize result. This is duplicate code. if (jvResult[jss::result].isMember (jss::error)) { jvResult = jvResult[jss::result]; jvResult[jss::status] = jss::error; jvResult[jss::request] = jvRequest; } else { jvResult[jss::status] = jss::success; } if (jvRequest.isMember (jss::id)) { jvResult[jss::id] = jvRequest[jss::id]; } jvResult[jss::type] = jss::response; return jvResult; }
// ========================================================================== // METHOD RPCRequestHandler::run // ========================================================================== int RPCRequestHandler::run (string &uri, string &postbody, value &inhdr, string &out, value &outhdr, value &env, tcpsocket &s) { try { DEBUG.storeFile ("RPCRequestHandler","postbody", postbody, "run"); CORE->log (log::debug, "RPC", "handle: %S %!" %format (uri, inhdr)); value indata; value res; string origin = "rpc"; uid_t uid = 0; RPCHandler hdl (sdb); indata.fromjson (postbody); if (inhdr.exists ("X-OpenCORE-Origin")) { origin = inhdr["X-OpenCORE-Origin"]; } CORE->log (log::debug, "RPC", "body: %!" %format (indata)); // Set up credentials if available s.getcredentials(); CORE->log (log::debug, "RPC", "credentials: %d %d %d", s.peer_uid, s.peer_gid, s.peer_pid); if (s.peer_pid == 0) { string peer_name = s.peer_name; if (peer_name == "127.0.0.1") { if (inhdr.exists ("X-Forwarded-For")) { peer_name = inhdr["X-Forwarded-For"]; } } if (origin.strchr ('/') >0) origin = origin.cutat ('/'); if (! origin) origin = "RPC"; origin.strcat ("/src=%s" %format (peer_name)); env["ip"] = s.peer_name = peer_name; } if (indata.exists ("header") && indata["header"].exists ("command")) { uri.strcat ("/%s" %format (indata["header"]["command"])); } res = hdl.handle (indata, s.peer_uid, origin); out = res.tojson (); if (inhdr.exists ("Accept-Encoding")) { string ae = inhdr["Accept-Encoding"]; if (ae.strstr ("deflate") >= 0) { unsigned long reslen = (out.strlen() * 1.05) + 12; char buf[reslen]; if (compress2 ((Bytef*) buf, &reslen, (const Bytef*) out.str(), out.strlen(), 4) == Z_OK) { outhdr["Content-Encoding"] = "deflate"; out.strcpy (buf+2, reslen-2); } else { log::write (log::warning, "RPC", "Compress error"); } } } outhdr["Content-type"] = "application/json"; } catch (...) { log::write (log::error, "RPC", "Exception caught"); } return HTTP_OK; }