Electroneum
Loading...
Searching...
No Matches
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
46namespace nodetool
47{
48 namespace
49 {
50 constexpr unsigned CURRENT_PEERLIST_STORAGE_ARCHIVE_VER = 6;
51
52 struct by_zone
53 {
54 using zone = epee::net_utils::zone;
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_options::overwrite_existing);
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
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
293BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER);
294BOOST_CLASS_VERSION(nodetool::peerlist_join, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER);
295
void get_peerlist(std::vector< peerlist_entry > &pl_gray, std::vector< peerlist_entry > &pl_white)
bool init(peerlist_types &&peers, bool allow_local_ip)
static boost::optional< peerlist_storage > open(std::istream &src, const bool new_format)
bool store(std::ostream &dest, const peerlist_types &other) const
Save peers from this and other in stream dest.
peerlist_types take_zone(epee::net_utils::zone zone)
#define MWARNING(x)
Definition misc_log_ex.h:74
uint64_t peerid_type
void serialize(Archive &a, peerlist_types &elem, unsigned ver)
BOOST_CLASS_VERSION(nodetool::peerlist_types, nodetool::CURRENT_PEERLIST_STORAGE_ARCHIVE_VER)
const GenericPointer< typename T::ValueType > T2 T::AllocatorType & a
Definition pointer.h:1124
CXA_THROW_INFO_T void(* dest)(void *))
unsigned __int64 uint64_t
Definition stdint.h:136
const peerlist_types & other
const peerlist_types & ours
std::vector< anchor_peerlist_entry > anchor
std::vector< peerlist_entry > gray
std::vector< peerlist_entry > white
#define CRITICAL_REGION_LOCAL(x)
Definition syncobj.h:228
#define T(x)