Electroneum
net_peerlist.cpp
Go to the documentation of this file.
1 // Copyright (c) 2018, The Monero Project
2 //
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without modification, are
6 // permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice, this list of
9 // conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 // of conditions and the following disclaimer in the documentation and/or other
13 // materials provided with the distribution.
14 //
15 // 3. Neither the name of the copyright holder nor the names of its contributors may be
16 // used to endorse or promote products derived from this software without specific
17 // prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
20 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
27 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 #include "net_peerlist.h"
30 
31 #include <algorithm>
32 #include <functional>
33 #include <fstream>
34 #include <iterator>
35 
36 #include <boost/archive/binary_iarchive.hpp>
39 #include <boost/filesystem/operations.hpp>
40 #include <boost/range/join.hpp>
41 #include <boost/serialization/version.hpp>
42 
44 
45 
46 namespace nodetool
47 {
48  namespace
49  {
50  constexpr unsigned CURRENT_PEERLIST_STORAGE_ARCHIVE_VER = 6;
51 
52  struct by_zone
53  {
55 
56  template<typename T>
57  bool operator()(const T& left, const zone right) const
58  {
59  return left.adr.get_zone() < right;
60  }
61 
62  template<typename T>
63  bool operator()(const zone left, const T& right) const
64  {
65  return left < right.adr.get_zone();
66  }
67 
68  template<typename T, typename U>
69  bool operator()(const T& left, const U& right) const
70  {
71  return left.adr.get_zone() < right.adr.get_zone();
72  }
73  };
74 
75  template<typename Elem, typename Archive>
76  std::vector<Elem> load_peers(Archive& a, unsigned ver)
77  {
78  // at v6, we drop existing peerlists, because annoying change
79  if (ver < 6)
80  return {};
81 
82  uint64_t size = 0;
83  a & size;
84 
85  Elem ple{};
86 
87  std::vector<Elem> elems{};
88  elems.reserve(size);
89  while (size--)
90  {
91  a & ple;
92  elems.push_back(std::move(ple));
93  }
94 
95  return elems;
96  }
97 
98  template<typename Archive, typename Range>
99  void save_peers(Archive& a, const Range& elems)
100  {
101  const uint64_t size = elems.size();
102  a & size;
103  for (const auto& elem : elems)
104  a & elem;
105  }
106 
107  template<typename T>
108  std::vector<T> do_take_zone(std::vector<T>& src, epee::net_utils::zone zone)
109  {
110  const auto start = std::lower_bound(src.begin(), src.end(), zone, by_zone{});
111  const auto end = std::upper_bound(start, src.end(), zone, by_zone{});
112 
113  std::vector<T> out{};
114  out.assign(std::make_move_iterator(start), std::make_move_iterator(end));
115  src.erase(start, end);
116  return out;
117  }
118 
119  template<typename Container, typename T>
120  void add_peers(Container& dest, std::vector<T>&& src)
121  {
122  dest.insert(std::make_move_iterator(src.begin()), std::make_move_iterator(src.end()));
123  }
124 
125  template<typename Container, typename Range>
126  void copy_peers(Container& dest, const Range& src)
127  {
128  std::copy(src.begin(), src.end(), std::back_inserter(dest));
129  }
130  } // anonymous
131 
133  {
136  };
137 
138  template<typename Archive>
139  void serialize(Archive& a, peerlist_types& elem, unsigned ver)
140  {
141  elem.white = load_peers<peerlist_entry>(a, ver);
142  elem.gray = load_peers<peerlist_entry>(a, ver);
143  elem.anchor = load_peers<anchor_peerlist_entry>(a, ver);
144 
145  if (ver == 0)
146  {
147  // from v1, we do not store the peer id anymore
148  peerid_type peer_id{};
149  a & peer_id;
150  }
151  }
152 
153  template<typename Archive>
154  void serialize(Archive& a, peerlist_join elem, unsigned ver)
155  {
156  save_peers(a, boost::range::join(elem.ours.white, elem.other.white));
157  save_peers(a, boost::range::join(elem.ours.gray, elem.other.gray));
158  save_peers(a, boost::range::join(elem.ours.anchor, elem.other.anchor));
159  }
160 
161  boost::optional<peerlist_storage> peerlist_storage::open(std::istream& src, const bool new_format)
162  {
163  try
164  {
165  peerlist_storage out{};
166  if (new_format)
167  {
169  a >> out.m_types;
170  }
171  else
172  {
173  boost::archive::binary_iarchive a{src};
174  a >> out.m_types;
175  }
176 
177  if (src.good())
178  {
179  std::sort(out.m_types.white.begin(), out.m_types.white.end(), by_zone{});
180  std::sort(out.m_types.gray.begin(), out.m_types.gray.end(), by_zone{});
181  std::sort(out.m_types.anchor.begin(), out.m_types.anchor.end(), by_zone{});
182  return {std::move(out)};
183  }
184  }
185  catch (const std::exception& e)
186  {}
187 
188  return boost::none;
189  }
190 
191  boost::optional<peerlist_storage> peerlist_storage::open(const std::string& path)
192  {
193  std::ifstream src_file{};
194  src_file.open( path , std::ios_base::binary | std::ios_base::in);
195  if(src_file.fail())
196  return boost::none;
197 
198  boost::optional<peerlist_storage> out = open(src_file, true);
199  if (!out)
200  {
201  // if failed, try reading in unportable mode
202  boost::filesystem::copy_file(path, path + ".unportable", boost::filesystem::copy_option::overwrite_if_exists);
203  src_file.close();
204  src_file.open( path , std::ios_base::binary | std::ios_base::in);
205  if(src_file.fail())
206  return boost::none;
207 
208  out = open(src_file, false);
209  if (!out)
210  {
211  // This is different from the `return boost::none` cases above. Those
212  // cases could fail due to bad file permissions, so a shutdown is
213  // likely more appropriate.
214  MWARNING("Failed to load p2p config file, falling back to default config");
215  out.emplace();
216  }
217  }
218 
219  return out;
220  }
221 
223  {}
224 
225  bool peerlist_storage::store(std::ostream& dest, const peerlist_types& other) const
226  {
227  try
228  {
230  const peerlist_join pj{std::cref(m_types), std::cref(other)};
231  a << pj;
232  return dest.good();
233  }
234  catch (const boost::archive::archive_exception& e)
235  {}
236 
237  return false;
238  }
239 
240  bool peerlist_storage::store(const std::string& path, const peerlist_types& other) const
241  {
242  std::ofstream dest_file{};
243  dest_file.open( path , std::ios_base::binary | std::ios_base::out| std::ios::trunc);
244  if(dest_file.fail())
245  return false;
246 
247  return store(dest_file, other);
248  }
249 
251  {
252  peerlist_types out{};
253  out.white = do_take_zone(m_types.white, zone);
254  out.gray = do_take_zone(m_types.gray, zone);
255  out.anchor = do_take_zone(m_types.anchor, zone);
256  return out;
257  }
258 
259  bool peerlist_manager::init(peerlist_types&& peers, bool allow_local_ip)
260  {
261  CRITICAL_REGION_LOCAL(m_peerlist_lock);
262 
263  if (!m_peers_white.empty() || !m_peers_gray.empty() || !m_peers_anchor.empty())
264  return false;
265 
266  add_peers(m_peers_white.get<by_addr>(), std::move(peers.white));
267  add_peers(m_peers_gray.get<by_addr>(), std::move(peers.gray));
268  add_peers(m_peers_anchor.get<by_addr>(), std::move(peers.anchor));
269  m_allow_local_ip = allow_local_ip;
270  return true;
271  }
272 
273  void peerlist_manager::get_peerlist(std::vector<peerlist_entry>& pl_gray, std::vector<peerlist_entry>& pl_white)
274  {
275  CRITICAL_REGION_LOCAL(m_peerlist_lock);
276  copy_peers(pl_gray, m_peers_gray.get<by_addr>());
277  copy_peers(pl_white, m_peers_white.get<by_addr>());
278  }
279 
281  {
282  CRITICAL_REGION_LOCAL(m_peerlist_lock);
283  peers.white.reserve(peers.white.size() + m_peers_white.size());
284  peers.gray.reserve(peers.gray.size() + m_peers_gray.size());
285  peers.anchor.reserve(peers.anchor.size() + m_peers_anchor.size());
286 
287  copy_peers(peers.white, m_peers_white.get<by_addr>());
288  copy_peers(peers.gray, m_peers_gray.get<by_addr>());
289  copy_peers(peers.anchor, m_peers_anchor.get<by_addr>());
290  }
291 }
292 
293 BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER);
294 BOOST_CLASS_VERSION(nodetool::peerlist_join, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER);
295 
const peerlist_types & other
std::vector< peerlist_entry > white
Definition: net_peerlist.h:57
const uint32_t T[512]
void get_peerlist(std::vector< peerlist_entry > &pl_gray, std::vector< peerlist_entry > &pl_white)
::std::string string
Definition: gtest-port.h:1097
CXA_THROW_INFO_T void(* dest)(void *))
Definition: stack_trace.cpp:91
static boost::optional< peerlist_storage > open(std::istream &src, const bool new_format)
std::vector< peerlist_entry > gray
Definition: net_peerlist.h:58
void copy(key &AA, const key &A)
Definition: rctOps.h:79
std::vector< anchor_peerlist_entry > anchor
Definition: net_peerlist.h:59
unsigned __int64 uint64_t
Definition: stdint.h:136
#define CRITICAL_REGION_LOCAL(x)
Definition: syncobj.h:228
const peerlist_types & ours
uint64_t peerid_type
#define MWARNING(x)
Definition: misc_log_ex.h:74
bool init(peerlist_types &&peers, bool allow_local_ip)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition: pointer.h:1124
const T & move(const T &t)
Definition: gtest-port.h:1317
BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER)
peerlist_types take_zone(epee::net_utils::zone zone)
void serialize(Archive &a, peerlist_types &elem, unsigned ver)
bool store(std::ostream &dest, const peerlist_types &other) const
Save peers from this and other in stream dest.