xrpld
Loading...
Searching...
No Matches
Handouts.h
1#pragma once
2
3#include <xrpld/peerfinder/detail/SlotImp.h>
4#include <xrpld/peerfinder/detail/Tuning.h>
5
6#include <xrpl/beast/container/aged_set.h>
7#include <xrpl/beast/utility/instrumentation.h>
8
9#include <utility>
10
11namespace xrpl::PeerFinder {
12
13namespace detail {
14
19// VFALCO TODO specialization that handles std::list for SequenceContainer
20// using splice for optimization over erase/push_back
21//
22template <class Target, class HopContainer>
24handoutOne(Target& t, HopContainer& h)
25{
26 XRPL_ASSERT(!t.full(), "xrpl::PeerFinder::detail::handoutOne : target is not full");
27 for (auto it = h.begin(); it != h.end(); ++it)
28 {
29 auto const& e = *it;
30 if (t.tryInsert(e))
31 {
32 h.moveBack(it);
33 return 1;
34 }
35 }
36 return 0;
37}
38
39} // namespace detail
40
45template <class TargetFwdIter, class SeqFwdIter>
46void
47handout(TargetFwdIter first, TargetFwdIter last, SeqFwdIter seqFirst, SeqFwdIter seqLast)
48{
49 for (;;)
50 {
51 std::size_t n(0);
52 for (auto si = seqFirst; si != seqLast; ++si)
53 {
54 auto c = *si;
55 bool allFull(true);
56 for (auto ti = first; ti != last; ++ti)
57 {
58 auto& t = *ti;
59 if (!t.full())
60 {
61 n += detail::handoutOne(t, c);
62 allFull = false;
63 }
64 }
65 if (allFull)
66 return;
67 }
68 if (!n)
69 break;
70 }
71}
72
73//------------------------------------------------------------------------------
74
79{
80public:
81 template <class = void>
83
84 template <class = void>
85 bool
86 tryInsert(Endpoint const& ep);
87
88 [[nodiscard]] bool
89 full() const
90 {
92 }
93
94 [[nodiscard]] SlotImp::ptr const&
95 slot() const
96 {
97 return slot_;
98 }
99
102 {
103 return list_;
104 }
105
106 [[nodiscard]] std::vector<Endpoint> const&
107 list() const
108 {
109 return list_;
110 }
111
112private:
115};
116
117template <class>
122
123template <class>
124bool
126{
127 if (full())
128 return false;
129
130 // VFALCO NOTE This check can be removed when we provide the
131 // addresses in a peer HTTP handshake instead of
132 // the tmENDPOINTS message.
133 //
134 if (ep.hops > Tuning::kMaxHops)
135 return false;
136
137 // Don't send them our address
138 if (ep.hops == 0)
139 return false;
140
141 // Don't send them their own address
142 if (slot_->remoteEndpoint().address() == ep.address.address())
143 return false;
144
145 // Make sure the address isn't already in our list
146 if (std::ranges::any_of(list_, [&ep](Endpoint const& other) {
147 // Ignore port for security reasons
148 return other.address.address() == ep.address.address();
149 }))
150 {
151 return false;
152 }
153
154 list_.emplace_back(ep.address, ep.hops);
155
156 return true;
157}
158
159//------------------------------------------------------------------------------
160
163{
164public:
165 template <class = void>
167
168 template <class = void>
169 bool
170 tryInsert(Endpoint const& ep);
171
172 [[nodiscard]] bool
173 full() const
174 {
175 return list_.size() >= Tuning::kNumberOfEndpoints;
176 }
177
178 void
179 insert(Endpoint const& ep)
180 {
181 list_.push_back(ep);
182 }
183
184 [[nodiscard]] SlotImp::ptr const&
185 slot() const
186 {
187 return slot_;
188 }
189
190 [[nodiscard]] std::vector<Endpoint> const&
191 list() const
192 {
193 return list_;
194 }
195
196private:
199};
200
201template <class>
206
207template <class>
208bool
210{
211 if (full())
212 return false;
213
214 if (ep.hops > Tuning::kMaxHops)
215 return false;
216
217 if (slot_->recent.filter(ep.address, ep.hops))
218 return false;
219
220 // Don't send them their own address
221 if (slot_->remoteEndpoint().address() == ep.address.address())
222 return false;
223
224 // Make sure the address isn't already in our list
225 if (std::ranges::any_of(list_, [&ep](Endpoint const& other) {
226 // Ignore port for security reasons
227 return other.address.address() == ep.address.address();
228 }))
229 return false;
230
231 list_.emplace_back(ep.address, ep.hops);
232
233 // Insert into this slot's recent table. Although the endpoint
234 // didn't come from the slot, adding it to the slot's table
235 // prevents us from sending it again until it has expired from
236 // the other end's cache.
237 //
238 slot_->recent.insert(ep.address, ep.hops);
239
240 return true;
241}
242
243//------------------------------------------------------------------------------
244
247{
248public:
249 // Keeps track of addresses we have made outgoing connections
250 // to, for the purposes of not connecting to them too frequently.
252
254
255private:
259
260public:
261 template <class = void>
262 ConnectHandouts(std::size_t needed, Squelches& squelches);
263
264 template <class = void>
265 bool
266 tryInsert(beast::IP::Endpoint const& endpoint);
267
268 [[nodiscard]] bool
269 empty() const
270 {
271 return list_.empty();
272 }
273
274 [[nodiscard]] bool
275 full() const
276 {
277 return list_.size() >= needed_;
278 }
279
280 bool
281 tryInsert(Endpoint const& endpoint)
282 {
283 return tryInsert(endpoint.address);
284 }
285
286 list_type&
288 {
289 return list_;
290 }
291
292 [[nodiscard]] list_type const&
293 list() const
294 {
295 return list_;
296 }
297};
298
299template <class>
301 : needed_(needed), squelches_(squelches)
302{
303 list_.reserve(needed);
304}
305
306template <class>
307bool
309{
310 if (full())
311 return false;
312
313 // Make sure the address isn't already in our list
314 if (std::ranges::any_of(list_, [&endpoint](beast::IP::Endpoint const& other) {
315 // Ignore port for security reasons
316 return other.address() == endpoint.address();
317 }))
318 {
319 return false;
320 }
321
322 // Add to squelch list so we don't try it too often.
323 // If its already there, then make try_insert fail.
324 auto const result(squelches_.insert(endpoint.address()));
325 if (!result.second)
326 return false;
327
328 list_.push_back(endpoint);
329
330 return true;
331}
332
333} // namespace xrpl::PeerFinder
T any_of(T... args)
A version-independent IP address and port combination.
Definition IPEndpoint.h:17
Address const & address() const
Returns the address portion of this endpoint.
Definition IPEndpoint.h:54
std::vector< beast::IP::Endpoint > list_type
Definition Handouts.h:253
bool tryInsert(beast::IP::Endpoint const &endpoint)
Definition Handouts.h:308
list_type const & list() const
Definition Handouts.h:293
ConnectHandouts(std::size_t needed, Squelches &squelches)
Definition Handouts.h:300
bool tryInsert(Endpoint const &endpoint)
Definition Handouts.h:281
beast::aged_set< beast::IP::Address > Squelches
Definition Handouts.h:251
std::vector< Endpoint > & list()
Definition Handouts.h:101
bool tryInsert(Endpoint const &ep)
Definition Handouts.h:125
RedirectHandouts(SlotImp::ptr slot)
Definition Handouts.h:118
std::vector< Endpoint > const & list() const
Definition Handouts.h:107
std::vector< Endpoint > list_
Definition Handouts.h:114
SlotImp::ptr const & slot() const
Definition Handouts.h:95
std::vector< Endpoint > const & list() const
Definition Handouts.h:191
SlotHandouts(SlotImp::ptr slot)
Definition Handouts.h:202
bool tryInsert(Endpoint const &ep)
Definition Handouts.h:209
void insert(Endpoint const &ep)
Definition Handouts.h:179
std::vector< Endpoint > list_
Definition Handouts.h:198
SlotImp::ptr const & slot() const
Definition Handouts.h:185
std::shared_ptr< SlotImp > ptr
Definition SlotImp.h:16
detail::AgedOrderedContainer< false, false, Key, void, Clock, Compare, Allocator > aged_set
Definition aged_set.h:16
STL namespace.
std::size_t handoutOne(Target &t, HopContainer &h)
Try to insert one object in the target.
Definition Handouts.h:24
void handout(TargetFwdIter first, TargetFwdIter last, SeqFwdIter seqFirst, SeqFwdIter seqLast)
Distributes objects to targets according to business rules.
Definition Handouts.h:47
Describes a connectable peer address along with some metadata.