rippled
Loading...
Searching...
No Matches
Handouts.h
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#ifndef RIPPLE_PEERFINDER_HANDOUTS_H_INCLUDED
21#define RIPPLE_PEERFINDER_HANDOUTS_H_INCLUDED
22
23#include <xrpld/peerfinder/detail/SlotImp.h>
24#include <xrpld/peerfinder/detail/Tuning.h>
25
26#include <xrpl/beast/container/aged_set.h>
27#include <xrpl/beast/utility/instrumentation.h>
28
29namespace ripple {
30namespace PeerFinder {
31
32namespace detail {
33
38// VFALCO TODO specialization that handles std::list for SequenceContainer
39// using splice for optimization over erase/push_back
40//
41template <class Target, class HopContainer>
43handout_one(Target& t, HopContainer& h)
44{
45 XRPL_ASSERT(
46 !t.full(),
47 "ripple::PeerFinder::detail::handout_one : target is not full");
48 for (auto it = h.begin(); it != h.end(); ++it)
49 {
50 auto const& e = *it;
51 if (t.try_insert(e))
52 {
53 h.move_back(it);
54 return 1;
55 }
56 }
57 return 0;
58}
59
60} // namespace detail
61
66template <class TargetFwdIter, class SeqFwdIter>
67void
69 TargetFwdIter first,
70 TargetFwdIter last,
71 SeqFwdIter seq_first,
72 SeqFwdIter seq_last)
73{
74 for (;;)
75 {
76 std::size_t n(0);
77 for (auto si = seq_first; si != seq_last; ++si)
78 {
79 auto c = *si;
80 bool all_full(true);
81 for (auto ti = first; ti != last; ++ti)
82 {
83 auto& t = *ti;
84 if (!t.full())
85 {
86 n += detail::handout_one(t, c);
87 all_full = false;
88 }
89 }
90 if (all_full)
91 return;
92 }
93 if (!n)
94 break;
95 }
96}
97
98//------------------------------------------------------------------------------
99
104{
105public:
106 template <class = void>
107 explicit RedirectHandouts(SlotImp::ptr const& slot);
108
109 template <class = void>
110 bool
111 try_insert(Endpoint const& ep);
112
113 bool
114 full() const
115 {
116 return list_.size() >= Tuning::redirectEndpointCount;
117 }
118
119 SlotImp::ptr const&
120 slot() const
121 {
122 return slot_;
123 }
124
127 {
128 return list_;
129 }
130
132 list() const
133 {
134 return list_;
135 }
136
137private:
140};
141
142template <class>
147
148template <class>
149bool
151{
152 if (full())
153 return false;
154
155 // VFALCO NOTE This check can be removed when we provide the
156 // addresses in a peer HTTP handshake instead of
157 // the tmENDPOINTS message.
158 //
159 if (ep.hops > Tuning::maxHops)
160 return false;
161
162 // Don't send them our address
163 if (ep.hops == 0)
164 return false;
165
166 // Don't send them their own address
167 if (slot_->remote_endpoint().address() == ep.address.address())
168 return false;
169
170 // Make sure the address isn't already in our list
171 if (std::any_of(list_.begin(), list_.end(), [&ep](Endpoint const& other) {
172 // Ignore port for security reasons
173 return other.address.address() == ep.address.address();
174 }))
175 {
176 return false;
177 }
178
179 list_.emplace_back(ep.address, ep.hops);
180
181 return true;
182}
183
184//------------------------------------------------------------------------------
185
188{
189public:
190 template <class = void>
191 explicit SlotHandouts(SlotImp::ptr const& slot);
192
193 template <class = void>
194 bool
195 try_insert(Endpoint const& ep);
196
197 bool
198 full() const
199 {
200 return list_.size() >= Tuning::numberOfEndpoints;
201 }
202
203 void
204 insert(Endpoint const& ep)
205 {
206 list_.push_back(ep);
207 }
208
209 SlotImp::ptr const&
210 slot() const
211 {
212 return slot_;
213 }
214
216 list() const
217 {
218 return list_;
219 }
220
221private:
224};
225
226template <class>
227SlotHandouts::SlotHandouts(SlotImp::ptr const& slot) : slot_(slot)
228{
230}
231
232template <class>
233bool
235{
236 if (full())
237 return false;
238
239 if (ep.hops > Tuning::maxHops)
240 return false;
241
242 if (slot_->recent.filter(ep.address, ep.hops))
243 return false;
244
245 // Don't send them their own address
246 if (slot_->remote_endpoint().address() == ep.address.address())
247 return false;
248
249 // Make sure the address isn't already in our list
250 if (std::any_of(list_.begin(), list_.end(), [&ep](Endpoint const& other) {
251 // Ignore port for security reasons
252 return other.address.address() == ep.address.address();
253 }))
254 return false;
255
256 list_.emplace_back(ep.address, ep.hops);
257
258 // Insert into this slot's recent table. Although the endpoint
259 // didn't come from the slot, adding it to the slot's table
260 // prevents us from sending it again until it has expired from
261 // the other end's cache.
262 //
263 slot_->recent.insert(ep.address, ep.hops);
264
265 return true;
266}
267
268//------------------------------------------------------------------------------
269
272{
273public:
274 // Keeps track of addresses we have made outgoing connections
275 // to, for the purposes of not connecting to them too frequently.
277
279
280private:
284
285public:
286 template <class = void>
287 ConnectHandouts(std::size_t needed, Squelches& squelches);
288
289 template <class = void>
290 bool
291 try_insert(beast::IP::Endpoint const& endpoint);
292
293 bool
294 empty() const
295 {
296 return m_list.empty();
297 }
298
299 bool
300 full() const
301 {
302 return m_list.size() >= m_needed;
303 }
304
305 bool
306 try_insert(Endpoint const& endpoint)
307 {
308 return try_insert(endpoint.address);
309 }
310
311 list_type&
313 {
314 return m_list;
315 }
316
317 list_type const&
318 list() const
319 {
320 return m_list;
321 }
322};
323
324template <class>
326 : m_needed(needed), m_squelches(squelches)
327{
328 m_list.reserve(needed);
329}
330
331template <class>
332bool
334{
335 if (full())
336 return false;
337
338 // Make sure the address isn't already in our list
339 if (std::any_of(
340 m_list.begin(),
341 m_list.end(),
342 [&endpoint](beast::IP::Endpoint const& other) {
343 // Ignore port for security reasons
344 return other.address() == endpoint.address();
345 }))
346 {
347 return false;
348 }
349
350 // Add to squelch list so we don't try it too often.
351 // If its already there, then make try_insert fail.
352 auto const result(m_squelches.insert(endpoint.address()));
353 if (!result.second)
354 return false;
355
356 m_list.push_back(endpoint);
357
358 return true;
359}
360
361} // namespace PeerFinder
362} // namespace ripple
363
364#endif
T any_of(T... args)
T begin(T... args)
A version-independent IP address and port combination.
Definition IPEndpoint.h:38
Address const & address() const
Returns the address portion of this endpoint.
Definition IPEndpoint.h:75
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
Receives handouts for making automatic connections.
Definition Handouts.h:272
std::vector< beast::IP::Endpoint > list_type
Definition Handouts.h:278
ConnectHandouts(std::size_t needed, Squelches &squelches)
Definition Handouts.h:325
bool try_insert(beast::IP::Endpoint const &endpoint)
Definition Handouts.h:333
bool try_insert(Endpoint const &endpoint)
Definition Handouts.h:306
list_type const & list() const
Definition Handouts.h:318
Receives handouts for redirecting a connection.
Definition Handouts.h:104
std::vector< Endpoint > list_
Definition Handouts.h:139
bool try_insert(Endpoint const &ep)
Definition Handouts.h:150
SlotImp::ptr const & slot() const
Definition Handouts.h:120
std::vector< Endpoint > & list()
Definition Handouts.h:126
RedirectHandouts(SlotImp::ptr const &slot)
Definition Handouts.h:143
std::vector< Endpoint > const & list() const
Definition Handouts.h:132
Receives endpoints for a slot during periodic handouts.
Definition Handouts.h:188
void insert(Endpoint const &ep)
Definition Handouts.h:204
SlotHandouts(SlotImp::ptr const &slot)
Definition Handouts.h:227
std::vector< Endpoint > const & list() const
Definition Handouts.h:216
std::vector< Endpoint > list_
Definition Handouts.h:223
bool try_insert(Endpoint const &ep)
Definition Handouts.h:234
SlotImp::ptr const & slot() const
Definition Handouts.h:210
T empty(T... args)
T end(T... args)
std::size_t handout_one(Target &t, HopContainer &h)
Try to insert one object in the target.
Definition Handouts.h:43
void handout(TargetFwdIter first, TargetFwdIter last, SeqFwdIter seq_first, SeqFwdIter seq_last)
Distributes objects to targets according to business rules.
Definition Handouts.h:68
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
T push_back(T... args)
T reserve(T... args)
T size(T... args)
Describes a connectible peer address along with some metadata.