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