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