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