rippled
Loading...
Searching...
No Matches
OverlayImpl.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/misc/HashRouter.h>
21#include <xrpld/app/misc/NetworkOPs.h>
22#include <xrpld/app/misc/ValidatorList.h>
23#include <xrpld/app/misc/ValidatorSite.h>
24#include <xrpld/app/rdb/RelationalDatabase.h>
25#include <xrpld/app/rdb/Wallet.h>
26#include <xrpld/overlay/Cluster.h>
27#include <xrpld/overlay/detail/ConnectAttempt.h>
28#include <xrpld/overlay/detail/PeerImp.h>
29#include <xrpld/overlay/detail/Tuning.h>
30#include <xrpld/overlay/predicates.h>
31#include <xrpld/peerfinder/make_Manager.h>
32#include <xrpld/rpc/handlers/GetCounts.h>
33#include <xrpld/rpc/json_body.h>
34
35#include <xrpl/basics/base64.h>
36#include <xrpl/basics/make_SSLContext.h>
37#include <xrpl/basics/random.h>
38#include <xrpl/beast/core/LexicalCast.h>
39#include <xrpl/protocol/STTx.h>
40#include <xrpl/server/SimpleWriter.h>
41
42#include <boost/algorithm/string/predicate.hpp>
43
44#include "xrpld/overlay/detail/TrafficCount.h"
45
46namespace ripple {
47
48namespace CrawlOptions {
49enum {
51 Overlay = (1 << 0),
52 ServerInfo = (1 << 1),
53 ServerCounts = (1 << 2),
54 Unl = (1 << 3)
55};
56}
57
58//------------------------------------------------------------------------------
59
60OverlayImpl::Child::Child(OverlayImpl& overlay) : overlay_(overlay)
61{
62}
63
65{
66 overlay_.remove(*this);
67}
68
69//------------------------------------------------------------------------------
70
72 : Child(overlay), timer_(overlay_.io_service_)
73{
74}
75
76void
78{
79 // This method is only ever called from the same strand that calls
80 // Timer::on_timer, ensuring they never execute concurrently.
81 stopping_ = true;
82 timer_.cancel();
83}
84
85void
87{
88 timer_.expires_after(std::chrono::seconds(1));
89 timer_.async_wait(overlay_.strand_.wrap(std::bind(
90 &Timer::on_timer, shared_from_this(), std::placeholders::_1)));
91}
92
93void
95{
96 if (ec || stopping_)
97 {
98 if (ec && ec != boost::asio::error::operation_aborted)
99 {
100 JLOG(overlay_.journal_.error()) << "on_timer: " << ec.message();
101 }
102 return;
103 }
104
105 overlay_.m_peerFinder->once_per_second();
106 overlay_.sendEndpoints();
107 overlay_.autoConnect();
108 if (overlay_.app_.config().TX_REDUCE_RELAY_ENABLE)
109 overlay_.sendTxQueue();
110
111 if ((++overlay_.timer_count_ % Tuning::checkIdlePeers) == 0)
112 overlay_.deleteIdlePeers();
113
114 async_wait();
115}
116
117//------------------------------------------------------------------------------
118
120 Application& app,
121 Setup const& setup,
122 ServerHandler& serverHandler,
124 Resolver& resolver,
125 boost::asio::io_service& io_service,
126 BasicConfig const& config,
127 beast::insight::Collector::ptr const& collector)
128 : app_(app)
129 , io_service_(io_service)
130 , work_(std::in_place, std::ref(io_service_))
132 , setup_(setup)
133 , journal_(app_.journal("Overlay"))
134 , serverHandler_(serverHandler)
136 , m_peerFinder(PeerFinder::make_Manager(
137 io_service,
138 stopwatch(),
139 app_.journal("PeerFinder"),
140 config,
141 collector))
142 , m_resolver(resolver)
143 , next_id_(1)
144 , timer_count_(0)
145 , slots_(app.logs(), *this)
146 , m_stats(
147 std::bind(&OverlayImpl::collect_metrics, this),
148 collector,
149 [counts = m_traffic.getCounts(), collector]() {
151
152 for (auto const& pair : counts)
153 ret.emplace(
154 pair.first, TrafficGauges(pair.second.name, collector));
155
156 return ret;
157 }())
158{
160}
161
162Handoff
164 std::unique_ptr<stream_type>&& stream_ptr,
165 http_request_type&& request,
166 endpoint_type remote_endpoint)
167{
168 auto const id = next_id_++;
169 beast::WrappedSink sink(app_.logs()["Peer"], makePrefix(id));
170 beast::Journal journal(sink);
171
172 Handoff handoff;
173 if (processRequest(request, handoff))
174 return handoff;
175 if (!isPeerUpgrade(request))
176 return handoff;
177
178 handoff.moved = true;
179
180 JLOG(journal.debug()) << "Peer connection upgrade from " << remote_endpoint;
181
182 error_code ec;
183 auto const local_endpoint(
184 stream_ptr->next_layer().socket().local_endpoint(ec));
185 if (ec)
186 {
187 JLOG(journal.debug()) << remote_endpoint << " failed: " << ec.message();
188 return handoff;
189 }
190
193 if (consumer.disconnect(journal))
194 return handoff;
195
196 auto const slot = m_peerFinder->new_inbound_slot(
199
200 if (slot == nullptr)
201 {
202 // self-connect, close
203 handoff.moved = false;
204 return handoff;
205 }
206
207 // Validate HTTP request
208
209 {
210 auto const types = beast::rfc2616::split_commas(request["Connect-As"]);
211 if (std::find_if(types.begin(), types.end(), [](std::string const& s) {
212 return boost::iequals(s, "peer");
213 }) == types.end())
214 {
215 handoff.moved = false;
216 handoff.response =
217 makeRedirectResponse(slot, request, remote_endpoint.address());
218 handoff.keep_alive = beast::rfc2616::is_keep_alive(request);
219 return handoff;
220 }
221 }
222
223 auto const negotiatedVersion = negotiateProtocolVersion(request["Upgrade"]);
224 if (!negotiatedVersion)
225 {
226 m_peerFinder->on_closed(slot);
227 handoff.moved = false;
228 handoff.response = makeErrorResponse(
229 slot,
230 request,
231 remote_endpoint.address(),
232 "Unable to agree on a protocol version");
233 handoff.keep_alive = false;
234 return handoff;
235 }
236
237 auto const sharedValue = makeSharedValue(*stream_ptr, journal);
238 if (!sharedValue)
239 {
240 m_peerFinder->on_closed(slot);
241 handoff.moved = false;
242 handoff.response = makeErrorResponse(
243 slot,
244 request,
245 remote_endpoint.address(),
246 "Incorrect security cookie");
247 handoff.keep_alive = false;
248 return handoff;
249 }
250
251 try
252 {
253 auto publicKey = verifyHandshake(
254 request,
255 *sharedValue,
258 remote_endpoint.address(),
259 app_);
260
261 {
262 // The node gets a reserved slot if it is in our cluster
263 // or if it has a reservation.
264 bool const reserved =
265 static_cast<bool>(app_.cluster().member(publicKey)) ||
266 app_.peerReservations().contains(publicKey);
267 auto const result =
268 m_peerFinder->activate(slot, publicKey, reserved);
269 if (result != PeerFinder::Result::success)
270 {
271 m_peerFinder->on_closed(slot);
272 JLOG(journal.debug())
273 << "Peer " << remote_endpoint << " redirected, slots full";
274 handoff.moved = false;
276 slot, request, remote_endpoint.address());
277 handoff.keep_alive = false;
278 return handoff;
279 }
280 }
281
282 auto const peer = std::make_shared<PeerImp>(
283 app_,
284 id,
285 slot,
286 std::move(request),
287 publicKey,
288 *negotiatedVersion,
289 consumer,
290 std::move(stream_ptr),
291 *this);
292 {
293 // As we are not on the strand, run() must be called
294 // while holding the lock, otherwise new I/O can be
295 // queued after a call to stop().
296 std::lock_guard<decltype(mutex_)> lock(mutex_);
297 {
298 auto const result = m_peers.emplace(peer->slot(), peer);
299 XRPL_ASSERT(
300 result.second,
301 "ripple::OverlayImpl::onHandoff : peer is inserted");
302 (void)result.second;
303 }
304 list_.emplace(peer.get(), peer);
305
306 peer->run();
307 }
308 handoff.moved = true;
309 return handoff;
310 }
311 catch (std::exception const& e)
312 {
313 JLOG(journal.debug()) << "Peer " << remote_endpoint
314 << " fails handshake (" << e.what() << ")";
315
316 m_peerFinder->on_closed(slot);
317 handoff.moved = false;
318 handoff.response = makeErrorResponse(
319 slot, request, remote_endpoint.address(), e.what());
320 handoff.keep_alive = false;
321 return handoff;
322 }
323}
324
325//------------------------------------------------------------------------------
326
327bool
329{
330 if (!is_upgrade(request))
331 return false;
332 auto const versions = parseProtocolVersions(request["Upgrade"]);
333 return !versions.empty();
334}
335
338{
340 ss << "[" << std::setfill('0') << std::setw(3) << id << "] ";
341 return ss.str();
342}
343
347 http_request_type const& request,
348 address_type remote_address)
349{
350 boost::beast::http::response<json_body> msg;
351 msg.version(request.version());
352 msg.result(boost::beast::http::status::service_unavailable);
353 msg.insert("Server", BuildInfo::getFullVersionString());
354 {
356 ostr << remote_address;
357 msg.insert("Remote-Address", ostr.str());
358 }
359 msg.insert("Content-Type", "application/json");
360 msg.insert(boost::beast::http::field::connection, "close");
361 msg.body() = Json::objectValue;
362 {
363 Json::Value& ips = (msg.body()["peer-ips"] = Json::arrayValue);
364 for (auto const& _ : m_peerFinder->redirect(slot))
365 ips.append(_.address.to_string());
366 }
367 msg.prepare_payload();
368 return std::make_shared<SimpleWriter>(msg);
369}
370
374 http_request_type const& request,
375 address_type remote_address,
376 std::string text)
377{
378 boost::beast::http::response<boost::beast::http::empty_body> msg;
379 msg.version(request.version());
380 msg.result(boost::beast::http::status::bad_request);
381 msg.reason("Bad Request (" + text + ")");
382 msg.insert("Server", BuildInfo::getFullVersionString());
383 msg.insert("Remote-Address", remote_address.to_string());
384 msg.insert(boost::beast::http::field::connection, "close");
385 msg.prepare_payload();
386 return std::make_shared<SimpleWriter>(msg);
387}
388
389//------------------------------------------------------------------------------
390
391void
393{
394 XRPL_ASSERT(work_, "ripple::OverlayImpl::connect : work is set");
395
396 auto usage = resourceManager().newOutboundEndpoint(remote_endpoint);
397 if (usage.disconnect(journal_))
398 {
399 JLOG(journal_.info()) << "Over resource limit: " << remote_endpoint;
400 return;
401 }
402
403 auto const slot = peerFinder().new_outbound_slot(remote_endpoint);
404 if (slot == nullptr)
405 {
406 JLOG(journal_.debug()) << "Connect: No slot for " << remote_endpoint;
407 return;
408 }
409
410 auto const p = std::make_shared<ConnectAttempt>(
411 app_,
414 usage,
416 next_id_++,
417 slot,
418 app_.journal("Peer"),
419 *this);
420
422 list_.emplace(p.get(), p);
423 p->run();
424}
425
426//------------------------------------------------------------------------------
427
428// Adds a peer that is already handshaked and active
429void
431{
433
434 {
435 auto const result = m_peers.emplace(peer->slot(), peer);
436 XRPL_ASSERT(
437 result.second,
438 "ripple::OverlayImpl::add_active : peer is inserted");
439 (void)result.second;
440 }
441
442 {
443 auto const result = ids_.emplace(
444 std::piecewise_construct,
445 std::make_tuple(peer->id()),
446 std::make_tuple(peer));
447 XRPL_ASSERT(
448 result.second,
449 "ripple::OverlayImpl::add_active : peer ID is inserted");
450 (void)result.second;
451 }
452
453 list_.emplace(peer.get(), peer);
454
455 JLOG(journal_.debug()) << "activated " << peer->getRemoteAddress() << " ("
456 << peer->id() << ":"
457 << toBase58(
458 TokenType::NodePublic, peer->getNodePublic())
459 << ")";
460
461 // As we are not on the strand, run() must be called
462 // while holding the lock, otherwise new I/O can be
463 // queued after a call to stop().
464 peer->run();
465}
466
467void
469{
471 auto const iter = m_peers.find(slot);
472 XRPL_ASSERT(
473 iter != m_peers.end(), "ripple::OverlayImpl::remove : valid input");
474 m_peers.erase(iter);
475}
476
477void
479{
481 app_.config(),
482 serverHandler_.setup().overlay.port(),
483 app_.getValidationPublicKey().has_value(),
485
486 m_peerFinder->setConfig(config);
487 m_peerFinder->start();
488
489 // Populate our boot cache: if there are no entries in [ips] then we use
490 // the entries in [ips_fixed].
491 auto bootstrapIps =
493
494 // If nothing is specified, default to several well-known high-capacity
495 // servers to serve as bootstrap:
496 if (bootstrapIps.empty())
497 {
498 // Pool of servers operated by Ripple Labs Inc. - https://ripple.com
499 bootstrapIps.push_back("r.ripple.com 51235");
500
501 // Pool of servers operated by ISRDC - https://isrdc.in
502 bootstrapIps.push_back("sahyadri.isrdc.in 51235");
503
504 // Pool of servers operated by @Xrpkuwait - https://xrpkuwait.com
505 bootstrapIps.push_back("hubs.xrpkuwait.com 51235");
506
507 // Pool of servers operated by XRPL Commons - https://xrpl-commons.org
508 bootstrapIps.push_back("hub.xrpl-commons.org 51235");
509 }
510
512 bootstrapIps,
513 [this](
514 std::string const& name,
515 std::vector<beast::IP::Endpoint> const& addresses) {
517 ips.reserve(addresses.size());
518 for (auto const& addr : addresses)
519 {
520 if (addr.port() == 0)
521 ips.push_back(to_string(addr.at_port(DEFAULT_PEER_PORT)));
522 else
523 ips.push_back(to_string(addr));
524 }
525
526 std::string const base("config: ");
527 if (!ips.empty())
528 m_peerFinder->addFallbackStrings(base + name, ips);
529 });
530
531 // Add the ips_fixed from the rippled.cfg file
533 {
536 [this](
537 std::string const& name,
538 std::vector<beast::IP::Endpoint> const& addresses) {
540 ips.reserve(addresses.size());
541
542 for (auto& addr : addresses)
543 {
544 if (addr.port() == 0)
545 ips.emplace_back(addr.address(), DEFAULT_PEER_PORT);
546 else
547 ips.emplace_back(addr);
548 }
549
550 if (!ips.empty())
551 m_peerFinder->addFixedPeer(name, ips);
552 });
553 }
554 auto const timer = std::make_shared<Timer>(*this);
556 list_.emplace(timer.get(), timer);
557 timer_ = timer;
558 timer->async_wait();
559}
560
561void
563{
565 {
566 std::unique_lock<decltype(mutex_)> lock(mutex_);
567 cond_.wait(lock, [this] { return list_.empty(); });
568 }
569 m_peerFinder->stop();
570}
571
572//------------------------------------------------------------------------------
573//
574// PropertyStream
575//
576//------------------------------------------------------------------------------
577
578void
580{
581 beast::PropertyStream::Set set("traffic", stream);
582 auto const stats = m_traffic.getCounts();
583 for (auto const& pair : stats)
584 {
586 item["category"] = pair.second.name;
587 item["bytes_in"] = std::to_string(pair.second.bytesIn.load());
588 item["messages_in"] = std::to_string(pair.second.messagesIn.load());
589 item["bytes_out"] = std::to_string(pair.second.bytesOut.load());
590 item["messages_out"] = std::to_string(pair.second.messagesOut.load());
591 }
592}
593
594//------------------------------------------------------------------------------
600void
602{
603 // Now track this peer
604 {
606 auto const result(ids_.emplace(
607 std::piecewise_construct,
608 std::make_tuple(peer->id()),
609 std::make_tuple(peer)));
610 XRPL_ASSERT(
611 result.second,
612 "ripple::OverlayImpl::activate : peer ID is inserted");
613 (void)result.second;
614 }
615
616 JLOG(journal_.debug()) << "activated " << peer->getRemoteAddress() << " ("
617 << peer->id() << ":"
618 << toBase58(
619 TokenType::NodePublic, peer->getNodePublic())
620 << ")";
621
622 // We just accepted this peer so we have non-zero active peers
623 XRPL_ASSERT(size(), "ripple::OverlayImpl::activate : nonzero peers");
624}
625
626void
628{
630 ids_.erase(id);
631}
632
633void
636 std::shared_ptr<PeerImp> const& from)
637{
638 auto const n = m->list_size();
639 auto const& journal = from->pjournal();
640
641 protocol::TMManifests relay;
642
643 for (std::size_t i = 0; i < n; ++i)
644 {
645 auto& s = m->list().Get(i).stobject();
646
647 if (auto mo = deserializeManifest(s))
648 {
649 auto const serialized = mo->serialized;
650
651 auto const result =
652 app_.validatorManifests().applyManifest(std::move(*mo));
653
654 if (result == ManifestDisposition::accepted)
655 {
656 relay.add_list()->set_stobject(s);
657
658 // N.B.: this is important; the applyManifest call above moves
659 // the loaded Manifest out of the optional so we need to
660 // reload it here.
661 mo = deserializeManifest(serialized);
662 XRPL_ASSERT(
663 mo,
664 "ripple::OverlayImpl::onManifests : manifest "
665 "deserialization succeeded");
666
667 app_.getOPs().pubManifest(*mo);
668
669 if (app_.validators().listed(mo->masterKey))
670 {
671 auto db = app_.getWalletDB().checkoutDb();
672 addValidatorManifest(*db, serialized);
673 }
674 }
675 }
676 else
677 {
678 JLOG(journal.debug())
679 << "Malformed manifest #" << i + 1 << ": " << strHex(s);
680 continue;
681 }
682 }
683
684 if (!relay.list().empty())
685 for_each([m2 = std::make_shared<Message>(relay, protocol::mtMANIFESTS)](
686 std::shared_ptr<PeerImp>&& p) { p->send(m2); });
687}
688
689void
691{
692 m_traffic.addCount(cat, true, size);
693}
694
695void
697{
698 m_traffic.addCount(cat, false, size);
699}
706{
708 return ids_.size();
709}
710
711int
713{
714 return m_peerFinder->config().maxPeers;
715}
716
719{
720 using namespace std::chrono;
721 Json::Value jv;
722 auto& av = jv["active"] = Json::Value(Json::arrayValue);
723
725 auto& pv = av.append(Json::Value(Json::objectValue));
726 pv[jss::public_key] = base64_encode(
727 sp->getNodePublic().data(), sp->getNodePublic().size());
728 pv[jss::type] = sp->slot()->inbound() ? "in" : "out";
729 pv[jss::uptime] = static_cast<std::uint32_t>(
730 duration_cast<seconds>(sp->uptime()).count());
731 if (sp->crawl())
732 {
733 pv[jss::ip] = sp->getRemoteAddress().address().to_string();
734 if (sp->slot()->inbound())
735 {
736 if (auto port = sp->slot()->listening_port())
737 pv[jss::port] = *port;
738 }
739 else
740 {
741 pv[jss::port] = std::to_string(sp->getRemoteAddress().port());
742 }
743 }
744
745 {
746 auto version{sp->getVersion()};
747 if (!version.empty())
748 // Could move here if Json::value supported moving from strings
749 pv[jss::version] = std::string{version};
750 }
751
752 std::uint32_t minSeq, maxSeq;
753 sp->ledgerRange(minSeq, maxSeq);
754 if (minSeq != 0 || maxSeq != 0)
755 pv[jss::complete_ledgers] =
756 std::to_string(minSeq) + "-" + std::to_string(maxSeq);
757 });
758
759 return jv;
760}
761
764{
765 bool const humanReadable = false;
766 bool const admin = false;
767 bool const counters = false;
768
769 Json::Value server_info =
770 app_.getOPs().getServerInfo(humanReadable, admin, counters);
771
772 // Filter out some information
773 server_info.removeMember(jss::hostid);
774 server_info.removeMember(jss::load_factor_fee_escalation);
775 server_info.removeMember(jss::load_factor_fee_queue);
776 server_info.removeMember(jss::validation_quorum);
777
778 if (server_info.isMember(jss::validated_ledger))
779 {
780 Json::Value& validated_ledger = server_info[jss::validated_ledger];
781
782 validated_ledger.removeMember(jss::base_fee);
783 validated_ledger.removeMember(jss::reserve_base_xrp);
784 validated_ledger.removeMember(jss::reserve_inc_xrp);
785 }
786
787 return server_info;
788}
789
792{
793 return getCountsJson(app_, 10);
794}
795
798{
799 Json::Value validators = app_.validators().getJson();
800
801 if (validators.isMember(jss::publisher_lists))
802 {
803 Json::Value& publisher_lists = validators[jss::publisher_lists];
804
805 for (auto& publisher : publisher_lists)
806 {
807 publisher.removeMember(jss::list);
808 }
809 }
810
811 validators.removeMember(jss::signing_keys);
812 validators.removeMember(jss::trusted_validator_keys);
813 validators.removeMember(jss::validation_quorum);
814
815 Json::Value validatorSites = app_.validatorSites().getJson();
816
817 if (validatorSites.isMember(jss::validator_sites))
818 {
819 validators[jss::validator_sites] =
820 std::move(validatorSites[jss::validator_sites]);
821 }
822
823 return validators;
824}
825
826// Returns information on verified peers.
829{
831 for (auto const& peer : getActivePeers())
832 {
833 json.append(peer->json());
834 }
835 return json;
836}
837
838bool
840{
841 if (req.target() != "/crawl" ||
843 return false;
844
845 boost::beast::http::response<json_body> msg;
846 msg.version(req.version());
847 msg.result(boost::beast::http::status::ok);
848 msg.insert("Server", BuildInfo::getFullVersionString());
849 msg.insert("Content-Type", "application/json");
850 msg.insert("Connection", "close");
851 msg.body()["version"] = Json::Value(2u);
852
854 {
855 msg.body()["overlay"] = getOverlayInfo();
856 }
858 {
859 msg.body()["server"] = getServerInfo();
860 }
862 {
863 msg.body()["counts"] = getServerCounts();
864 }
866 {
867 msg.body()["unl"] = getUnlInfo();
868 }
869
870 msg.prepare_payload();
871 handoff.response = std::make_shared<SimpleWriter>(msg);
872 return true;
873}
874
875bool
877 http_request_type const& req,
878 Handoff& handoff)
879{
880 // If the target is in the form "/vl/<validator_list_public_key>",
881 // return the most recent validator list for that key.
882 constexpr std::string_view prefix("/vl/");
883
884 if (!req.target().starts_with(prefix.data()) || !setup_.vlEnabled)
885 return false;
886
887 std::uint32_t version = 1;
888
889 boost::beast::http::response<json_body> msg;
890 msg.version(req.version());
891 msg.insert("Server", BuildInfo::getFullVersionString());
892 msg.insert("Content-Type", "application/json");
893 msg.insert("Connection", "close");
894
895 auto fail = [&msg, &handoff](auto status) {
896 msg.result(status);
897 msg.insert("Content-Length", "0");
898
899 msg.body() = Json::nullValue;
900
901 msg.prepare_payload();
902 handoff.response = std::make_shared<SimpleWriter>(msg);
903 return true;
904 };
905
906 std::string_view key = req.target().substr(prefix.size());
907
908 if (auto slash = key.find('/'); slash != std::string_view::npos)
909 {
910 auto verString = key.substr(0, slash);
911 if (!boost::conversion::try_lexical_convert(verString, version))
912 return fail(boost::beast::http::status::bad_request);
913 key = key.substr(slash + 1);
914 }
915
916 if (key.empty())
917 return fail(boost::beast::http::status::bad_request);
918
919 // find the list
920 auto vl = app_.validators().getAvailable(key, version);
921
922 if (!vl)
923 {
924 // 404 not found
925 return fail(boost::beast::http::status::not_found);
926 }
927 else if (!*vl)
928 {
929 return fail(boost::beast::http::status::bad_request);
930 }
931 else
932 {
933 msg.result(boost::beast::http::status::ok);
934
935 msg.body() = *vl;
936
937 msg.prepare_payload();
938 handoff.response = std::make_shared<SimpleWriter>(msg);
939 return true;
940 }
941}
942
943bool
945{
946 if (req.target() != "/health")
947 return false;
948 boost::beast::http::response<json_body> msg;
949 msg.version(req.version());
950 msg.insert("Server", BuildInfo::getFullVersionString());
951 msg.insert("Content-Type", "application/json");
952 msg.insert("Connection", "close");
953
954 auto info = getServerInfo();
955
956 int last_validated_ledger_age = -1;
957 if (info.isMember(jss::validated_ledger))
958 last_validated_ledger_age =
959 info[jss::validated_ledger][jss::age].asInt();
960 bool amendment_blocked = false;
961 if (info.isMember(jss::amendment_blocked))
962 amendment_blocked = true;
963 int number_peers = info[jss::peers].asInt();
964 std::string server_state = info[jss::server_state].asString();
965 auto load_factor = info[jss::load_factor_server].asDouble() /
966 info[jss::load_base].asDouble();
967
968 enum { healthy, warning, critical };
969 int health = healthy;
970 auto set_health = [&health](int state) {
971 if (health < state)
972 health = state;
973 };
974
975 msg.body()[jss::info] = Json::objectValue;
976 if (last_validated_ledger_age >= 7 || last_validated_ledger_age < 0)
977 {
978 msg.body()[jss::info][jss::validated_ledger] =
979 last_validated_ledger_age;
980 if (last_validated_ledger_age < 20)
981 set_health(warning);
982 else
983 set_health(critical);
984 }
985
986 if (amendment_blocked)
987 {
988 msg.body()[jss::info][jss::amendment_blocked] = true;
989 set_health(critical);
990 }
991
992 if (number_peers <= 7)
993 {
994 msg.body()[jss::info][jss::peers] = number_peers;
995 if (number_peers != 0)
996 set_health(warning);
997 else
998 set_health(critical);
999 }
1000
1001 if (!(server_state == "full" || server_state == "validating" ||
1002 server_state == "proposing"))
1003 {
1004 msg.body()[jss::info][jss::server_state] = server_state;
1005 if (server_state == "syncing" || server_state == "tracking" ||
1006 server_state == "connected")
1007 {
1008 set_health(warning);
1009 }
1010 else
1011 set_health(critical);
1012 }
1013
1014 if (load_factor > 100)
1015 {
1016 msg.body()[jss::info][jss::load_factor] = load_factor;
1017 if (load_factor < 1000)
1018 set_health(warning);
1019 else
1020 set_health(critical);
1021 }
1022
1023 switch (health)
1024 {
1025 case healthy:
1026 msg.result(boost::beast::http::status::ok);
1027 break;
1028 case warning:
1029 msg.result(boost::beast::http::status::service_unavailable);
1030 break;
1031 case critical:
1032 msg.result(boost::beast::http::status::internal_server_error);
1033 break;
1034 }
1035
1036 msg.prepare_payload();
1037 handoff.response = std::make_shared<SimpleWriter>(msg);
1038 return true;
1039}
1040
1041bool
1043{
1044 // Take advantage of || short-circuiting
1045 return processCrawl(req, handoff) || processValidatorList(req, handoff) ||
1046 processHealth(req, handoff);
1047}
1048
1051{
1053 ret.reserve(size());
1054
1055 for_each([&ret](std::shared_ptr<PeerImp>&& sp) {
1056 ret.emplace_back(std::move(sp));
1057 });
1058
1059 return ret;
1060}
1061
1064 std::set<Peer::id_t> const& toSkip,
1065 std::size_t& active,
1067 std::size_t& enabledInSkip) const
1068{
1070 std::lock_guard lock(mutex_);
1071
1072 active = ids_.size();
1073 disabled = enabledInSkip = 0;
1074 ret.reserve(ids_.size());
1075
1076 // NOTE The purpose of p is to delay the destruction of PeerImp
1078 for (auto& [id, w] : ids_)
1079 {
1080 if (p = w.lock(); p != nullptr)
1081 {
1082 bool const reduceRelayEnabled = p->txReduceRelayEnabled();
1083 // tx reduced relay feature disabled
1084 if (!reduceRelayEnabled)
1085 ++disabled;
1086
1087 if (toSkip.count(id) == 0)
1088 ret.emplace_back(std::move(p));
1089 else if (reduceRelayEnabled)
1090 ++enabledInSkip;
1091 }
1092 }
1093
1094 return ret;
1095}
1096
1097void
1099{
1100 for_each(
1101 [index](std::shared_ptr<PeerImp>&& sp) { sp->checkTracking(index); });
1102}
1103
1106{
1107 std::lock_guard lock(mutex_);
1108 auto const iter = ids_.find(id);
1109 if (iter != ids_.end())
1110 return iter->second.lock();
1111 return {};
1112}
1113
1114// A public key hash map was not used due to the peer connect/disconnect
1115// update overhead outweighing the performance of a small set linear search.
1118{
1119 std::lock_guard lock(mutex_);
1120 // NOTE The purpose of peer is to delay the destruction of PeerImp
1122 for (auto const& e : ids_)
1123 {
1124 if (peer = e.second.lock(); peer != nullptr)
1125 {
1126 if (peer->getNodePublic() == pubKey)
1127 return peer;
1128 }
1129 }
1130 return {};
1131}
1132
1133void
1134OverlayImpl::broadcast(protocol::TMProposeSet& m)
1135{
1136 auto const sm = std::make_shared<Message>(m, protocol::mtPROPOSE_LEDGER);
1137 for_each([&](std::shared_ptr<PeerImp>&& p) { p->send(sm); });
1138}
1139
1142 protocol::TMProposeSet& m,
1143 uint256 const& uid,
1144 PublicKey const& validator)
1145{
1146 if (auto const toSkip = app_.getHashRouter().shouldRelay(uid))
1147 {
1148 auto const sm =
1149 std::make_shared<Message>(m, protocol::mtPROPOSE_LEDGER, validator);
1151 if (toSkip->find(p->id()) == toSkip->end())
1152 p->send(sm);
1153 });
1154 return *toSkip;
1155 }
1156 return {};
1157}
1158
1159void
1160OverlayImpl::broadcast(protocol::TMValidation& m)
1161{
1162 auto const sm = std::make_shared<Message>(m, protocol::mtVALIDATION);
1163 for_each([sm](std::shared_ptr<PeerImp>&& p) { p->send(sm); });
1164}
1165
1168 protocol::TMValidation& m,
1169 uint256 const& uid,
1170 PublicKey const& validator)
1171{
1172 if (auto const toSkip = app_.getHashRouter().shouldRelay(uid))
1173 {
1174 auto const sm =
1175 std::make_shared<Message>(m, protocol::mtVALIDATION, validator);
1177 if (toSkip->find(p->id()) == toSkip->end())
1178 p->send(sm);
1179 });
1180 return *toSkip;
1181 }
1182 return {};
1183}
1184
1187{
1189
1190 if (auto seq = app_.validatorManifests().sequence();
1192 {
1193 protocol::TMManifests tm;
1194
1196 [&tm](std::size_t s) { tm.mutable_list()->Reserve(s); },
1197 [&tm, &hr = app_.getHashRouter()](Manifest const& manifest) {
1198 tm.add_list()->set_stobject(
1199 manifest.serialized.data(), manifest.serialized.size());
1200 hr.addSuppression(manifest.hash());
1201 });
1202
1204
1205 if (tm.list_size() != 0)
1207 std::make_shared<Message>(tm, protocol::mtMANIFESTS);
1208
1210 }
1211
1212 return manifestMessage_;
1213}
1214
1215void
1217 uint256 const& hash,
1219 std::set<Peer::id_t> const& toSkip)
1220{
1221 bool relay = tx.has_value();
1222 if (relay)
1223 {
1224 auto& txn = tx->get();
1225 SerialIter sit(makeSlice(txn.rawtransaction()));
1226 relay = !isPseudoTx(STTx{sit});
1227 }
1228
1229 Overlay::PeerSequence peers = {};
1230 std::size_t total = 0;
1232 std::size_t enabledInSkip = 0;
1233
1234 if (!relay)
1235 {
1237 return;
1238
1239 peers = getActivePeers(toSkip, total, disabled, enabledInSkip);
1240 JLOG(journal_.trace())
1241 << "not relaying tx, total peers " << peers.size();
1242 for (auto const& p : peers)
1243 p->addTxQueue(hash);
1244 return;
1245 }
1246
1247 auto& txn = tx->get();
1248 auto const sm = std::make_shared<Message>(txn, protocol::mtTRANSACTION);
1249 peers = getActivePeers(toSkip, total, disabled, enabledInSkip);
1250 auto const minRelay = app_.config().TX_REDUCE_RELAY_MIN_PEERS + disabled;
1251
1252 if (!app_.config().TX_REDUCE_RELAY_ENABLE || total <= minRelay)
1253 {
1254 for (auto const& p : peers)
1255 p->send(sm);
1258 txMetrics_.addMetrics(total, toSkip.size(), 0);
1259 return;
1260 }
1261
1262 // We have more peers than the minimum (disabled + minimum enabled),
1263 // relay to all disabled and some randomly selected enabled that
1264 // do not have the transaction.
1265 auto const enabledTarget = app_.config().TX_REDUCE_RELAY_MIN_PEERS +
1266 (total - minRelay) * app_.config().TX_RELAY_PERCENTAGE / 100;
1267
1268 txMetrics_.addMetrics(enabledTarget, toSkip.size(), disabled);
1269
1270 if (enabledTarget > enabledInSkip)
1271 std::shuffle(peers.begin(), peers.end(), default_prng());
1272
1273 JLOG(journal_.trace()) << "relaying tx, total peers " << peers.size()
1274 << " selected " << enabledTarget << " skip "
1275 << toSkip.size() << " disabled " << disabled;
1276
1277 // count skipped peers with the enabled feature towards the quota
1278 std::uint16_t enabledAndRelayed = enabledInSkip;
1279 for (auto const& p : peers)
1280 {
1281 // always relay to a peer with the disabled feature
1282 if (!p->txReduceRelayEnabled())
1283 {
1284 p->send(sm);
1285 }
1286 else if (enabledAndRelayed < enabledTarget)
1287 {
1288 enabledAndRelayed++;
1289 p->send(sm);
1290 }
1291 else
1292 {
1293 p->addTxQueue(hash);
1294 }
1295 }
1296}
1297
1298//------------------------------------------------------------------------------
1299
1300void
1302{
1303 std::lock_guard lock(mutex_);
1304 list_.erase(&child);
1305 if (list_.empty())
1306 cond_.notify_all();
1307}
1308
1309void
1311{
1312 // Calling list_[].second->stop() may cause list_ to be modified
1313 // (OverlayImpl::remove() may be called on this same thread). So
1314 // iterating directly over list_ to call child->stop() could lead to
1315 // undefined behavior.
1316 //
1317 // Therefore we copy all of the weak/shared ptrs out of list_ before we
1318 // start calling stop() on them. That guarantees OverlayImpl::remove()
1319 // won't be called until vector<> children leaves scope.
1321 {
1322 std::lock_guard lock(mutex_);
1323 if (!work_)
1324 return;
1325 work_ = std::nullopt;
1326
1327 children.reserve(list_.size());
1328 for (auto const& element : list_)
1329 {
1330 children.emplace_back(element.second.lock());
1331 }
1332 } // lock released
1333
1334 for (auto const& child : children)
1335 {
1336 if (child != nullptr)
1337 child->stop();
1338 }
1339}
1340
1341void
1343{
1344 auto const result = m_peerFinder->autoconnect();
1345 for (auto addr : result)
1346 connect(addr);
1347}
1348
1349void
1351{
1352 auto const result = m_peerFinder->buildEndpointsForPeers();
1353 for (auto const& e : result)
1354 {
1356 {
1357 std::lock_guard lock(mutex_);
1358 auto const iter = m_peers.find(e.first);
1359 if (iter != m_peers.end())
1360 peer = iter->second.lock();
1361 }
1362 if (peer)
1363 peer->sendEndpoints(e.second.begin(), e.second.end());
1364 }
1365}
1366
1367void
1369{
1370 for_each([](auto const& p) {
1371 if (p->txReduceRelayEnabled())
1372 p->sendTxQueue();
1373 });
1374}
1375
1378 PublicKey const& validator,
1379 bool squelch,
1380 uint32_t squelchDuration)
1381{
1382 protocol::TMSquelch m;
1383 m.set_squelch(squelch);
1384 m.set_validatorpubkey(validator.data(), validator.size());
1385 if (squelch)
1386 m.set_squelchduration(squelchDuration);
1387 return std::make_shared<Message>(m, protocol::mtSQUELCH);
1388}
1389
1390void
1392{
1393 if (auto peer = findPeerByShortID(id);
1394 peer && app_.config().VP_REDUCE_RELAY_SQUELCH)
1395 {
1396 // optimize - multiple message with different
1397 // validator might be sent to the same peer
1398 peer->send(makeSquelchMessage(validator, false, 0));
1399 }
1400}
1401
1402void
1404 PublicKey const& validator,
1405 Peer::id_t id,
1406 uint32_t squelchDuration) const
1407{
1408 if (auto peer = findPeerByShortID(id);
1409 peer && app_.config().VP_REDUCE_RELAY_SQUELCH)
1410 {
1411 peer->send(makeSquelchMessage(validator, true, squelchDuration));
1412 }
1413}
1414
1415void
1417 uint256 const& key,
1418 PublicKey const& validator,
1419 std::set<Peer::id_t>&& peers,
1420 protocol::MessageType type)
1421{
1422 if (!strand_.running_in_this_thread())
1423 return post(
1424 strand_,
1425 [this, key, validator, peers = std::move(peers), type]() mutable {
1426 updateSlotAndSquelch(key, validator, std::move(peers), type);
1427 });
1428
1429 for (auto id : peers)
1430 slots_.updateSlotAndSquelch(key, validator, id, type);
1431}
1432
1433void
1435 uint256 const& key,
1436 PublicKey const& validator,
1437 Peer::id_t peer,
1438 protocol::MessageType type)
1439{
1440 if (!strand_.running_in_this_thread())
1441 return post(strand_, [this, key, validator, peer, type]() {
1442 updateSlotAndSquelch(key, validator, peer, type);
1443 });
1444
1445 slots_.updateSlotAndSquelch(key, validator, peer, type);
1446}
1447
1448void
1450{
1451 if (!strand_.running_in_this_thread())
1452 return post(strand_, std::bind(&OverlayImpl::deletePeer, this, id));
1453
1454 slots_.deletePeer(id, true);
1455}
1456
1457void
1459{
1460 if (!strand_.running_in_this_thread())
1461 return post(strand_, std::bind(&OverlayImpl::deleteIdlePeers, this));
1462
1463 slots_.deleteIdlePeers();
1464}
1465
1466//------------------------------------------------------------------------------
1467
1470{
1471 Overlay::Setup setup;
1472
1473 {
1474 auto const& section = config.section("overlay");
1475 setup.context = make_SSLContext("");
1476
1477 set(setup.ipLimit, "ip_limit", section);
1478 if (setup.ipLimit < 0)
1479 Throw<std::runtime_error>("Configured IP limit is invalid");
1480
1481 std::string ip;
1482 set(ip, "public_ip", section);
1483 if (!ip.empty())
1484 {
1485 boost::system::error_code ec;
1486 setup.public_ip = beast::IP::Address::from_string(ip, ec);
1487 if (ec || beast::IP::is_private(setup.public_ip))
1488 Throw<std::runtime_error>("Configured public IP is invalid");
1489 }
1490 }
1491
1492 {
1493 auto const& section = config.section("crawl");
1494 auto const& values = section.values();
1495
1496 if (values.size() > 1)
1497 {
1498 Throw<std::runtime_error>(
1499 "Configured [crawl] section is invalid, too many values");
1500 }
1501
1502 bool crawlEnabled = true;
1503
1504 // Only allow "0|1" as a value
1505 if (values.size() == 1)
1506 {
1507 try
1508 {
1509 crawlEnabled = boost::lexical_cast<bool>(values.front());
1510 }
1511 catch (boost::bad_lexical_cast const&)
1512 {
1513 Throw<std::runtime_error>(
1514 "Configured [crawl] section has invalid value: " +
1515 values.front());
1516 }
1517 }
1518
1519 if (crawlEnabled)
1520 {
1521 if (get<bool>(section, "overlay", true))
1522 {
1524 }
1525 if (get<bool>(section, "server", true))
1526 {
1528 }
1529 if (get<bool>(section, "counts", false))
1530 {
1532 }
1533 if (get<bool>(section, "unl", true))
1534 {
1536 }
1537 }
1538 }
1539 {
1540 auto const& section = config.section("vl");
1541
1542 set(setup.vlEnabled, "enabled", section);
1543 }
1544
1545 try
1546 {
1547 auto id = config.legacy("network_id");
1548
1549 if (!id.empty())
1550 {
1551 if (id == "main")
1552 id = "0";
1553
1554 if (id == "testnet")
1555 id = "1";
1556
1557 if (id == "devnet")
1558 id = "2";
1559
1560 setup.networkID = beast::lexicalCastThrow<std::uint32_t>(id);
1561 }
1562 }
1563 catch (...)
1564 {
1565 Throw<std::runtime_error>(
1566 "Configured [network_id] section is invalid: must be a number "
1567 "or one of the strings 'main', 'testnet' or 'devnet'.");
1568 }
1569
1570 return setup;
1571}
1572
1575 Application& app,
1576 Overlay::Setup const& setup,
1577 ServerHandler& serverHandler,
1578 Resource::Manager& resourceManager,
1579 Resolver& resolver,
1580 boost::asio::io_service& io_service,
1581 BasicConfig const& config,
1582 beast::insight::Collector::ptr const& collector)
1583{
1584 return std::make_unique<OverlayImpl>(
1585 app,
1586 setup,
1587 serverHandler,
1588 resourceManager,
1589 resolver,
1590 io_service,
1591 config,
1592 collector);
1593}
1594
1595} // namespace ripple
T begin(T... args)
T bind(T... args)
Represents a JSON value.
Definition: json_value.h:150
Value & append(Value const &value)
Append value to array at the end.
Definition: json_value.cpp:910
Value removeMember(char const *key)
Remove and return the named member.
Definition: json_value.cpp:935
bool isMember(char const *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:962
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
A generic endpoint for log messages.
Definition: Journal.h:60
Stream debug() const
Definition: Journal.h:328
Stream info() const
Definition: Journal.h:334
Stream trace() const
Severity stream access functions.
Definition: Journal.h:322
std::string const & name() const
Returns the name of this source.
void add(Source &source)
Add a child source.
Wraps a Journal::Sink to prefix its output with a string.
Definition: WrappedSink.h:34
virtual Config & config()=0
virtual beast::Journal journal(std::string const &name)=0
virtual ValidatorSite & validatorSites()=0
virtual DatabaseCon & getWalletDB()=0
Retrieve the "wallet database".
virtual NetworkOPs & getOPs()=0
virtual ValidatorList & validators()=0
virtual std::optional< PublicKey const > getValidationPublicKey() const =0
virtual ManifestCache & validatorManifests()=0
virtual PeerReservationTable & peerReservations()=0
virtual Cluster & cluster()=0
virtual Logs & logs()=0
virtual HashRouter & getHashRouter()=0
Holds unparsed configuration information.
Definition: BasicConfig.h:218
Section & section(std::string const &name)
Returns the section with the given name.
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
std::optional< std::string > member(PublicKey const &node) const
Determines whether a node belongs in the cluster.
Definition: Cluster.cpp:38
std::vector< std::string > IPS_FIXED
Definition: Config.h:144
std::vector< std::string > IPS
Definition: Config.h:141
bool standalone() const
Definition: Config.h:337
std::size_t TX_REDUCE_RELAY_MIN_PEERS
Definition: Config.h:269
bool TX_REDUCE_RELAY_ENABLE
Definition: Config.h:259
bool TX_REDUCE_RELAY_METRICS
Definition: Config.h:266
std::size_t TX_RELAY_PERCENTAGE
Definition: Config.h:272
LockedSociSession checkoutDb()
Definition: DatabaseCon.h:190
std::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
Definition: HashRouter.cpp:119
virtual void pubManifest(Manifest const &)=0
std::uint32_t sequence() const
A monotonically increasing number used to detect new manifests.
Definition: Manifest.h:278
void for_each_manifest(Function &&f) const
Invokes the callback once for every populated manifest.
Definition: Manifest.h:425
ManifestDisposition applyManifest(Manifest m)
Add manifest to cache.
Definition: Manifest.cpp:383
virtual Json::Value getServerInfo(bool human, bool admin, bool counters)=0
Child(OverlayImpl &overlay)
Definition: OverlayImpl.cpp:60
boost::system::error_code error_code
Definition: OverlayImpl.h:83
Json::Value getUnlInfo()
Returns information about the local server's UNL.
void stop() override
static std::string makePrefix(std::uint32_t id)
PeerFinder::Manager & peerFinder()
Definition: OverlayImpl.h:161
boost::asio::ip::tcp::endpoint endpoint_type
Definition: OverlayImpl.h:82
bool processHealth(http_request_type const &req, Handoff &handoff)
Handles health requests.
boost::asio::ip::address address_type
Definition: OverlayImpl.h:81
static bool is_upgrade(boost::beast::http::header< true, Fields > const &req)
Definition: OverlayImpl.h:320
std::condition_variable_any cond_
Definition: OverlayImpl.h:107
void onWrite(beast::PropertyStream::Map &stream) override
Subclass override.
void deleteIdlePeers()
Check if peers stopped relaying messages and if slots stopped receiving messages from the validator.
Resolver & m_resolver
Definition: OverlayImpl.h:118
void activate(std::shared_ptr< PeerImp > const &peer)
Called when a peer has connected successfully This is called after the peer handshake has been comple...
PeerSequence getActivePeers() const override
Returns a sequence representing the current list of peers.
void start() override
hash_map< std::shared_ptr< PeerFinder::Slot >, std::weak_ptr< PeerImp > > m_peers
Definition: OverlayImpl.h:116
void add_active(std::shared_ptr< PeerImp > const &peer)
std::shared_ptr< Peer > findPeerByPublicKey(PublicKey const &pubKey) override
Returns the peer with the matching public key, or null.
Resource::Manager & m_resourceManager
Definition: OverlayImpl.h:113
std::shared_ptr< Message > manifestMessage_
Definition: OverlayImpl.h:131
std::optional< std::uint32_t > manifestListSeq_
Definition: OverlayImpl.h:133
TrafficCount m_traffic
Definition: OverlayImpl.h:115
void squelch(PublicKey const &validator, Peer::id_t const id, std::uint32_t squelchDuration) const override
Squelch handler.
std::shared_ptr< Writer > makeErrorResponse(std::shared_ptr< PeerFinder::Slot > const &slot, http_request_type const &request, address_type remote_address, std::string msg)
reduce_relay::Slots< UptimeClock > slots_
Definition: OverlayImpl.h:125
void deletePeer(Peer::id_t id)
Called when the peer is deleted.
std::shared_ptr< Peer > findPeerByShortID(Peer::id_t const &id) const override
Returns the peer with the matching short id, or null.
std::atomic< Peer::id_t > next_id_
Definition: OverlayImpl.h:119
boost::asio::io_service & io_service_
Definition: OverlayImpl.h:103
Application & app_
Definition: OverlayImpl.h:102
std::weak_ptr< Timer > timer_
Definition: OverlayImpl.h:108
metrics::TxMetrics txMetrics_
Definition: OverlayImpl.h:128
void broadcast(protocol::TMProposeSet &m) override
Broadcast a proposal.
void onPeerDeactivate(Peer::id_t id)
std::mutex manifestLock_
Definition: OverlayImpl.h:135
bool processRequest(http_request_type const &req, Handoff &handoff)
Handles non-peer protocol requests.
std::recursive_mutex mutex_
Definition: OverlayImpl.h:106
void remove(std::shared_ptr< PeerFinder::Slot > const &slot)
void sendTxQueue()
Send once a second transactions' hashes aggregated by peers.
void reportOutboundTraffic(TrafficCount::category cat, int bytes)
std::set< Peer::id_t > relay(protocol::TMProposeSet &m, uint256 const &uid, PublicKey const &validator) override
Relay a proposal.
std::size_t size() const override
The number of active peers on the network Active peers are only those peers that have completed the h...
void unsquelch(PublicKey const &validator, Peer::id_t id) const override
Unsquelch handler.
std::shared_ptr< Writer > makeRedirectResponse(std::shared_ptr< PeerFinder::Slot > const &slot, http_request_type const &request, address_type remote_address)
void for_each(UnaryFunc &&f) const
Definition: OverlayImpl.h:278
std::optional< boost::asio::io_service::work > work_
Definition: OverlayImpl.h:104
Json::Value getOverlayInfo()
Returns information about peers on the overlay network.
Resource::Manager & resourceManager()
Definition: OverlayImpl.h:167
static bool isPeerUpgrade(http_request_type const &request)
Json::Value getServerCounts()
Returns information about the local server's performance counters.
void reportInboundTraffic(TrafficCount::category cat, int bytes)
boost::asio::io_service::strand strand_
Definition: OverlayImpl.h:105
void onManifests(std::shared_ptr< protocol::TMManifests > const &m, std::shared_ptr< PeerImp > const &from)
std::unique_ptr< PeerFinder::Manager > m_peerFinder
Definition: OverlayImpl.h:114
void connect(beast::IP::Endpoint const &remote_endpoint) override
Establish a peer connection to the specified endpoint.
Handoff onHandoff(std::unique_ptr< stream_type > &&bundle, http_request_type &&request, endpoint_type remote_endpoint) override
Conditionally accept an incoming HTTP request.
Setup const & setup() const
Definition: OverlayImpl.h:173
std::shared_ptr< Message > getManifestsMessage()
hash_map< Peer::id_t, std::weak_ptr< PeerImp > > ids_
Definition: OverlayImpl.h:117
Json::Value getServerInfo()
Returns information about the local server.
bool processValidatorList(http_request_type const &req, Handoff &handoff)
Handles validator list requests.
Json::Value json() override
Return diagnostics on the status of all peers.
void checkTracking(std::uint32_t) override
Calls the checkTracking function on each peer.
ServerHandler & serverHandler_
Definition: OverlayImpl.h:112
bool processCrawl(http_request_type const &req, Handoff &handoff)
Handles crawl requests.
int limit() override
Returns the maximum number of peers we are configured to allow.
void updateSlotAndSquelch(uint256 const &key, PublicKey const &validator, std::set< Peer::id_t > &&peers, protocol::MessageType type)
Updates message count for validator/peer.
OverlayImpl(Application &app, Setup const &setup, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_service &io_service, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
beast::Journal const journal_
Definition: OverlayImpl.h:111
boost::container::flat_map< Child *, std::weak_ptr< Child > > list_
Definition: OverlayImpl.h:109
Manages the set of connected peers.
Definition: Overlay.h:49
virtual std::shared_ptr< Slot > new_outbound_slot(beast::IP::Endpoint const &remote_endpoint)=0
Create a new outbound slot with the specified remote endpoint.
bool contains(PublicKey const &nodeId)
A public key.
Definition: PublicKey.h:62
void resolve(std::vector< std::string > const &names, Handler handler)
resolve all hostnames on the list
Definition: Resolver.h:57
Tracks load and resource consumption.
virtual Consumer newInboundEndpoint(beast::IP::Endpoint const &address)=0
Create a new endpoint keyed by inbound IP address or the forwarded IP if proxied.
virtual Consumer newOutboundEndpoint(beast::IP::Endpoint const &address)=0
Create a new endpoint keyed by outbound IP address and port.
std::vector< std::string > const & values() const
Returns all the values in the section.
Definition: BasicConfig.h:79
void setup(Setup const &setup, beast::Journal journal)
auto const & getCounts() const
An up-to-date copy of all the counters.
Definition: TrafficCount.h:241
void addCount(category cat, bool inbound, int bytes)
Account for traffic associated with the given category.
Definition: TrafficCount.h:212
bool listed(PublicKey const &identity) const
Returns true if public key is included on any lists.
std::optional< Json::Value > getAvailable(std::string_view pubKey, std::optional< std::uint32_t > forceVersion={})
Returns the current valid list for the given publisher key, if available, as a Json object.
Json::Value getJson() const
Return a JSON representation of the state of the validator list.
Json::Value getJson() const
Return JSON representation of configured validator sites.
Inject raw JSON.
Definition: jtx_json.h:33
T count(T... args)
T data(T... args)
T emplace_back(T... args)
T emplace(T... args)
T empty(T... args)
T end(T... args)
T find_if(T... args)
T get(T... args)
T make_tuple(T... args)
@ nullValue
'null' value
Definition: json_value.h:39
@ arrayValue
array value (ordered list)
Definition: json_value.h:45
@ objectValue
object value (collection of name/value pairs).
Definition: json_value.h:46
bool is_private(Address const &addr)
Returns true if the address is a private unroutable address.
Definition: IPAddress.h:75
Result split_commas(FwdIt first, FwdIt last)
Definition: rfc2616.h:201
bool is_keep_alive(boost::beast::http::message< isRequest, Body, Fields > const &m)
Definition: rfc2616.h:388
std::string const & getFullVersionString()
Full server version string.
Definition: BuildInfo.cpp:81
@ checkIdlePeers
How often we check for idle peers (seconds)
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
Definition: envconfig.cpp:113
static disabled_t const disabled
Definition: tags.h:50
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::string toBase58(AccountID const &v)
Convert AccountID to base58 checked string.
Definition: AccountID.cpp:114
std::optional< ProtocolVersion > negotiateProtocolVersion(std::vector< ProtocolVersion > const &versions)
Given a list of supported protocol versions, choose the one we prefer.
std::optional< Manifest > deserializeManifest(Slice s, beast::Journal journal)
Constructs Manifest from serialized string.
Definition: Manifest.cpp:54
std::vector< ProtocolVersion > parseProtocolVersions(boost::beast::string_view const &value)
Parse a set of protocol versions.
bool isPseudoTx(STObject const &tx)
Check whether a transaction is a pseudo-transaction.
Definition: STTx.cpp:646
void addValidatorManifest(soci::session &session, std::string const &serialized)
addValidatorManifest Saves the manifest of a validator to the database.
Definition: Wallet.cpp:119
bool set(T &target, std::string const &name, Section const &section)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
Definition: BasicConfig.h:315
std::optional< uint256 > makeSharedValue(stream_type &ssl, beast::Journal journal)
Computes a shared value based on the SSL connection state.
Definition: Handshake.cpp:146
std::shared_ptr< boost::asio::ssl::context > make_SSLContext(std::string const &cipherList)
Create a self-signed SSL context that allows anonymous Diffie Hellman.
std::shared_ptr< Message > makeSquelchMessage(PublicKey const &validator, bool squelch, uint32_t squelchDuration)
std::string strHex(FwdIt begin, FwdIt end)
Definition: strHex.h:30
@ accepted
Manifest is valid.
std::enable_if_t< std::is_same< T, char >::value||std::is_same< T, unsigned char >::value, Slice > makeSlice(std::array< T, N > const &a)
Definition: Slice.h:244
std::string base64_encode(std::uint8_t const *data, std::size_t len)
Definition: base64.cpp:239
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition: chrono.h:119
boost::beast::http::request< boost::beast::http::dynamic_body > http_request_type
Definition: Handoff.h:33
Json::Value getCountsJson(Application &app, int minObjectCount)
Definition: GetCounts.cpp:62
std::string to_string(base_uint< Bits, Tag > const &a)
Definition: base_uint.h:630
PublicKey verifyHandshake(boost::beast::http::fields const &headers, ripple::uint256 const &sharedValue, std::optional< std::uint32_t > networkID, beast::IP::Address public_ip, beast::IP::Address remote, Application &app)
Validate header fields necessary for upgrading the link to the peer protocol.
Definition: Handshake.cpp:227
@ manifest
Manifest.
Overlay::Setup setup_Overlay(BasicConfig const &config)
constexpr Number squelch(Number const &x, Number const &limit) noexcept
Definition: Number.h:363
std::unique_ptr< Overlay > make_Overlay(Application &app, Overlay::Setup const &setup, ServerHandler &serverHandler, Resource::Manager &resourceManager, Resolver &resolver, boost::asio::io_service &io_service, BasicConfig const &config, beast::insight::Collector::ptr const &collector)
Creates the implementation of Overlay.
beast::xor_shift_engine & default_prng()
Return the default random engine.
STL namespace.
T push_back(T... args)
T shuffle(T... args)
T reserve(T... args)
T reset(T... args)
T setfill(T... args)
T setw(T... args)
T size(T... args)
T str(T... args)
static boost::asio::ip::tcp::endpoint to_asio_endpoint(IP::Endpoint const &address)
static IP::Endpoint from_asio(boost::asio::ip::address const &address)
Used to indicate the result of a server connection handoff.
Definition: Handoff.h:40
bool keep_alive
Definition: Handoff.h:46
std::shared_ptr< Writer > response
Definition: Handoff.h:49
void on_timer(error_code ec)
Definition: OverlayImpl.cpp:94
Timer(OverlayImpl &overlay)
Definition: OverlayImpl.cpp:71
beast::IP::Address public_ip
Definition: Overlay.h:69
std::uint32_t crawlOptions
Definition: Overlay.h:71
std::shared_ptr< boost::asio::ssl::context > context
Definition: Overlay.h:68
std::optional< std::uint32_t > networkID
Definition: Overlay.h:72
PeerFinder configuration settings.
static Config makeConfig(ripple::Config const &config, std::uint16_t port, bool validationPublicKey, int ipLimit)
Make PeerFinder::Config from configuration parameters.
void addMetrics(protocol::MessageType type, std::uint32_t val)
Add protocol message metrics.
Definition: TxMetrics.cpp:31
Set the sequence number on a JTx.
Definition: seq.h:34
T substr(T... args)
T to_string(T... args)
T what(T... args)