BitShares-Core  7.0.2
BitShares blockchain node software and command-line wallet software
peer_database.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
3  *
4  * The MIT License
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22  * THE SOFTWARE.
23  */
24 #include <boost/multi_index_container.hpp>
25 #include <boost/multi_index/ordered_index.hpp>
26 #include <boost/multi_index/hashed_index.hpp>
27 #include <boost/multi_index/member.hpp>
28 #include <boost/multi_index/mem_fun.hpp>
29 #include <boost/multi_index/tag.hpp>
30 
31 #include <fc/io/raw.hpp>
32 #include <fc/io/raw_variant.hpp>
33 #include <fc/log/logger.hpp>
34 #include <fc/io/json.hpp>
35 
37 #include <graphene/net/config.hpp>
38 
39 namespace graphene { namespace net {
40  namespace detail
41  {
42  using namespace boost::multi_index;
43 
45  {
46  public:
48  struct endpoint_index {};
49  typedef boost::multi_index_container<potential_peer_record,
50  indexed_by<ordered_non_unique<tag<last_seen_time_index>,
51  member<potential_peer_record,
54  std::greater<fc::time_point_sec> >,
55  hashed_unique<tag<endpoint_index>,
56  member<potential_peer_record,
60 
61  private:
62  potential_peer_set _potential_peer_set;
63  fc::path _peer_database_filename;
64 
65  public:
66  void open(const fc::path& databaseFilename);
67  void close();
68  void clear();
69  void erase(const fc::ip::endpoint& endpointToErase);
70  void update_entry(const potential_peer_record& updatedRecord);
71  potential_peer_record lookup_or_create_entry_for_ep(const fc::ip::endpoint& endpointToLookup)const;
72  fc::optional<potential_peer_record> lookup_entry_for_endpoint(const fc::ip::endpoint& endpointToLookup)const;
73 
74  peer_database::iterator begin() const;
75  peer_database::iterator end() const;
76  size_t size() const;
77  };
78 
80  {
81  public:
82  typedef peer_database_impl::potential_peer_set::index<peer_database_impl::last_seen_time_index>::type::iterator last_seen_time_index_iterator;
85  _iterator(iterator)
86  {}
87  };
89  boost::iterator_facade<peer_database_iterator, const potential_peer_record, boost::forward_traversal_tag>(c){}
90 
91  void peer_database_impl::open(const fc::path& peer_database_filename)
92  {
93  _peer_database_filename = peer_database_filename;
94  if (fc::exists(_peer_database_filename))
95  {
96  try
97  {
98  std::vector<potential_peer_record> peer_records = fc::json::from_file(_peer_database_filename).as<std::vector<potential_peer_record> >( GRAPHENE_NET_MAX_NESTED_OBJECTS );
99  std::copy(peer_records.begin(), peer_records.end(), std::inserter(_potential_peer_set, _potential_peer_set.end()));
100  if (_potential_peer_set.size() > MAXIMUM_PEERDB_SIZE)
101  {
102  // prune database to a reasonable size
103  auto iter = _potential_peer_set.begin();
104  std::advance(iter, MAXIMUM_PEERDB_SIZE);
105  _potential_peer_set.erase(iter, _potential_peer_set.end());
106  }
107  }
108  catch (const fc::exception& e)
109  {
110  elog("error opening peer database file ${peer_database_filename}, starting with a clean database",
111  ("peer_database_filename", _peer_database_filename));
112  }
113  }
114  }
115 
117  {
118  std::vector<potential_peer_record> peer_records;
119  peer_records.reserve(_potential_peer_set.size());
120  std::copy(_potential_peer_set.begin(), _potential_peer_set.end(), std::back_inserter(peer_records));
121 
122  try
123  {
124  fc::path peer_database_filename_dir = _peer_database_filename.parent_path();
125  if (!fc::exists(peer_database_filename_dir))
126  fc::create_directories(peer_database_filename_dir);
127  fc::json::save_to_file( peer_records, _peer_database_filename, GRAPHENE_NET_MAX_NESTED_OBJECTS );
128  dlog( "Saved peer database to file ${filename}", ( "filename", _peer_database_filename) );
129  }
130  catch (const fc::exception& e)
131  {
132  wlog( "error saving peer database to file ${peer_database_filename}: ${error}",
133  ("peer_database_filename", _peer_database_filename)("error", e.to_detail_string()) );
134  }
135  _potential_peer_set.clear();
136  }
137 
139  {
140  _potential_peer_set.clear();
141  }
142 
143  void peer_database_impl::erase(const fc::ip::endpoint& endpointToErase)
144  {
145  auto iter = _potential_peer_set.get<endpoint_index>().find(endpointToErase);
146  if (iter != _potential_peer_set.get<endpoint_index>().end())
147  _potential_peer_set.get<endpoint_index>().erase(iter);
148  }
149 
151  {
152  auto iter = _potential_peer_set.get<endpoint_index>().find(updatedRecord.endpoint);
153  if (iter != _potential_peer_set.get<endpoint_index>().end())
154  _potential_peer_set.get<endpoint_index>().modify(iter, [&updatedRecord](potential_peer_record& record) { record = updatedRecord; });
155  else
156  _potential_peer_set.get<endpoint_index>().insert(updatedRecord);
157  }
158 
160  const fc::ip::endpoint& endpointToLookup ) const
161  {
162  auto iter = _potential_peer_set.get<endpoint_index>().find(endpointToLookup);
163  if (iter != _potential_peer_set.get<endpoint_index>().end())
164  return *iter;
165  return potential_peer_record(endpointToLookup);
166  }
167 
169  const fc::ip::endpoint& endpointToLookup ) const
170  {
171  auto iter = _potential_peer_set.get<endpoint_index>().find(endpointToLookup);
172  if (iter != _potential_peer_set.get<endpoint_index>().end())
173  return *iter;
175  }
176 
178  {
179  return peer_database::iterator( std::make_unique<peer_database_iterator_impl>(
180  _potential_peer_set.get<last_seen_time_index>().begin() ) );
181  }
182 
184  {
185  return peer_database::iterator( std::make_unique<peer_database_iterator_impl>(
186  _potential_peer_set.get<last_seen_time_index>().end() ) );
187  }
188 
190  {
191  return _potential_peer_set.size();
192  }
193 
195  {
196  }
197 
199  {
200  }
201 
202  peer_database_iterator::peer_database_iterator( std::unique_ptr<peer_database_iterator_impl>&& impl) :
203  my( std::move(impl) )
204  {
205  }
206 
207  void peer_database_iterator::increment()
208  {
209  ++my->_iterator;
210  }
211 
212  bool peer_database_iterator::equal(const peer_database_iterator& other) const
213  {
214  return my->_iterator == other.my->_iterator;
215  }
216 
217  const potential_peer_record& peer_database_iterator::dereference() const
218  {
219  return *my->_iterator;
220  }
221 
222  } // end namespace detail
223 
225  my( std::make_unique<detail::peer_database_impl>() )
226  {
227  }
228 
230  {}
231 
232  void peer_database::open(const fc::path& databaseFilename)
233  {
234  my->open(databaseFilename);
235  }
236 
238  {
239  my->close();
240  }
241 
243  {
244  my->clear();
245  }
246 
247  void peer_database::erase(const fc::ip::endpoint& endpointToErase)
248  {
249  my->erase(endpointToErase);
250  }
251 
253  {
254  my->update_entry(updatedRecord);
255  }
256 
258  const fc::ip::endpoint& endpointToLookup ) const
259  {
260  return my->lookup_or_create_entry_for_ep(endpointToLookup);
261  }
262 
264  const fc::ip::endpoint& endpoint_to_lookup ) const
265  {
266  return my->lookup_entry_for_endpoint(endpoint_to_lookup);
267  }
268 
270  {
271  return my->begin();
272  }
273 
275  {
276  return my->end();
277  }
278 
279  size_t peer_database::size() const
280  {
281  return my->size();
282  }
283 
284 } } // end namespace graphene::net
285 
291  (endpoint)(last_seen_time)(last_connection_disposition)
292  (last_connection_attempt_time)(number_of_successful_connection_attempts)
293  (number_of_failed_connection_attempts)(last_error) )
294 
fc::copy
void copy(const path &from, const path &to)
Definition: filesystem.cpp:241
graphene::net::peer_database::clear
void clear()
Definition: peer_database.cpp:242
graphene::net::detail::peer_database_impl::close
void close()
Definition: peer_database.cpp:116
graphene::net::potential_peer_last_connection_disposition
potential_peer_last_connection_disposition
Definition: peer_database.hpp:38
std::hash< fc::ip::endpoint >
Definition: ip.hpp:149
graphene::net::last_connection_failed
@ last_connection_failed
Definition: peer_database.hpp:41
graphene::net::detail::peer_database_impl::clear
void clear()
Definition: peer_database.cpp:138
graphene::net::peer_database::end
iterator end() const
Definition: peer_database.cpp:274
graphene::net::potential_peer_record::last_seen_time
fc::time_point_sec last_seen_time
Definition: peer_database.hpp:50
graphene::net::detail::peer_database_impl::endpoint_index
Definition: peer_database.cpp:48
graphene::net::peer_database::lookup_or_create_entry_for_ep
potential_peer_record lookup_or_create_entry_for_ep(const fc::ip::endpoint &endpointToLookup) const
Definition: peer_database.cpp:257
graphene::net::peer_database::size
size_t size() const
Definition: peer_database.cpp:279
wlog
#define wlog(FORMAT,...)
Definition: logger.hpp:123
graphene::net::detail::peer_database_iterator::~peer_database_iterator
~peer_database_iterator()
Definition: peer_database.cpp:198
fc::exception
Used to generate a useful error report when an exception is thrown.
Definition: exception.hpp:56
graphene::net::detail::peer_database_impl::last_seen_time_index
Definition: peer_database.cpp:47
graphene::net::peer_database::open
void open(const fc::path &databaseFilename)
Definition: peer_database.cpp:232
graphene::net::peer_database::erase
void erase(const fc::ip::endpoint &endpointToErase)
Definition: peer_database.cpp:247
graphene::net::detail::peer_database_impl::erase
void erase(const fc::ip::endpoint &endpointToErase)
Definition: peer_database.cpp:143
graphene::net::detail::peer_database_impl::update_entry
void update_entry(const potential_peer_record &updatedRecord)
Definition: peer_database.cpp:150
graphene::net::detail::peer_database_iterator_impl::last_seen_time_index_iterator
peer_database_impl::potential_peer_set::index< peer_database_impl::last_seen_time_index >::type::iterator last_seen_time_index_iterator
Definition: peer_database.cpp:82
GRAPHENE_NET_MAX_NESTED_OBJECTS
#define GRAPHENE_NET_MAX_NESTED_OBJECTS
Definition: config.hpp:112
graphene::net::last_connection_rejected
@ last_connection_rejected
Definition: peer_database.hpp:42
graphene::net::peer_database::iterator
detail::peer_database_iterator iterator
Definition: peer_database.hpp:111
graphene::net::detail::peer_database_impl
Definition: peer_database.cpp:44
graphene::net::detail::peer_database_iterator_impl::_iterator
last_seen_time_index_iterator _iterator
Definition: peer_database.cpp:83
graphene::net::potential_peer_record::endpoint
fc::ip::endpoint endpoint
Definition: peer_database.hpp:49
graphene::net::detail::peer_database_impl::end
peer_database::iterator end() const
Definition: peer_database.cpp:183
GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION
#define GRAPHENE_IMPLEMENT_EXTERNAL_SERIALIZATION(type)
Definition: types.hpp:86
graphene::net::potential_peer_record
Definition: peer_database.hpp:47
fc::asio::tcp::endpoint
boost::asio::ip::tcp::endpoint endpoint
Definition: asio.hpp:239
fc::ip::endpoint
Definition: ip.hpp:65
graphene::net::detail::peer_database_iterator
Definition: peer_database.hpp:74
graphene::net::detail::peer_database_impl::lookup_entry_for_endpoint
fc::optional< potential_peer_record > lookup_entry_for_endpoint(const fc::ip::endpoint &endpointToLookup) const
Definition: peer_database.cpp:168
fc::path
wraps boost::filesystem::path to provide platform independent path manipulation.
Definition: filesystem.hpp:28
graphene::net::detail::peer_database_impl::open
void open(const fc::path &databaseFilename)
Definition: peer_database.cpp:91
graphene::net::detail::peer_database_iterator_impl
Definition: peer_database.cpp:79
dlog
#define dlog(FORMAT,...)
Definition: logger.hpp:100
raw_variant.hpp
fc::time_point_sec
Definition: time.hpp:74
fc::variant::as
T as(uint32_t max_depth) const
Definition: variant.hpp:337
FC_REFLECT_DERIVED_NO_TYPENAME
#define FC_REFLECT_DERIVED_NO_TYPENAME(TYPE, INHERITS, MEMBERS)
Definition: reflect.hpp:357
graphene::net::detail::peer_database_iterator::peer_database_iterator
peer_database_iterator()
Definition: peer_database.cpp:194
fc::exception::to_detail_string
std::string to_detail_string(log_level ll=log_level::all) const
Definition: exception.cpp:183
graphene::net::detail::peer_database_impl::potential_peer_set
boost::multi_index_container< potential_peer_record, indexed_by< ordered_non_unique< tag< last_seen_time_index >, member< potential_peer_record, fc::time_point_sec, &potential_peer_record::last_seen_time >, std::greater< fc::time_point_sec > >, hashed_unique< tag< endpoint_index >, member< potential_peer_record, fc::ip::endpoint, &potential_peer_record::endpoint >, std::hash< fc::ip::endpoint > > > > potential_peer_set
Definition: peer_database.cpp:59
graphene::net::last_connection_succeeded
@ last_connection_succeeded
Definition: peer_database.hpp:44
fc::json::save_to_file
static void save_to_file(const T &v, const fc::path &fi, bool pretty=true, output_formatting format=stringify_large_ints_and_doubles, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition: json.hpp:51
graphene::net::peer_database::lookup_entry_for_endpoint
fc::optional< potential_peer_record > lookup_entry_for_endpoint(const fc::ip::endpoint &endpointToLookup) const
Definition: peer_database.cpp:263
graphene::net::detail::peer_database_impl::begin
peer_database::iterator begin() const
Definition: peer_database.cpp:177
json.hpp
graphene::net::last_connection_handshaking_failed
@ last_connection_handshaking_failed
Definition: peer_database.hpp:43
graphene::net::peer_database::~peer_database
virtual ~peer_database()
Definition: peer_database.cpp:229
graphene::net::detail::peer_database_impl::size
size_t size() const
Definition: peer_database.cpp:189
graphene::net::never_attempted_to_connect
@ never_attempted_to_connect
Definition: peer_database.hpp:40
FC_REFLECT_ENUM
FC_REFLECT_ENUM(graphene::net::core_message_type_enum,(trx_message_type)(block_message_type)(core_message_type_first)(item_ids_inventory_message_type)(blockchain_item_ids_inventory_message_type)(fetch_blockchain_item_ids_message_type)(fetch_items_message_type)(item_not_available_message_type)(hello_message_type)(connection_accepted_message_type)(connection_rejected_message_type)(address_request_message_type)(address_message_type)(closing_connection_message_type)(current_time_request_message_type)(current_time_reply_message_type)(check_firewall_message_type)(check_firewall_reply_message_type)(get_current_connections_request_message_type)(get_current_connections_reply_message_type)(core_message_type_last))(different_chain)(already_connected)(connected_to_self)(not_accepting_connections)(blocked)(invalid_hello_message)(client_too_old))(inbound)(outbound))(firewalled)(not_firewalled))(unable_to_connect)(connection_successful)) namespace std
Definition: core_messages.hpp:404
graphene::net::detail::peer_database_iterator_impl::peer_database_iterator_impl
peer_database_iterator_impl(const last_seen_time_index_iterator &iterator)
Definition: peer_database.cpp:84
std
Definition: zeroed_array.hpp:76
fc::path::parent_path
fc::path parent_path() const
Definition: filesystem.cpp:163
graphene::net::peer_database::update_entry
void update_entry(const potential_peer_record &updatedRecord)
Definition: peer_database.cpp:252
logger.hpp
fc::create_directories
void create_directories(const path &p)
Definition: filesystem.cpp:210
fc::optional
provides stack-based nullable value similar to boost::optional
Definition: optional.hpp:20
fc::json::from_file
static variant from_file(const fc::path &p, parse_type ptype=legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition: json.cpp:767
graphene::net::peer_database::begin
iterator begin() const
Definition: peer_database.cpp:269
graphene::net::peer_database::peer_database
peer_database()
Definition: peer_database.cpp:224
MAXIMUM_PEERDB_SIZE
#define MAXIMUM_PEERDB_SIZE
Definition: config.hpp:114
graphene::net::detail::peer_database_impl::lookup_or_create_entry_for_ep
potential_peer_record lookup_or_create_entry_for_ep(const fc::ip::endpoint &endpointToLookup) const
Definition: peer_database.cpp:159
peer_database.hpp
config.hpp
graphene
Definition: api.cpp:48
fc::exists
bool exists(const path &p)
Definition: filesystem.cpp:209
graphene::net::peer_database::close
void close()
Definition: peer_database.cpp:237
elog
#define elog(FORMAT,...)
Definition: logger.hpp:129
raw.hpp