xrpld
Loading...
Searching...
No Matches
GRPCServer.cpp
1#include <xrpld/app/main/GRPCServer.h>
2
3#include <xrpld/app/ledger/LedgerMaster.h> // IWYU pragma: keep
4#include <xrpld/app/main/Application.h>
5#include <xrpld/rpc/Context.h>
6#include <xrpld/rpc/GRPCHandlers.h>
7#include <xrpld/rpc/Role.h>
8#include <xrpld/rpc/detail/Handler.h>
9
10#include <xrpl/basics/FileUtilities.h>
11#include <xrpl/basics/Log.h>
12#include <xrpl/basics/StringUtilities.h>
13#include <xrpl/basics/contract.h>
14#include <xrpl/beast/core/CurrentThreadName.h>
15#include <xrpl/beast/net/IPAddressConversion.h>
16#include <xrpl/beast/net/IPEndpoint.h>
17#include <xrpl/beast/utility/instrumentation.h>
18#include <xrpl/config/BasicConfig.h>
19#include <xrpl/config/Constants.h>
20#include <xrpl/core/Job.h>
21#include <xrpl/core/JobQueue.h>
22#include <xrpl/protocol/ErrorCodes.h>
23#include <xrpl/resource/Charge.h>
24#include <xrpl/resource/Consumer.h>
25#include <xrpl/resource/Fees.h>
26#include <xrpl/server/InfoSub.h>
27
28#include <boost/asio/ip/address.hpp>
29#include <boost/asio/ip/tcp.hpp>
30#include <boost/icl/interval_set.hpp>
31
32#include <grpc/grpc_security_constants.h>
33#include <grpcpp/completion_queue.h>
34#include <grpcpp/security/server_credentials.h>
35#include <grpcpp/server_builder.h>
36#include <grpcpp/support/status.h>
37#include <org/xrpl/rpc/v1/get_ledger.pb.h>
38#include <org/xrpl/rpc/v1/get_ledger_data.pb.h>
39#include <org/xrpl/rpc/v1/get_ledger_diff.pb.h>
40#include <org/xrpl/rpc/v1/get_ledger_entry.pb.h>
41#include <org/xrpl/rpc/v1/xrp_ledger.grpc.pb.h>
42
43#include <algorithm>
44#include <cstddef>
45#include <cstdint>
46#include <exception>
47#include <memory>
48#include <optional>
49#include <sstream>
50#include <stdexcept>
51#include <string>
52#include <system_error>
53#include <utility>
54#include <vector>
55
56namespace xrpl {
57
58namespace {
59
60// helper function. converts string to endpoint. handles ipv4 and ipv6, with or
61// without port, with or without prepended scheme
62std::optional<boost::asio::ip::tcp::endpoint>
63getEndpoint(std::string const& peer)
64{
65 try
66 {
67 std::size_t const first = peer.find_first_of(':');
68 std::size_t const last = peer.find_last_of(':');
69 std::string peerClean(peer);
70 if (first != last)
71 {
72 peerClean = peer.substr(first + 1);
73 }
74
75 std::optional<beast::ip::Endpoint> endpoint =
77 if (endpoint)
78 return beast::ip::toAsioEndpoint(endpoint.value());
79 }
80 catch (std::exception const&) // NOLINT(bugprone-empty-catch)
81 {
82 }
83 return {};
84}
85
86} // namespace
87
88template <class Request, class Response>
90 org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService& service,
91 grpc::ServerCompletionQueue& cq,
92 Application& app,
96 rpc::Condition requiredCondition,
97 resource::Charge loadType,
98 std::vector<boost::asio::ip::address> const& secureGatewayIPs)
99 : service_(service)
100 , cq_(cq)
101 , finished_(false)
102 , app_(app)
103 , responder_(&ctx_)
104 , bindListener_(std::move(bindListener))
105 , handler_(std::move(handler))
106 , forward_(std::move(forward))
107 , requiredCondition_(requiredCondition)
108 , loadType_(std::move(loadType))
109 , secureGatewayIPs_(secureGatewayIPs)
110{
111 // Bind a listener. When a request is received, "this" will be returned
112 // from CompletionQueue::Next
114}
115
116template <class Request, class Response>
131
132template <class Request, class Response>
133void
135{
136 // sanity check
137 BOOST_ASSERT(!finished_);
138
140
141 // Need to set finished to true before processing the response,
142 // because as soon as the response is posted to the completion
143 // queue (via responder_.Finish(...) or responder_.FinishWithError(...)),
144 // the CallData object is returned as a tag in handleRpcs().
145 // handleRpcs() checks the finished variable, and if true, destroys
146 // the object. Setting finished to true before calling process
147 // ensures that finished is always true when this CallData object
148 // is returned as a tag in handleRpcs(), after sending the response
149 finished_ = true;
150 auto coro = app_.getJobQueue().postCoro(
151 JobType::JtRpc, "gRPC-Client", [thisShared](std::shared_ptr<JobQueue::Coro> coro) {
152 thisShared->process(coro);
153 });
154
155 // If coro is null, then the JobQueue has already been shutdown
156 if (!coro)
157 {
158 grpc::Status const status{grpc::StatusCode::INTERNAL, "Job Queue is already stopped"};
159 responder_.FinishWithError(status, this);
160 }
161}
162
163template <class Request, class Response>
164void
166{
167 try
168 {
169 auto usage = getUsage();
170 bool const isUnlimited = clientIsUnlimited();
171 if (!isUnlimited && usage.disconnect(app_.getJournal("gRPCServer")))
172 {
173 grpc::Status const status{
174 grpc::StatusCode::RESOURCE_EXHAUSTED, "usage balance exceeds threshold"};
175 responder_.FinishWithError(status, this);
176 }
177 else
178 {
179 auto loadType = getLoadType();
180 usage.charge(loadType);
181 auto role = getRole(isUnlimited);
182
183 {
184 std::stringstream toLog;
185 toLog << "role = " << (int)role;
186
187 toLog << " address = ";
188 if (auto clientIp = getClientIpAddress())
189 toLog << clientIp.value();
190
191 toLog << " user = ";
192 if (auto user = getUser())
193 toLog << user.value();
194 toLog << " isUnlimited = " << isUnlimited;
195
196 JLOG(app_.getJournal("GRPCServer::Calldata").debug()) << toLog.str();
197 }
198
200 {app_.getJournal("gRPCServer"),
201 app_,
202 loadType,
203 app_.getOPs(),
204 app_.getLedgerMaster(),
205 usage,
206 role,
207 coro,
210 request_};
211
212 // Make sure we can currently handle the rpc
213 ErrorCodeI const conditionMetRes = rpc::conditionMet(requiredCondition_, context);
214
215 if (conditionMetRes != RpcSuccess)
216 {
217 rpc::ErrorInfo const errorInfo = rpc::getErrorInfo(conditionMetRes);
218 grpc::Status const status{
219 grpc::StatusCode::FAILED_PRECONDITION, errorInfo.message.cStr()};
220 responder_.FinishWithError(status, this);
221 }
222 else
223 {
226 responder_.Finish(result.first, result.second, this);
227 }
228 }
229 }
230 catch (std::exception const& ex)
231 {
232 grpc::Status const status{grpc::StatusCode::INTERNAL, ex.what()};
233 responder_.FinishWithError(status, this);
234 }
235}
236
237template <class Request, class Response>
238bool
243
244template <class Request, class Response>
250
251template <class Request, class Response>
252Role
254{
255 if (isUnlimited)
256 {
257 return Role::IDENTIFIED;
258 }
259
260 return Role::USER;
261}
262
263template <class Request, class Response>
266{
267 if (auto descriptor = Request::GetDescriptor()->FindFieldByName("user"))
268 {
269 std::string user = Request::GetReflection()->GetString(request_, descriptor);
270 if (!user.empty())
271 {
272 return user;
273 }
274 }
275 return {};
276}
277
278template <class Request, class Response>
281{
282 auto endpoint = getClientEndpoint();
283 if (endpoint)
284 return endpoint->address();
285 return {};
286}
287
288template <class Request, class Response>
291{
292 return xrpl::getEndpoint(ctx_.peer());
293}
294
295template <class Request, class Response>
296bool
298{
299 if (!getUser())
300 return false;
301 auto clientIp = getClientIpAddress();
302 if (clientIp)
303 {
304 for (auto& ip : secureGatewayIPs_)
305 {
306 if (ip == clientIp)
307 return true;
308 }
309 }
310 return false;
311}
312
313template <class Request, class Response>
314void
316{
317 if (isUnlimited)
318 {
319 if (auto descriptor = Response::GetDescriptor()->FindFieldByName("is_unlimited"))
320 {
321 Response::GetReflection()->SetBool(&response, descriptor, true);
322 }
323 }
324}
325
326template <class Request, class Response>
329{
330 auto endpoint = getClientEndpoint();
331 if (endpoint)
332 return app_.getResourceManager().newInboundEndpoint(beast::ip::fromAsio(endpoint.value()));
333 Throw<std::runtime_error>("Failed to get client endpoint");
334}
335
337 : app_(app), journal_(app_.getJournal("gRPC Server"))
338{
339 // if present, get endpoint from config
340 if (app_.config().exists(Sections::kPortGrpc))
341 {
342 Section const& section = app_.config().section(Sections::kPortGrpc);
343
344 auto const optIp = section.get(Keys::kIp);
345 if (!optIp)
346 return;
347
348 auto const optPort = section.get(Keys::kPort);
349 if (!optPort)
350 return;
351 try
352 {
353 boost::asio::ip::tcp::endpoint const endpoint(
354 boost::asio::ip::make_address(*optIp), std::stoi(*optPort));
355
356 std::stringstream ss;
357 ss << endpoint;
358 serverAddress_ = ss.str();
359 }
360 catch (std::exception const&)
361 {
362 JLOG(journal_.error()) << "Error setting grpc server address";
363 Throw<std::runtime_error>("Error setting grpc server address");
364 }
365
366 auto const optSecureGateway = section.get(Keys::kSecureGateway);
367 if (optSecureGateway)
368 {
369 try
370 {
371 std::stringstream ss{*optSecureGateway};
372 std::string ip;
373 while (std::getline(ss, ip, ','))
374 {
375 ip = trimWhitespace(ip);
376 auto const addr = boost::asio::ip::make_address(ip);
377
378 if (addr.is_unspecified())
379 {
380 JLOG(journal_.error()) << "Can't pass unspecified IP in "
381 << "secure_gateway section of port_grpc";
382 Throw<std::runtime_error>("Unspecified IP in secure_gateway section");
383 }
384
385 secureGatewayIPs_.emplace_back(addr);
386 }
387 }
388 catch (std::exception const&)
389 {
390 JLOG(journal_.error()) << "Error parsing secure gateway IPs for grpc server";
391 Throw<std::runtime_error>("Error parsing secure_gateway section");
392 }
393 }
394
395 // Read TLS certificate configuration (optional)
396 sslCertPath_ = section.get(Keys::kSslCert);
397 sslKeyPath_ = section.get(Keys::kSslKey);
400
401 // If cert or key is specified, both must be specified
402 if (sslCertPath_.has_value() || sslKeyPath_.has_value())
403 {
404 if (!sslCertPath_.has_value() || !sslKeyPath_.has_value())
405 {
406 JLOG(journal_.error())
407 << "Both ssl_cert and ssl_key must be specified for gRPC TLS";
408 Throw<std::runtime_error>("Incomplete TLS configuration for gRPC");
409 }
410 JLOG(journal_.info()) << "gRPC TLS enabled with certificate: " << *sslCertPath_;
411 }
412
413 // Validate TLS configuration consistency: ssl_cert_chain only makes sense when TLS is
414 // enabled
415 if (sslCertChainPath_.has_value() &&
416 (!sslCertPath_.has_value() || !sslKeyPath_.has_value()))
417 {
418 JLOG(journal_.error())
419 << "ssl_cert_chain specified for gRPC without both ssl_cert and ssl_key; "
420 << "this is an invalid TLS configuration";
421 Throw<std::runtime_error>(
422 "Invalid gRPC TLS configuration: ssl_cert_chain requires both ssl_cert and "
423 "ssl_key");
424 }
425
426 // Validate TLS configuration consistency: ssl_client_ca only makes sense when TLS is
427 // enabled
428 if (sslClientCAPath_.has_value() && (!sslCertPath_.has_value() || !sslKeyPath_.has_value()))
429 {
430 JLOG(journal_.error())
431 << "ssl_client_ca specified for gRPC without both ssl_cert and ssl_key; "
432 << "this is an invalid TLS configuration";
433 Throw<std::runtime_error>(
434 "Invalid gRPC TLS configuration: ssl_client_ca requires both ssl_cert and ssl_key");
435 }
436 }
437}
438
439void
441{
442 JLOG(journal_.debug()) << "Shutting down";
443
444 // The below call cancels all "listeners" (CallData objects that are waiting
445 // for a request, as opposed to processing a request), and blocks until all
446 // requests being processed are completed. CallData objects in the midst of
447 // processing requests need to actually send data back to the client, via
448 // responder_.Finish(...) or responder_.FinishWithError(...), for this call
449 // to unblock. Each cancelled listener is returned via cq_.Next(...) with ok
450 // set to false
451 server_->Shutdown();
452 JLOG(journal_.debug()) << "Server has been shutdown";
453
454 // Always shutdown the completion queue after the server. This call allows
455 // cq_.Next() to return false, once all events posted to the completion
456 // queue have been processed. See handleRpcs() for more details.
457 cq_->Shutdown();
458 JLOG(journal_.debug()) << "Completion Queue has been shutdown";
459}
460
461void
463{
464 // This collection should really be an unordered_set. However, to delete
465 // from the unordered_set, we need a shared_ptr, but cq_.Next() (see below
466 // while loop) sets the tag to a raw pointer.
468
469 auto erase = [&requests](Processor* ptr) {
470 auto it = std::ranges::find_if(
471 requests, [ptr](std::shared_ptr<Processor>& sPtr) { return sPtr.get() == ptr; });
472 BOOST_ASSERT(it != requests.end());
473 it->swap(requests.back());
474 requests.pop_back();
475 };
476
477 void* tag = nullptr; // uniquely identifies a request.
478 bool ok = false;
479 // Block waiting to read the next event from the completion queue. The
480 // event is uniquely identified by its tag, which in this case is the
481 // memory address of a CallData instance.
482 // The return value of Next should always be checked. This return value
483 // tells us whether there is any kind of event or cq_ is shutting down.
484 // When cq_.Next(...) returns false, all work has been completed and the
485 // loop can exit. When the server is shutdown, each CallData object that is
486 // listening for a request is forcibly cancelled, and is returned by
487 // cq_->Next() with ok set to false. Then, each CallData object processing
488 // a request must complete (by sending data to the client), each of which
489 // will be returned from cq_->Next() with ok set to true. After all
490 // cancelled listeners and all CallData objects processing requests are
491 // returned via cq_->Next(), cq_->Next() will return false, causing the
492 // loop to exit.
493 while (cq_->Next(&tag, &ok))
494 {
495 auto ptr = static_cast<Processor*>(tag);
496 JLOG(journal_.trace()) << "Processing CallData object."
497 << " ptr = " << ptr << " ok = " << ok;
498
499 if (!ok)
500 {
501 JLOG(journal_.debug()) << "Request listener cancelled. "
502 << "Destroying object";
503 erase(ptr);
504 }
505 else
506 {
507 if (!ptr->isFinished())
508 {
509 JLOG(journal_.debug()) << "Received new request. Processing";
510 // ptr is now processing a request, so create a new CallData
511 // object to handle additional requests
512 auto cloned = ptr->clone();
513 requests.push_back(cloned);
514 // process the request
515 ptr->process();
516 }
517 else
518 {
519 JLOG(journal_.debug()) << "Sent response. Destroying object";
520 erase(ptr);
521 }
522 }
523 }
524 JLOG(journal_.debug()) << "Completion Queue drained";
525}
526
527// create a CallData instance for each RPC
530{
531 using rpc::Condition;
533
534 auto addToRequests = [&requests](auto callData) { requests.push_back(std::move(callData)); };
535
536 {
537 using cd =
539
540 addToRequests(
542 service_,
543 *cq_,
544 app_,
545 &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedger,
547 &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedger,
548 Condition::NoCondition,
551 }
552 {
553 using cd = CallData<
554 org::xrpl::rpc::v1::GetLedgerDataRequest,
555 org::xrpl::rpc::v1::GetLedgerDataResponse>;
556
557 addToRequests(
559 service_,
560 *cq_,
561 app_,
562 &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedgerData,
564 &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedgerData,
565 Condition::NoCondition,
568 }
569 {
570 using cd = CallData<
571 org::xrpl::rpc::v1::GetLedgerDiffRequest,
572 org::xrpl::rpc::v1::GetLedgerDiffResponse>;
573
574 addToRequests(
576 service_,
577 *cq_,
578 app_,
579 &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedgerDiff,
581 &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedgerDiff,
582 Condition::NoCondition,
585 }
586 {
587 using cd = CallData<
588 org::xrpl::rpc::v1::GetLedgerEntryRequest,
589 org::xrpl::rpc::v1::GetLedgerEntryResponse>;
590
591 addToRequests(
593 service_,
594 *cq_,
595 app_,
596 &org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService::RequestGetLedgerEntry,
598 &org::xrpl::rpc::v1::XRPLedgerAPIService::Stub::GetLedgerEntry,
599 Condition::NoCondition,
602 }
603 return requests;
604}
605
608{
609 if (not sslCertPath_.has_value() or not sslKeyPath_.has_value())
610 {
611 JLOG(journal_.info()) << "Configuring gRPC server without TLS";
612 return grpc::InsecureServerCredentials();
613 }
614
615 JLOG(journal_.info()) << "Configuring gRPC server with TLS";
616
617 try
618 {
620 grpc::SslServerCredentialsOptions sslOpts;
621 grpc::SslServerCredentialsOptions::PemKeyCertPair keyCertPair;
622
623 std::string const certContents = getFileContents(ec, *sslCertPath_);
624 if (ec)
625 {
626 JLOG(journal_.error()) << "Failed to read gRPC SSL certificate file: " << *sslCertPath_
627 << " - " << ec.message(); // LCOV_EXCL_LINE
628 return nullptr;
629 }
630
631 std::string const keyContents = getFileContents(ec, *sslKeyPath_);
632 if (ec)
633 {
634 JLOG(journal_.error()) << "Failed to read gRPC SSL key file: " << *sslKeyPath_ << " - "
635 << ec.message(); // LCOV_EXCL_LINE
636 return nullptr;
637 }
638
639 keyCertPair.private_key = keyContents;
640
641 // Read intermediate CA certificates for server certificate chain (optional)
642 std::string certChainContents;
643 if (sslCertChainPath_.has_value())
644 {
645 certChainContents = getFileContents(ec, *sslCertChainPath_);
646 if (ec)
647 {
648 JLOG(journal_.error())
649 << "Failed to read gRPC SSL cert chain file: " << *sslCertChainPath_ << " - "
650 << ec.message(); // LCOV_EXCL_LINE
651 return nullptr;
652 }
653 }
654
655 // Read CA certificate for client verification (mTLS, optional)
656 if (sslClientCAPath_.has_value())
657 {
658 auto const clientCAContents = getFileContents(ec, *sslClientCAPath_);
659 if (ec)
660 {
661 JLOG(journal_.error())
662 << "Failed to read gRPC SSL client CA file: " << *sslClientCAPath_ << " - "
663 << ec.message(); // LCOV_EXCL_LINE
664 return nullptr;
665 }
666
667 if (clientCAContents.empty())
668 {
669 JLOG(journal_.error())
670 << "Empty/truncated gRPC SSL client CA file: " << *sslClientCAPath_
671 << " - failed to configure mutual TLS"; // LCOV_EXCL_LINE
672 return nullptr;
673 }
674
675 sslOpts.pem_root_certs = clientCAContents;
676 sslOpts.client_certificate_request =
677 GRPC_SSL_REQUEST_AND_REQUIRE_CLIENT_CERTIFICATE_AND_VERIFY;
678 JLOG(journal_.info()) << "gRPC mutual TLS enabled - client certificates will be "
679 "required and verified";
680 }
681
682 // Combine server cert with intermediate CA certs for complete chain
683 keyCertPair.cert_chain = certContents;
684 if (!certChainContents.empty())
685 {
686 keyCertPair.cert_chain += '\n' + certChainContents;
687 JLOG(journal_.info()) << "gRPC server certificate chain configured with "
688 "intermediate CA certificates"; // LCOV_EXCL_LINE
689 }
690
691 sslOpts.pem_key_cert_pairs.push_back(keyCertPair);
692
693 JLOG(journal_.info()) << "gRPC TLS credentials configured successfully"; // LCOV_EXCL_LINE
694 return grpc::SslServerCredentials(sslOpts);
695 }
696 catch (std::exception const& e)
697 {
698 JLOG(journal_.error()) << "Exception while configuring gRPC TLS: "
699 << e.what(); // LCOV_EXCL_LINE
700 return nullptr;
701 }
702}
703
704bool
706{
707 // if config does not specify a grpc server address, don't start
708 if (serverAddress_.empty())
709 return false;
710
711 // Determine TLS mode for logging
712 bool const tlsEnabled = sslCertPath_.has_value() && sslKeyPath_.has_value();
713 bool const mtlsEnabled = tlsEnabled && sslClientCAPath_.has_value();
714
715 std::string tlsMode = "without TLS";
716 if (mtlsEnabled)
717 {
718 tlsMode = "with mutual TLS (mTLS)";
719 }
720 else if (tlsEnabled)
721 {
722 tlsMode = "with TLS";
723 }
724
725 JLOG(journal_.info()) << "Starting gRPC server at " << serverAddress_ << " "
726 << tlsMode; // LCOV_EXCL_LINE
727
728 grpc::ServerBuilder builder;
729 int port = 0;
730
731 // Create credentials (TLS or insecure) based on configuration
733 if (!credentials)
734 {
735 JLOG(journal_.error()) << "Failed to create gRPC server credentials for " << serverAddress_
736 << " (TLS mode: " << tlsMode
737 << ") - server will not start"; // LCOV_EXCL_LINE
738 return false;
739 }
740
741 // Add listening port with appropriate credentials
742 builder.AddListeningPort(serverAddress_, credentials, &port);
743
744 // Register "service_" as the instance through which we'll communicate with
745 // clients. In this case it corresponds to an *asynchronous* service.
746 builder.RegisterService(&service_);
747
748 // Get hold of the completion queue used for the asynchronous communication
749 // with the gRPC runtime.
750 cq_ = builder.AddCompletionQueue();
751
752 // Finally assemble the server.
753 server_ = builder.BuildAndStart();
754 serverPort_ = static_cast<std::uint16_t>(port);
755
756 if (serverPort_ != 0u)
757 {
758 JLOG(journal_.info()) << "gRPC server started successfully on port " << serverPort_;
759 }
760 else
761 {
762 JLOG(journal_.error())
763 << "Failed to start gRPC server at " << serverAddress_ << " (TLS mode: " << tlsMode
764 << "); Possible causes: address already in use, invalid address format, or permission "
765 "denied"; // LCOV_EXCL_LINE
766 }
767
768 return static_cast<bool>(serverPort_);
769}
770
771boost::asio::ip::tcp::endpoint
773{
774 std::string const addr = serverAddress_.substr(0, serverAddress_.find_last_of(':'));
775 return boost::asio::ip::tcp::endpoint(boost::asio::ip::make_address(addr), serverPort_);
776}
777
778bool
780{
781 // Start the server and setup listeners
782 if (running_ = impl_.start(); running_)
783 {
784 thread_ = std::thread([this]() {
785 // Start the event loop and begin handling requests
786 beast::setCurrentThreadName("xrpld: grpc");
787 this->impl_.handleRpcs();
788 });
789 }
790 return running_;
791}
792
793void
795{
796 if (running_)
797 {
798 impl_.shutdown();
799 thread_.join();
800 running_ = false;
801 }
802}
803
805{
806 XRPL_ASSERT(!running_, "xrpl::GRPCServer::~GRPCServer : is not running");
807}
808
809boost::asio::ip::tcp::endpoint
811{
812 return impl_.getEndpoint();
813}
814
815} // namespace xrpl
T back(T... args)
static std::optional< Endpoint > fromStringChecked(std::string const &s)
Create an Endpoint from a string.
constexpr char const * cStr() const
Definition json_value.h:61
Forward< Request, Response > forward_
Definition GRPCServer.h:189
std::vector< boost::asio::ip::address > const & secureGatewayIPs_
Definition GRPCServer.h:197
std::optional< boost::asio::ip::address > getClientIpAddress()
org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService & service_
Definition GRPCServer.h:157
Handler< Request, Response > handler_
Definition GRPCServer.h:186
std::optional< std::string > getUser()
BindListener< Request, Response > bindListener_
Definition GRPCServer.h:183
Role getRole(bool isUnlimited)
resource::Consumer getUsage()
std::optional< boost::asio::ip::tcp::endpoint > getClientEndpoint()
resource::Charge getLoadType()
CallData(org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService &service, grpc::ServerCompletionQueue &cq, Application &app, BindListener< Request, Response > bindListener, Handler< Request, Response > handler, Forward< Request, Response > forward, rpc::Condition requiredCondition, resource::Charge loadType, std::vector< boost::asio::ip::address > const &secureGatewayIPs)
grpc::ServerAsyncResponseWriter< Response > responder_
Definition GRPCServer.h:180
std::shared_ptr< Processor > clone() override
void setIsUnlimited(Response &response, bool isUnlimited)
grpc::ServerCompletionQueue & cq_
Definition GRPCServer.h:160
rpc::Condition requiredCondition_
Definition GRPCServer.h:192
grpc::ServerContext ctx_
Definition GRPCServer.h:165
std::uint16_t serverPort_
Definition GRPCServer.h:76
Application & app_
Definition GRPCServer.h:73
std::optional< std::string > sslKeyPath_
Definition GRPCServer.h:82
std::optional< std::string > sslCertPath_
Definition GRPCServer.h:81
std::function< grpc::Status( org::xrpl::rpc::v1::XRPLedgerAPIService::Stub *, grpc::ClientContext *, Request, Response *)> Forward
Definition GRPCServer.h:110
std::vector< boost::asio::ip::address > secureGatewayIPs_
Definition GRPCServer.h:78
std::optional< std::string > sslCertChainPath_
Definition GRPCServer.h:83
std::unique_ptr< grpc::ServerCompletionQueue > cq_
Definition GRPCServer.h:64
std::vector< std::shared_ptr< Processor > > setupListeners()
std::optional< std::string > sslClientCAPath_
Definition GRPCServer.h:85
GRPCServerImpl(Application &app)
beast::Journal journal_
Definition GRPCServer.h:87
std::function< std::pair< Response, grpc::Status >(rpc::GRPCContext< Request > &)> Handler
Definition GRPCServer.h:105
std::unique_ptr< grpc::Server > server_
Definition GRPCServer.h:71
boost::asio::ip::tcp::endpoint getEndpoint() const
std::string serverAddress_
Definition GRPCServer.h:75
org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService service_
Definition GRPCServer.h:69
std::function< void( org::xrpl::rpc::v1::XRPLedgerAPIService::AsyncService &, grpc::ServerContext *, Request *, grpc::ServerAsyncResponseWriter< Response > *, grpc::CompletionQueue *, grpc::ServerCompletionQueue *, void *)> BindListener
Definition GRPCServer.h:93
static constexpr unsigned kApiVersion
Definition GRPCServer.h:107
std::shared_ptr< grpc::ServerCredentials > createServerCredentials()
std::thread thread_
Definition GRPCServer.h:324
boost::asio::ip::tcp::endpoint getEndpoint() const
GRPCServerImpl impl_
Definition GRPCServer.h:323
std::shared_ptr< InfoSub > pointer
Definition InfoSub.h:91
A consumption charge.
Definition Charge.h:13
An endpoint that consumes resources.
Definition Consumer.h:20
T empty(T... args)
T end(T... args)
T find_first_of(T... args)
T find_if(T... args)
T find_last_of(T... args)
T get(T... args)
T getline(T... args)
T make_shared(T... args)
T message(T... args)
boost::asio::ip::tcp::endpoint toAsioEndpoint(Endpoint const &endpoint)
Convert to asio::ip::tcp::endpoint.
Endpoint fromAsio(boost::asio::ip::address const &address)
Convert to Endpoint.
void setCurrentThreadName(std::string_view newThreadName)
Changes the name of the caller thread.
STL namespace.
Charge const kFeeMediumBurdenRpc
ErrorCodeI conditionMet(Condition conditionRequired, T &context)
Definition Handler.h:70
ErrorInfo const & getErrorInfo(ErrorCodeI code)
Returns an ErrorInfo that reflects the error code.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
ErrorCodeI
Definition ErrorCodes.h:23
@ RpcSuccess
Definition ErrorCodes.h:27
std::pair< org::xrpl::rpc::v1::GetLedgerDataResponse, grpc::Status > doLedgerDataGrpc(rpc::GRPCContext< org::xrpl::rpc::v1::GetLedgerDataRequest > &context)
std::string trimWhitespace(std::string str)
Remove leading and trailing ASCII whitespace.
std::pair< org::xrpl::rpc::v1::GetLedgerDiffResponse, grpc::Status > doLedgerDiffGrpc(rpc::GRPCContext< org::xrpl::rpc::v1::GetLedgerDiffRequest > &context)
Role
Indicates the level of administrative permission to grant.
Definition Role.h:27
@ IDENTIFIED
Definition Role.h:27
@ USER
Definition Role.h:27
@ JtRpc
Definition Job.h:38
std::string getFileContents(std::error_code &ec, std::filesystem::path const &sourcePath, std::optional< std::size_t > maxSize=std::nullopt)
std::pair< org::xrpl::rpc::v1::GetLedgerEntryResponse, grpc::Status > doLedgerEntryGrpc(rpc::GRPCContext< org::xrpl::rpc::v1::GetLedgerEntryRequest > &context)
std::pair< org::xrpl::rpc::v1::GetLedgerResponse, grpc::Status > doLedgerGrpc(rpc::GRPCContext< org::xrpl::rpc::v1::GetLedgerRequest > &context)
void erase(STObject &st, TypedField< U > const &f)
Remove a field in an STObject.
Definition STExchange.h:161
bool isUnlimited(Role const &role)
ADMIN and IDENTIFIED roles shall have unlimited resources.
Definition Role.cpp:115
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52
T pop_back(T... args)
T push_back(T... args)
T str(T... args)
static constexpr auto kSslCertChain
Definition Constants.h:161
static constexpr auto kSslKey
Definition Constants.h:165
static constexpr auto kSslClientCa
Definition Constants.h:164
static constexpr auto kSslCert
Definition Constants.h:160
static constexpr auto kSecureGateway
Definition Constants.h:154
static constexpr auto kPortGrpc
Definition Constants.h:45
Maps an rpc error code to its token, default message, and HTTP status.
Definition ErrorCodes.h:176
json::StaticString message
Definition ErrorCodes.h:195
T substr(T... args)
T value(T... args)
T what(T... args)