xrpld
Loading...
Searching...
No Matches
RPCHandler.cpp
1#include <xrpld/rpc/RPCHandler.h>
2
3#include <xrpld/app/ledger/LedgerMaster.h> // IWYU pragma: keep
4#include <xrpld/app/main/Application.h>
5#include <xrpld/core/Config.h>
6#include <xrpld/rpc/Context.h>
7#include <xrpld/rpc/Role.h>
8#include <xrpld/rpc/Status.h>
9#include <xrpld/rpc/detail/Handler.h>
10#include <xrpld/rpc/detail/Tuning.h>
11
12#include <xrpl/basics/Log.h>
13#include <xrpl/core/Job.h>
14#include <xrpl/core/JobQueue.h>
15#include <xrpl/core/PerfLog.h>
16#include <xrpl/json/to_string.h> // IWYU pragma: keep
17#include <xrpl/protocol/ErrorCodes.h>
18#include <xrpl/protocol/jss.h>
19#include <xrpl/resource/Fees.h>
20
21#include <atomic>
22#include <chrono>
23#include <cstdint>
24#include <exception>
25#include <string>
26#include <string_view>
27
28namespace xrpl::rpc {
29
30namespace {
31
110
112fillHandler(JsonContext& context, Handler const*& result)
113{
114 if (!isUnlimited(context.role))
115 {
116 // Count all jobs at jtCLIENT priority or higher.
117 int const jobCount = context.app.getJobQueue().getJobCountGE(JtClient);
118 if (jobCount > tuning::kMaxJobQueueClients)
119 {
120 JLOG(context.j.debug()) << "Too busy for command: " << jobCount;
121 return RpcTooBusy;
122 }
123 }
124
125 if (!context.params.isMember(jss::command) && !context.params.isMember(jss::method))
126 return RpcCommandMissing;
127 if (context.params.isMember(jss::command) && context.params.isMember(jss::method))
128 {
129 if (context.params[jss::command].asString() != context.params[jss::method].asString())
130 return RpcUnknownCommand;
131 }
132
133 std::string const strCommand = context.params.isMember(jss::command)
134 ? context.params[jss::command].asString()
135 : context.params[jss::method].asString();
136
137 JLOG(context.j.trace()) << "COMMAND:" << strCommand;
138 JLOG(context.j.trace()) << "REQUEST:" << context.params;
139 auto handler = getHandler(context.apiVersion, context.app.config().betaRpcApi, strCommand);
140
141 if (handler == nullptr)
142 return RpcUnknownCommand;
143
144 if (handler->role == Role::ADMIN && context.role != Role::ADMIN)
145 return RpcNoPermission;
146
147 ErrorCodeI const res = conditionMet(handler->condition, context);
148 if (res != RpcSuccess)
149 {
150 return res;
151 }
152
153 result = handler;
154 return RpcSuccess;
155}
156
157Status
158callMethod(JsonContext& context, Handler::Method method, std::string_view name, json::Value& result)
159{
160 static std::atomic<std::uint64_t> kRequestId{0};
161 auto& perfLog = context.app.getPerfLog();
162 std::uint64_t const curId = ++kRequestId;
163 try
164 {
165 perfLog.rpcStart(name, curId);
166 auto v =
167 context.app.getJobQueue().makeLoadEvent(JtGeneric, std::string{"cmd:"}.append(name));
168
169 auto start = std::chrono::system_clock::now();
170 auto ret = method(context, result);
172
173 JLOG(context.j.debug()) << "RPC call " << name << " completed in "
174 << ((end - start).count() / 1000000000.0) << "seconds";
175 perfLog.rpcFinish(name, curId);
176 return ret;
177 }
178 catch (std::exception& e)
179 {
180 perfLog.rpcError(name, curId);
181 JLOG(context.j.info()) << "Caught throw: " << e.what();
182
183 if (context.loadType == resource::kFeeReferenceRpc)
184 context.loadType = resource::kFeeExceptionRpc;
185
186 injectError(RpcInternal, result);
187 return RpcInternal;
188 }
189}
190
191} // namespace
192
193Status
195{
196 Handler const* handler = nullptr;
197 if (auto error = fillHandler(context, handler))
198 {
199 injectError(error, result);
200 return error;
201 }
202
203 // No null check on the method: Handler::Method has no default constructor, so
204 // every entry in the dispatch table names one.
205 if (!context.headers.user.empty() || !context.headers.forwardedFor.empty())
206 {
207 JLOG(context.j.debug()) << "start command: " << handler->name
208 << ", user: " << context.headers.user
209 << ", forwarded for: " << context.headers.forwardedFor;
210
211 auto const ret = callMethod(context, handler->valueMethod, handler->name, result);
212
213 JLOG(context.j.debug()) << "finish command: " << handler->name
214 << ", user: " << context.headers.user
215 << ", forwarded for: " << context.headers.forwardedFor;
216
217 return ret;
218 }
219
220 return callMethod(context, handler->valueMethod, handler->name, result);
221}
222
223Role
224roleRequired(unsigned int version, bool betaEnabled, std::string_view method)
225{
226 auto handler = rpc::getHandler(version, betaEnabled, method);
227
228 if (handler == nullptr)
229 return Role::FORBID;
230
231 return handler->role;
232}
233
234} // namespace xrpl::rpc
Stream debug() const
Definition Journal.h:344
Represents a JSON value.
Definition json_value.h:117
The function a handler dispatches to.
Definition Handler.h:48
T empty(T... args)
T end(T... args)
Charge const kFeeReferenceRpc
Charge const kFeeExceptionRpc
static constexpr int kMaxJobQueueClients
API version numbers used in later API versions.
Definition ApiVersion.h:36
ErrorCodeI conditionMet(Condition conditionRequired, T &context)
Definition Handler.h:139
Role roleRequired(unsigned int version, bool betaEnabled, std::string_view method)
Handler const * getHandler(unsigned version, bool betaEnabled, std::string_view name)
Definition Handler.cpp:672
void injectError(ErrorCodeI code, json::Value &json)
Add or update the json update to reflect the error code.
Status doCommand(rpc::JsonContext &context, json::Value &result)
Execute an RPC command and store the results in a json::Value.
ErrorCodeI
Definition ErrorCodes.h:23
@ RpcInternal
Definition ErrorCodes.h:113
@ RpcSuccess
Definition ErrorCodes.h:27
@ RpcCommandMissing
Definition ErrorCodes.h:85
@ RpcTooBusy
Definition ErrorCodes.h:39
@ RpcNoPermission
Definition ErrorCodes.h:36
@ RpcUnknownCommand
Definition ErrorCodes.h:68
Role
Indicates the level of administrative permission to grant.
Definition Role.h:27
@ ADMIN
Definition Role.h:27
@ FORBID
Definition Role.h:27
@ JtGeneric
Definition Job.h:73
@ JtClient
Definition Job.h:31
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition Role.cpp:115
beast::Journal const j
Definition Context.h:28
Method valueMethod
Definition Handler.h:87
std::string_view name
Definition Handler.h:86
std::string_view forwardedFor
Definition Context.h:48
Status represents the results of an operation that might fail.
Definition Status.h:27
T what(T... args)