rippled
RPCHandler.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/ledger/InboundLedgers.h>
21 #include <ripple/app/ledger/LedgerMaster.h>
22 #include <ripple/app/ledger/LedgerToJson.h>
23 #include <ripple/app/main/Application.h>
24 #include <ripple/app/misc/NetworkOPs.h>
25 #include <ripple/app/reporting/P2pProxy.h>
26 #include <ripple/basics/Log.h>
27 #include <ripple/basics/PerfLog.h>
28 #include <ripple/basics/contract.h>
29 #include <ripple/core/Config.h>
30 #include <ripple/core/JobQueue.h>
31 #include <ripple/json/Object.h>
32 #include <ripple/json/to_string.h>
33 #include <ripple/net/InfoSub.h>
34 #include <ripple/net/RPCErr.h>
35 #include <ripple/protocol/ErrorCodes.h>
36 #include <ripple/protocol/jss.h>
37 #include <ripple/resource/Fees.h>
38 #include <ripple/rpc/Context.h>
39 #include <ripple/rpc/RPCHandler.h>
40 #include <ripple/rpc/Role.h>
41 #include <ripple/rpc/impl/Handler.h>
42 #include <ripple/rpc/impl/Tuning.h>
43 #include <atomic>
44 #include <chrono>
45 #include <variant>
46 
47 namespace ripple {
48 namespace RPC {
49 
50 namespace {
51 
133 fillHandler(JsonContext& context, Handler const*& result)
134 {
135  if (!isUnlimited(context.role))
136  {
137  // Count all jobs at jtCLIENT priority or higher.
138  int const jobCount = context.app.getJobQueue().getJobCountGE(jtCLIENT);
139  if (jobCount > Tuning::maxJobQueueClients)
140  {
141  JLOG(context.j.debug()) << "Too busy for command: " << jobCount;
142  return rpcTOO_BUSY;
143  }
144  }
145 
146  if (!context.params.isMember(jss::command) &&
147  !context.params.isMember(jss::method))
148  return rpcCOMMAND_MISSING;
149  if (context.params.isMember(jss::command) &&
150  context.params.isMember(jss::method))
151  {
152  if (context.params[jss::command].asString() !=
153  context.params[jss::method].asString())
154  return rpcUNKNOWN_COMMAND;
155  }
156 
157  std::string strCommand = context.params.isMember(jss::command)
158  ? context.params[jss::command].asString()
159  : context.params[jss::method].asString();
160 
161  JLOG(context.j.trace()) << "COMMAND:" << strCommand;
162  JLOG(context.j.trace()) << "REQUEST:" << context.params;
163  auto handler = getHandler(
164  context.apiVersion, context.app.config().BETA_RPC_API, strCommand);
165 
166  if (!handler)
167  return rpcUNKNOWN_COMMAND;
168 
169  if (handler->role_ == Role::ADMIN && context.role != Role::ADMIN)
170  return rpcNO_PERMISSION;
171 
172  error_code_i res = conditionMet(handler->condition_, context);
173  if (res != rpcSUCCESS)
174  {
175  return res;
176  }
177 
178  result = handler;
179  return rpcSUCCESS;
180 }
181 
182 template <class Object, class Method>
183 Status
184 callMethod(
185  JsonContext& context,
186  Method method,
187  std::string const& name,
188  Object& result)
189 {
190  static std::atomic<std::uint64_t> requestId{0};
191  auto& perfLog = context.app.getPerfLog();
192  std::uint64_t const curId = ++requestId;
193  try
194  {
195  perfLog.rpcStart(name, curId);
196  auto v =
197  context.app.getJobQueue().makeLoadEvent(jtGENERIC, "cmd:" + name);
198 
199  auto start = std::chrono::system_clock::now();
200  auto ret = method(context, result);
202 
203  JLOG(context.j.debug())
204  << "RPC call " << name << " completed in "
205  << ((end - start).count() / 1000000000.0) << "seconds";
206  perfLog.rpcFinish(name, curId);
207  return ret;
208  }
209  catch (ReportingShouldProxy&)
210  {
211  result = forwardToP2p(context);
212  return rpcSUCCESS;
213  }
214  catch (std::exception& e)
215  {
216  perfLog.rpcError(name, curId);
217  JLOG(context.j.info()) << "Caught throw: " << e.what();
218 
219  if (context.loadType == Resource::feeReferenceRPC)
220  context.loadType = Resource::feeExceptionRPC;
221 
222  inject_error(rpcINTERNAL, result);
223  return rpcINTERNAL;
224  }
225 }
226 
227 } // namespace
228 
229 void
231 {
232  if (context.app.config().reporting())
233  {
234  Json::Value warnings{Json::arrayValue};
235  Json::Value& w = warnings.append(Json::objectValue);
236  w[jss::id] = warnRPC_REPORTING;
237  w[jss::message] =
238  "This is a reporting server. "
239  " The default behavior of a reporting server is to only"
240  " return validated data. If you are looking for not yet"
241  " validated data, include \"ledger_index : current\""
242  " in your request, which will cause this server to forward"
243  " the request to a p2p node. If the forward is successful"
244  " the response will include \"forwarded\" : \"true\"";
245  result[jss::warnings] = std::move(warnings);
246  }
247 }
248 
249 Status
251 {
252  if (shouldForwardToP2p(context))
253  {
254  result = forwardToP2p(context);
255  injectReportingWarning(context, result);
256  // this return value is ignored
257  return rpcSUCCESS;
258  }
259  Handler const* handler = nullptr;
260  if (auto error = fillHandler(context, handler))
261  {
262  inject_error(error, result);
263  return error;
264  }
265 
266  if (auto method = handler->valueMethod_)
267  {
268  if (!context.headers.user.empty() ||
269  !context.headers.forwardedFor.empty())
270  {
271  JLOG(context.j.debug())
272  << "start command: " << handler->name_
273  << ", user: " << context.headers.user
274  << ", forwarded for: " << context.headers.forwardedFor;
275 
276  auto ret = callMethod(context, method, handler->name_, result);
277 
278  JLOG(context.j.debug())
279  << "finish command: " << handler->name_
280  << ", user: " << context.headers.user
281  << ", forwarded for: " << context.headers.forwardedFor;
282 
283  return ret;
284  }
285  else
286  {
287  auto ret = callMethod(context, method, handler->name_, result);
288  injectReportingWarning(context, result);
289  return ret;
290  }
291  }
292 
293  return rpcUNKNOWN_COMMAND;
294 }
295 
296 Role
297 roleRequired(unsigned int version, bool betaEnabled, std::string const& method)
298 {
299  auto handler = RPC::getHandler(version, betaEnabled, method);
300 
301  if (!handler)
302  return Role::FORBID;
303 
304  return handler->role_;
305 }
306 
307 } // namespace RPC
308 } // namespace ripple
ripple::RPC::JsonContext
Definition: Context.h:53
std::string
STL class.
ripple::jtCLIENT
@ jtCLIENT
Definition: Job.h:45
std::exception
STL class.
ripple::RPC::JsonContext::Headers::user
boost::string_view user
Definition: Context.h:60
ripple::RPC::getHandler
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:243
Json::arrayValue
@ arrayValue
array value (ordered list)
Definition: json_value.h:42
ripple::RPC::roleRequired
Role roleRequired(unsigned int version, bool betaEnabled, std::string const &method)
Definition: RPCHandler.cpp:297
ripple::RPC::injectReportingWarning
void injectReportingWarning(RPC::JsonContext &context, Json::Value &result)
Definition: RPCHandler.cpp:230
ripple::rpcTOO_BUSY
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
ripple::Resource::feeReferenceRPC
const Charge feeReferenceRPC
ripple::RPC::Handler::name_
const char * name_
Definition: Handler.h:51
ripple::RPC::JsonContext::headers
Headers headers
Definition: Context.h:66
ripple::error_code_i
error_code_i
Definition: ErrorCodes.h:40
ripple::RPC::Context::j
const beast::Journal j
Definition: Context.h:41
ripple::RPC::doCommand
Status doCommand(RPC::JsonContext &context, Json::Value &result)
Execute an RPC command and store the results in a Json::Value.
Definition: RPCHandler.cpp:250
ripple::rpcSUCCESS
@ rpcSUCCESS
Definition: ErrorCodes.h:44
ripple::warnRPC_REPORTING
@ warnRPC_REPORTING
Definition: ErrorCodes.h:157
Json::Value::append
Value & append(const Value &value)
Append value to array at the end.
Definition: json_value.cpp:882
ripple::Config::reporting
bool reporting() const
Definition: Config.h:337
ripple::RPC::Handler
Definition: Handler.h:46
ripple::Role::ADMIN
@ ADMIN
Json::objectValue
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:43
chrono
ripple::Application::config
virtual Config & config()=0
ripple::jtGENERIC
@ jtGENERIC
Definition: Job.h:88
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
ripple::Role::FORBID
@ FORBID
std::uint64_t
atomic
ripple::rpcCOMMAND_MISSING
@ rpcCOMMAND_MISSING
Definition: ErrorCodes.h:102
ripple::rpcINTERNAL
@ rpcINTERNAL
Definition: ErrorCodes.h:130
ripple::forwardToP2p
Json::Value forwardToP2p(RPC::JsonContext &context)
Forward a JSON request to a p2p node and return the response.
Definition: P2pProxy.cpp:28
ripple::isUnlimited
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:124
ripple::NodeStore::Status
Status
Return codes from Backend operations.
Definition: nodestore/Types.h:44
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::RPC::Handler::valueMethod_
Method< Json::Value > valueMethod_
Definition: Handler.h:52
ripple::rpcUNKNOWN_COMMAND
@ rpcUNKNOWN_COMMAND
Definition: ErrorCodes.h:85
ripple::shouldForwardToP2p
bool shouldForwardToP2p(RPC::JsonContext &context)
Whether a request should be forwarded, based on request parameters.
Definition: P2pProxy.cpp:45
ripple::RPC::conditionMet
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:78
ripple::rpcNO_PERMISSION
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
ripple::Resource::feeExceptionRPC
const Charge feeExceptionRPC
ripple::RPC::JsonContext::Headers::forwardedFor
boost::string_view forwardedFor
Definition: Context.h:61
std::count
T count(T... args)
beast::Journal::debug
Stream debug() const
Definition: Journal.h:315
std::end
T end(T... args)
ripple::RPC::inject_error
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition: ErrorCodes.h:212
ripple::RPC::Tuning::maxJobQueueClients
static constexpr int maxJobQueueClients
Definition: rpc/impl/Tuning.h:64
ripple::Role
Role
Indicates the level of administrative permission to grant.
Definition: Role.h:43
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
variant
std::chrono::system_clock::now
T now(T... args)