rippled
Loading...
Searching...
No Matches
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 <xrpld/app/ledger/InboundLedgers.h>
21#include <xrpld/app/ledger/LedgerMaster.h>
22#include <xrpld/app/ledger/LedgerToJson.h>
23#include <xrpld/app/main/Application.h>
24#include <xrpld/app/misc/NetworkOPs.h>
25#include <xrpld/core/Config.h>
26#include <xrpld/core/JobQueue.h>
27#include <xrpld/net/InfoSub.h>
28#include <xrpld/perflog/PerfLog.h>
29#include <xrpld/rpc/Context.h>
30#include <xrpld/rpc/RPCHandler.h>
31#include <xrpld/rpc/Role.h>
32#include <xrpld/rpc/detail/Handler.h>
33#include <xrpld/rpc/detail/Tuning.h>
34#include <xrpl/basics/Log.h>
35#include <xrpl/basics/contract.h>
36#include <xrpl/json/Object.h>
37#include <xrpl/json/to_string.h>
38#include <xrpl/protocol/ErrorCodes.h>
39#include <xrpl/protocol/RPCErr.h>
40#include <xrpl/protocol/jss.h>
41#include <xrpl/resource/Fees.h>
42#include <atomic>
43#include <chrono>
44#include <variant>
45
46namespace ripple {
47namespace RPC {
48
49namespace {
50
132fillHandler(JsonContext& context, Handler const*& result)
133{
134 if (!isUnlimited(context.role))
135 {
136 // Count all jobs at jtCLIENT priority or higher.
137 int const jobCount = context.app.getJobQueue().getJobCountGE(jtCLIENT);
138 if (jobCount > Tuning::maxJobQueueClients)
139 {
140 JLOG(context.j.debug()) << "Too busy for command: " << jobCount;
141 return rpcTOO_BUSY;
142 }
143 }
144
145 if (!context.params.isMember(jss::command) &&
146 !context.params.isMember(jss::method))
147 return rpcCOMMAND_MISSING;
148 if (context.params.isMember(jss::command) &&
149 context.params.isMember(jss::method))
150 {
151 if (context.params[jss::command].asString() !=
152 context.params[jss::method].asString())
153 return rpcUNKNOWN_COMMAND;
154 }
155
156 std::string strCommand = context.params.isMember(jss::command)
157 ? context.params[jss::command].asString()
158 : context.params[jss::method].asString();
159
160 JLOG(context.j.trace()) << "COMMAND:" << strCommand;
161 JLOG(context.j.trace()) << "REQUEST:" << context.params;
162 auto handler = getHandler(
163 context.apiVersion, context.app.config().BETA_RPC_API, strCommand);
164
165 if (!handler)
166 return rpcUNKNOWN_COMMAND;
167
168 if (handler->role_ == Role::ADMIN && context.role != Role::ADMIN)
169 return rpcNO_PERMISSION;
170
171 error_code_i res = conditionMet(handler->condition_, context);
172 if (res != rpcSUCCESS)
173 {
174 return res;
175 }
176
177 result = handler;
178 return rpcSUCCESS;
179}
180
181template <class Object, class Method>
182Status
183callMethod(
184 JsonContext& context,
185 Method method,
186 std::string const& name,
187 Object& result)
188{
189 static std::atomic<std::uint64_t> requestId{0};
190 auto& perfLog = context.app.getPerfLog();
191 std::uint64_t const curId = ++requestId;
192 try
193 {
194 perfLog.rpcStart(name, curId);
195 auto v =
196 context.app.getJobQueue().makeLoadEvent(jtGENERIC, "cmd:" + name);
197
198 auto start = std::chrono::system_clock::now();
199 auto ret = method(context, result);
201
202 JLOG(context.j.debug())
203 << "RPC call " << name << " completed in "
204 << ((end - start).count() / 1000000000.0) << "seconds";
205 perfLog.rpcFinish(name, curId);
206 return ret;
207 }
208 catch (std::exception& e)
209 {
210 perfLog.rpcError(name, curId);
211 JLOG(context.j.info()) << "Caught throw: " << e.what();
212
213 if (context.loadType == Resource::feeReferenceRPC)
214 context.loadType = Resource::feeExceptionRPC;
215
216 inject_error(rpcINTERNAL, result);
217 return rpcINTERNAL;
218 }
219}
220
221} // namespace
222
223Status
225{
226 Handler const* handler = nullptr;
227 if (auto error = fillHandler(context, handler))
228 {
229 inject_error(error, result);
230 return error;
231 }
232
233 if (auto method = handler->valueMethod_)
234 {
235 if (!context.headers.user.empty() ||
236 !context.headers.forwardedFor.empty())
237 {
238 JLOG(context.j.debug())
239 << "start command: " << handler->name_
240 << ", user: " << context.headers.user
241 << ", forwarded for: " << context.headers.forwardedFor;
242
243 auto ret = callMethod(context, method, handler->name_, result);
244
245 JLOG(context.j.debug())
246 << "finish command: " << handler->name_
247 << ", user: " << context.headers.user
248 << ", forwarded for: " << context.headers.forwardedFor;
249
250 return ret;
251 }
252 else
253 {
254 auto ret = callMethod(context, method, handler->name_, result);
255 return ret;
256 }
257 }
258
259 return rpcUNKNOWN_COMMAND;
260}
261
262Role
263roleRequired(unsigned int version, bool betaEnabled, std::string const& method)
264{
265 auto handler = RPC::getHandler(version, betaEnabled, method);
266
267 if (!handler)
268 return Role::FORBID;
269
270 return handler->role_;
271}
272
273} // namespace RPC
274} // namespace ripple
Represents a JSON value.
Definition: json_value.h:147
Stream debug() const
Definition: Journal.h:317
T count(T... args)
T empty(T... args)
T end(T... args)
Status
Return codes from Backend operations.
static int constexpr maxJobQueueClients
Role roleRequired(unsigned int version, bool betaEnabled, std::string const &method)
Definition: RPCHandler.cpp:263
void inject_error(error_code_i code, JsonValue &json)
Add or update the json update to reflect the error code.
Definition: ErrorCodes.h:223
Status doCommand(RPC::JsonContext &context, Json::Value &result)
Execute an RPC command and store the results in a Json::Value.
Definition: RPCHandler.cpp:224
Handler const * getHandler(unsigned version, bool betaEnabled, std::string const &name)
Definition: Handler.cpp:310
error_code_i conditionMet(Condition condition_required, T &context)
Definition: Handler.h:82
Charge const feeReferenceRPC
Charge const feeExceptionRPC
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
error_code_i
Definition: ErrorCodes.h:40
@ rpcUNKNOWN_COMMAND
Definition: ErrorCodes.h:85
@ rpcTOO_BUSY
Definition: ErrorCodes.h:56
@ rpcSUCCESS
Definition: ErrorCodes.h:44
@ rpcINTERNAL
Definition: ErrorCodes.h:130
@ rpcCOMMAND_MISSING
Definition: ErrorCodes.h:102
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition: Role.cpp:124
Role
Indicates the level of administrative permission to grant.
Definition: Role.h:43
@ jtGENERIC
Definition: Job.h:87
@ jtCLIENT
Definition: Job.h:45
beast::Journal const j
Definition: Context.h:41
Method< Json::Value > valueMethod_
Definition: Handler.h:53
const char * name_
Definition: Handler.h:52
std::string_view forwardedFor
Definition: Context.h:61
T what(T... args)