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