20#ifndef RIPPLE_PEERFINDER_LOGIC_H_INCLUDED
21#define RIPPLE_PEERFINDER_LOGIC_H_INCLUDED
23#include <xrpld/peerfinder/PeerfinderManager.h>
24#include <xrpld/peerfinder/detail/Bootcache.h>
25#include <xrpld/peerfinder/detail/Counts.h>
26#include <xrpld/peerfinder/detail/Fixed.h>
27#include <xrpld/peerfinder/detail/Handouts.h>
28#include <xrpld/peerfinder/detail/Livecache.h>
29#include <xrpld/peerfinder/detail/SlotImp.h>
30#include <xrpld/peerfinder/detail/Source.h>
31#include <xrpld/peerfinder/detail/Store.h>
32#include <xrpld/peerfinder/detail/iosformat.h>
34#include <xrpl/basics/Log.h>
35#include <xrpl/basics/contract.h>
36#include <xrpl/basics/random.h>
37#include <xrpl/beast/net/IPAddressConversion.h>
52template <
class Checker>
185 if (addresses.
empty())
188 <<
"Could not resolve fixed slot '" << name <<
"'";
192 for (
auto const& remote_address : addresses)
194 if (remote_address.port() == 0)
196 Throw<std::runtime_error>(
197 "Port not specified for address:" +
198 remote_address.to_string());
201 auto result(
fixed_.emplace(
210 <<
"' at " << remote_address;
223 boost::system::error_code ec)
225 if (ec == boost::asio::error::operation_aborted)
234 <<
beast::leftw(18) <<
"Logic tested " << checkedAddress
235 <<
" but the connection was closed";
249 <<
" with error, " << ec.message();
257 << checkedAddress <<
" succeeded";
268 <<
beast::leftw(18) <<
"Logic accept" << remote_endpoint
269 <<
" on local " << local_endpoint;
274 if (is_public(remote_endpoint))
282 << remote_endpoint <<
" because of ip limits.";
291 <<
beast::leftw(18) <<
"Logic dropping " << remote_endpoint
292 <<
" as duplicate incoming";
303 auto const result(
slots_.
emplace(slot->remote_endpoint(), slot));
307 "ripple::PeerFinder::Logic::new_inbound_slot : remote endpoint "
315 return {result.first->second, Result::success};
323 <<
beast::leftw(18) <<
"Logic connect " << remote_endpoint;
331 <<
beast::leftw(18) <<
"Logic dropping " << remote_endpoint
332 <<
" as duplicate connect";
341 auto const result =
slots_.
emplace(slot->remote_endpoint(), slot);
345 "ripple::PeerFinder::Logic::new_outbound_slot : remote endpoint "
354 return {result.first->second, Result::success};
363 <<
beast::leftw(18) <<
"Logic connected" << slot->remote_endpoint()
364 <<
" on local " << local_endpoint;
371 "ripple::PeerFinder::Logic::onConnected : valid slot input");
373 slot->local_endpoint(local_endpoint);
381 iter->second->local_endpoint() == slot->remote_endpoint(),
382 "ripple::PeerFinder::Logic::onConnected : local and remote "
383 "endpoints do match");
386 << slot->remote_endpoint() <<
" as self connect";
402 <<
beast::leftw(18) <<
"Logic handshake " << slot->remote_endpoint()
403 <<
" with " << (reserved ?
"reserved " :
"") <<
"key " << key;
410 "ripple::PeerFinder::Logic::activate : valid slot input");
414 "ripple::PeerFinder::Logic::activate : valid slot state");
418 return Result::duplicatePeer;
423 slot->reserved(reserved);
429 if (!slot->inbound())
432 return Result::inboundDisabled;
438 slot->public_key(key);
440 [[maybe_unused]]
bool const inserted =
keys_.insert(key).second;
444 "ripple::PeerFinder::Logic::activate : public key inserted");
452 if (!slot->inbound())
456 if (slot->fixed() && !slot->inbound())
458 auto iter(
fixed_.find(slot->remote_endpoint()));
461 "PeerFinder::Logic::activate(): remote_endpoint "
462 "missing from fixed_");
466 << slot->remote_endpoint() <<
" success";
469 return Result::success;
483 return std::move(h.
list());
508 for (
auto const& s :
slots_)
560 << ((h.
list().
size() > 1) ?
"endpoints" :
"endpoint");
598 << ((h.
list().
size() > 1) ?
"addresses" :
"address");
626 [&slots](Slots::value_type
const& value) {
627 if (value.second->state() == Slot::active)
628 slots.emplace_back(value.second);
638 targets.emplace_back(slot);
667 for (
auto& t : targets)
680 for (
auto const& t : targets)
683 auto const& list = t.list();
686 << slot->remote_endpoint() <<
" with " << list.size()
687 << ((list.size() == 1) ?
" endpoint" :
" endpoints");
706 for (
auto const& entry :
slots_)
707 entry.second->expire();
721 bool neighbor(
false);
722 for (
auto iter = list.
begin(); iter != list.
end();)
731 <<
" for excess hops " << ep.
hops;
732 iter = list.
erase(iter);
744 slot->remote_endpoint().at_port(ep.
address.
port());
750 <<
" for extra self";
751 iter = list.
erase(iter);
760 << ep.
address <<
" as invalid";
761 iter = list.
erase(iter);
769 [ep](Endpoints::value_type
const& other) {
770 return ep.address == other.address;
774 << ep.
address <<
" as duplicate";
775 iter = list.
erase(iter);
799 <<
beast::leftw(18) <<
"Endpoints from " << slot->remote_endpoint()
800 <<
" contained " << list.
size()
801 << ((list.
size() > 1) ?
" entries" :
" entry");
808 "ripple::PeerFinder::Logic::on_endpoints : valid slot input");
813 "ripple::PeerFinder::Logic::on_endpoints : valid slot state");
818 if (slot->whenAcceptEndpoints > now)
823 for (
auto const& ep : list)
827 "ripple::PeerFinder::Logic::on_endpoints : nonzero hops");
829 slot->recent.insert(ep.address, ep.hops);
836 if (slot->connectivityCheckInProgress)
840 <<
" already in progress";
847 slot->connectivityCheckInProgress =
true;
857 slot->remote_endpoint(),
859 std::placeholders::_1));
870 if (!slot->canAccept)
891 auto const iter =
slots_.
find(slot->remote_endpoint());
895 "PeerFinder::Logic::remove(): remote_endpoint "
896 "missing from slots_");
904 auto const iter =
keys_.find(*slot->public_key());
906 if (iter ==
keys_.end())
908 "PeerFinder::Logic::remove(): public_key missing "
920 "PeerFinder::Logic::remove(): remote_endpont "
921 "address missing from connectedAddresses_");
938 if (slot->fixed() && !slot->inbound() && slot->state() !=
Slot::active)
940 auto iter(
fixed_.find(slot->remote_endpoint()));
943 "PeerFinder::Logic::on_closed(): remote_endpont "
944 "missing from fixed_");
948 << slot->remote_endpoint() <<
" failed";
952 switch (slot->state())
956 << slot->remote_endpoint() <<
" failed";
971 << slot->remote_endpoint();
976 << slot->remote_endpoint();
981 "ripple::PeerFinder::Logic::on_closed : invalid slot "
996 template <
class FwdIter>
1001 boost::asio::ip::tcp::endpoint
const& remote_address);
1010 for (
auto const& entry :
fixed_)
1011 if (entry.first == endpoint)
1022 for (
auto const& entry :
fixed_)
1023 if (entry.first.address() == address)
1035 template <
class Container>
1043 for (
auto iter =
fixed_.begin(); needed && iter !=
fixed_.end(); ++iter)
1045 auto const& address(iter->first.address());
1046 if (iter->second.when() <= now &&
1047 squelches.
find(address) == squelches.
end() &&
1051 [address](Slots::value_type
const& v) {
1052 return address == v.first.address();
1055 squelches.
insert(iter->first.address());
1056 c.push_back(iter->first);
1090 for (
auto addr : list)
1129 <<
beast::leftw(18) <<
"Logic added " << count <<
" new "
1130 << ((count == 1) ?
"address" :
"addresses") <<
" from "
1136 <<
"'" << source->name() <<
"' fetch, "
1137 << results.
error.message();
1151 if (is_unspecified(address))
1153 if (!is_public(address))
1155 if (address.
port() == 0)
1169 for (
auto const& entry : slots)
1172 SlotImp const& slot(*entry.second);
1177 item[
"inbound"] =
"yes";
1179 item[
"fixed"] =
"yes";
1181 item[
"reserved"] =
"yes";
1260template <
class Checker>
1261template <
class FwdIter>
1266 boost::asio::ip::tcp::endpoint
const& remote_address)
1274 JLOG(m_journal.trace()) <<
beast::leftw(18) <<
"Logic add " << n
1275 <<
" redirect IPs from " << remote_address;
A version-independent IP address and port combination.
Address const & address() const
Returns the address portion of this endpoint.
Endpoint at_port(Port port) const
Returns a new Endpoint with a different port.
Port port() const
Returns the port number on the endpoint.
A generic endpoint for log messages.
Stream trace() const
Severity stream access functions.
typename Clock::time_point time_point
virtual time_point now() const =0
Returns the current time.
Associative container where each element is also indexed by time.
auto insert(value_type const &value) -> typename std::enable_if<!maybe_multi, std::pair< iterator, bool > >::type
void touch(beast::detail::aged_container_iterator< is_const, Iterator > pos)
iterator find(K const &k)
Stores IP addresses useful for gaining initial connections.
map_type::size_type size() const
Returns the number of entries in the cache.
const_iterator end() const
void periodicActivity()
Stores the cache in the persistent database on a timer.
bool insert(beast::IP::Endpoint const &endpoint)
Add a newly-learned address to the cache.
void on_failure(beast::IP::Endpoint const &endpoint)
Called when an outbound connection attempt fails to handshake.
const_iterator begin() const
IP::Endpoint iterators that traverse in decreasing valence.
void onWrite(beast::PropertyStream::Map &map)
Write the cache state to the property stream.
void on_success(beast::IP::Endpoint const &endpoint)
Called when an outbound connection handshake completes.
bool insertStatic(beast::IP::Endpoint const &endpoint)
Add a staticallyconfigured address to the cache.
void load()
Load the persisted data from the Store into the container.
Tests remote listening sockets to make sure they are connectible.
void async_connect(beast::IP::Endpoint const &endpoint, Handler &&handler)
Performs an async connection test on the specified endpoint.
Receives handouts for making automatic connections.
bool try_insert(beast::IP::Endpoint const &endpoint)
Manages the count of available connections for the various slots.
std::size_t fixed_active() const
Returns the number of active fixed connections.
int out_active() const
Returns the number of outbound peers assigned an open slot.
std::size_t attempts_needed() const
Returns the number of attempts needed to bring us to the max.
void onWrite(beast::PropertyStream::Map &map)
Output statistics.
int out_max() const
Returns the total number of outbound slots.
void add(Slot const &s)
Adds the slot state and properties to the slot counts.
int in_max() const
Returns the total number of inbound slots.
void remove(Slot const &s)
Removes the slot state and properties from the slot counts.
void onConfig(Config const &config)
Called when the config is set or changed.
bool can_activate(Slot const &s) const
Returns true if the slot can become active.
std::size_t attempts() const
Returns the number of outbound connection attempts.
void shuffle()
Shuffle each hop list.
reverse_iterator rbegin()
The Livecache holds the short-lived relayed Endpoint messages.
void expire()
Erase entries whose time has expired.
void insert(Endpoint const &ep)
Creates or updates an existing Element based on a new message.
void onWrite(beast::PropertyStream::Map &map)
Output statistics.
class ripple::PeerFinder::Livecache::hops_t hops
The Logic for maintaining the list of Slot addresses.
void stop()
Stop the logic.
bool fixed(beast::IP::Endpoint const &endpoint) const
int addBootcacheAddresses(IPAddresses const &list)
void onWrite(beast::PropertyStream::Map &map)
std::recursive_mutex lock_
void fetch(std::shared_ptr< Source > const &source)
bool onConnected(SlotImp::ptr const &slot, beast::IP::Endpoint const &local_endpoint)
bool is_valid_address(beast::IP::Endpoint const &address)
std::vector< std::pair< std::shared_ptr< Slot >, std::vector< Endpoint > > > buildEndpointsForPeers()
void on_closed(SlotImp::ptr const &slot)
void addFixedPeer(std::string const &name, std::vector< beast::IP::Endpoint > const &addresses)
void on_failure(SlotImp::ptr const &slot)
std::set< PublicKey > keys_
void preprocess(SlotImp::ptr const &slot, Endpoints &list)
void checkComplete(beast::IP::Endpoint const &remoteAddress, beast::IP::Endpoint const &checkedAddress, boost::system::error_code ec)
Result activate(SlotImp::ptr const &slot, PublicKey const &key, bool reserved)
bool fixed(beast::IP::Address const &address) const
std::shared_ptr< Source > fetchSource_
void remove(SlotImp::ptr const &slot)
std::pair< SlotImp::ptr, Result > new_inbound_slot(beast::IP::Endpoint const &local_endpoint, beast::IP::Endpoint const &remote_endpoint)
clock_type::time_point m_whenBroadcast
std::multiset< beast::IP::Address > connectedAddresses_
void get_fixed(std::size_t needed, Container &c, typename ConnectHandouts::Squelches &squelches)
Adds eligible Fixed addresses for outbound attempts.
std::vector< beast::IP::Endpoint > autoconnect()
Create new outbound connection attempts as needed.
std::vector< std::shared_ptr< Source > > m_sources
void onRedirects(FwdIter first, FwdIter last, boost::asio::ip::tcp::endpoint const &remote_address)
void addSource(std::shared_ptr< Source > const &source)
void on_endpoints(SlotImp::ptr const &slot, Endpoints list)
void addStaticSource(std::shared_ptr< Source > const &source)
Logic(clock_type &clock, Store &store, Checker &checker, beast::Journal journal)
Counts const & counts() const
void writeSlots(beast::PropertyStream::Set &set, Slots const &slots)
std::pair< SlotImp::ptr, Result > new_outbound_slot(beast::IP::Endpoint const &remote_endpoint)
ConnectHandouts::Squelches m_squelches
void addFixedPeer(std::string const &name, beast::IP::Endpoint const &ep)
std::vector< Endpoint > redirect(SlotImp::ptr const &slot)
Return a list of addresses suitable for redirection.
std::map< beast::IP::Endpoint, Fixed > fixed_
void config(Config const &c)
static std::string stateString(Slot::State state)
Receives handouts for redirecting a connection.
std::vector< Endpoint > & list()
std::optional< beast::IP::Endpoint > const & local_endpoint() const override
The local endpoint of the socket, when known.
bool fixed() const override
Returns true if this is a fixed connection.
bool inbound() const override
Returns true if this is an inbound connection.
bool connectivityCheckInProgress
std::shared_ptr< SlotImp > ptr
void set_listening_port(std::uint16_t port)
State state() const override
Returns the state of the connection.
beast::IP::Endpoint const & remote_endpoint() const override
The remote endpoint of socket.
bool reserved() const override
Returns true if this is a reserved connection.
Abstract persistence for PeerFinder data.
T forward_as_tuple(T... args)
boost::asio::ip::address_v6 AddressV6
boost::asio::ip::address Address
std::enable_if< is_aged_container< AgedContainer >::value, std::size_t >::type expire(AgedContainer &c, std::chrono::duration< Rep, Period > const &age)
Expire aged container items past the specified age.
std::chrono::seconds constexpr secondsPerMessage(151)
std::uint32_t constexpr numberOfEndpointsMax
std::chrono::seconds constexpr recentAttemptDuration(60)
std::uint32_t constexpr maxHops
std::string_view to_string(Result result) noexcept
Converts a Result enum value to its string representation.
Result
Possible results from activating a slot.
void handout(TargetFwdIter first, TargetFwdIter last, SeqFwdIter seq_first, SeqFwdIter seq_last)
Distributes objects to targets according to business rules.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
bool set(T &target, std::string const &name, Section const §ion)
Set a value from a configuration Section If the named value is not found or doesn't parse as a T,...
void LogicError(std::string const &how) noexcept
Called when faulty logic causes a broken invariant.
beast::xor_shift_engine & default_prng()
Return the default random engine.
static IP::Endpoint from_asio(boost::asio::ip::address const &address)
Left justifies a field at the specified width.
PeerFinder configuration settings.
void onWrite(beast::PropertyStream::Map &map)
Write the configuration into a property stream.
bool autoConnect
true if we want to establish connections automatically
int ipLimit
Limit how many incoming connections we allow per IP.
bool wantIncoming
true if we want to accept incoming connections.
std::uint16_t listeningPort
The listening port number.
Describes a connectible peer address along with some metadata.
beast::IP::Endpoint address
boost::system::error_code error