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/LedgerMaster.h>
21 #include <ripple/app/main/Application.h>
22 #include <ripple/app/misc/NetworkOPs.h>
23 #include <ripple/app/reporting/P2pProxy.h>
24 #include <ripple/basics/Log.h>
25 #include <ripple/basics/PerfLog.h>
26 #include <ripple/basics/contract.h>
27 #include <ripple/core/Config.h>
28 #include <ripple/core/JobQueue.h>
29 #include <ripple/json/Object.h>
30 #include <ripple/json/to_string.h>
31 #include <ripple/net/InfoSub.h>
32 #include <ripple/net/RPCErr.h>
33 #include <ripple/protocol/jss.h>
34 #include <ripple/resource/Fees.h>
35 #include <ripple/rpc/RPCHandler.h>
36 #include <ripple/rpc/Role.h>
37 #include <ripple/rpc/impl/Handler.h>
38 #include <ripple/rpc/impl/Tuning.h>
39 #include <atomic>
40 #include <chrono>
41 
42 namespace ripple {
43 namespace RPC {
44 
45 namespace {
46 
128 fillHandler(JsonContext& context, Handler const*& result)
129 {
130  if (!isUnlimited(context.role))
131  {
132  // Count all jobs at jtCLIENT priority or higher.
133  int const jobCount = context.app.getJobQueue().getJobCountGE(jtCLIENT);
134  if (jobCount > Tuning::maxJobQueueClients)
135  {
136  JLOG(context.j.debug()) << "Too busy for command: " << jobCount;
137  return rpcTOO_BUSY;
138  }
139  }
140 
141  if (!context.params.isMember(jss::command) &&
142  !context.params.isMember(jss::method))
143  return rpcCOMMAND_MISSING;
144  if (context.params.isMember(jss::command) &&
145  context.params.isMember(jss::method))
146  {
147  if (context.params[jss::command].asString() !=
148  context.params[jss::method].asString())
149  return rpcUNKNOWN_COMMAND;
150  }
151 
152  std::string strCommand = context.params.isMember(jss::command)
153  ? context.params[jss::command].asString()
154  : context.params[jss::method].asString();
155 
156  JLOG(context.j.trace()) << "COMMAND:" << strCommand;
157  JLOG(context.j.trace()) << "REQUEST:" << context.params;
158  auto handler = getHandler(
159  context.apiVersion, context.app.config().BETA_RPC_API, strCommand);
160 
161  if (!handler)
162  return rpcUNKNOWN_COMMAND;
163 
164  if (handler->role_ == Role::ADMIN && context.role != Role::ADMIN)
165  return rpcNO_PERMISSION;
166 
167  error_code_i res = conditionMet(handler->condition_, context);
168  if (res != rpcSUCCESS)
169  {
170  return res;
171  }
172 
173  result = handler;
174  return rpcSUCCESS;
175 }
176 
177 template <class Object, class Method>
178 Status
179 callMethod(
180  JsonContext& context,
181  Method method,
182  std::string const& name,
183  Object& result)
184 {
185  static std::atomic<std::uint64_t> requestId{0};
186  auto& perfLog = context.app.getPerfLog();
187  std::uint64_t const curId = ++requestId;
188  try
189  {
190  perfLog.rpcStart(name, curId);
191  auto v =
192  context.app.getJobQueue().makeLoadEvent(jtGENERIC, "cmd:" + name);
193 
194  auto start = std::chrono::system_clock::now();
195  auto ret = method(context, result);
197 
198  JLOG(context.j.debug())
199  << "RPC call " << name << " completed in "
200  << ((end - start).count() / 1000000000.0) << "seconds";
201  perfLog.rpcFinish(name, curId);
202  return ret;
203  }
204  catch (ReportingShouldProxy&)
205  {
206  result = forwardToP2p(context);
207  return rpcSUCCESS;
208  }
209  catch (std::exception& e)
210  {
211  perfLog.rpcError(name, curId);
212  JLOG(context.j.info()) << "Caught throw: " << e.what();
213 
214  if (context.loadType == Resource::feeReferenceRPC)
215  context.loadType = Resource::feeExceptionRPC;
216 
217  inject_error(rpcINTERNAL, result);
218  return rpcINTERNAL;
219  }
220 }
221 
222 } // namespace
223 
224 void
226 {
227  if (context.app.config().reporting())
228  {
229  Json::Value warnings{Json::arrayValue};
230  Json::Value& w = warnings.append(Json::objectValue);
231  w[jss::id] = warnRPC_REPORTING;
232  w[jss::message] =
233  "This is a reporting server. "
234  " The default behavior of a reporting server is to only"
235  " return validated data. If you are looking for not yet"
236  " validated data, include \"ledger_index : current\""
237  " in your request, which will cause this server to forward"
238  " the request to a p2p node. If the forward is successful"
239  " the response will include \"forwarded\" : \"true\"";
240  result[jss::warnings] = std::move(warnings);
241  }
242 }
243 
244 Status
246 {
247  if (shouldForwardToP2p(context))
248  {
249  result = forwardToP2p(context);
250  injectReportingWarning(context, result);
251  // this return value is ignored
252  return rpcSUCCESS;
253  }
254  Handler const* handler = nullptr;
255  if (auto error = fillHandler(context, handler))
256  {
257  inject_error(error, result);
258  return error;
259  }
260 
261  if (auto method = handler->valueMethod_)
262  {
263  if (!context.headers.user.empty() ||
264  !context.headers.forwardedFor.empty())
265  {
266  JLOG(context.j.debug())
267  << "start command: " << handler->name_
268  << ", user: " << context.headers.user
269  << ", forwarded for: " << context.headers.forwardedFor;
270 
271  auto ret = callMethod(context, method, handler->name_, result);
272 
273  JLOG(context.j.debug())
274  << "finish command: " << handler->name_
275  << ", user: " << context.headers.user
276  << ", forwarded for: " << context.headers.forwardedFor;
277 
278  return ret;
279  }
280  else
281  {
282  auto ret = callMethod(context, method, handler->name_, result);
283  injectReportingWarning(context, result);
284  return ret;
285  }
286  }
287 
288  return rpcUNKNOWN_COMMAND;
289 }
290 
291 Role
292 roleRequired(unsigned int version, bool betaEnabled, std::string const& method)
293 {
294  auto handler = RPC::getHandler(version, betaEnabled, method);
295 
296  if (!handler)
297  return Role::FORBID;
298 
299  return handler->role_;
300 }
301 
302 } // namespace RPC
303 } // 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:242
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:292
ripple::RPC::injectReportingWarning
void injectReportingWarning(RPC::JsonContext &context, Json::Value &result)
Definition: RPCHandler.cpp:225
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:245
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:316
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:196
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
std::chrono::system_clock::now
T now(T... args)