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