From 82dbeedd1bb92a6db31b2e887fee59b4382dc582 Mon Sep 17 00:00:00 2001 From: Miguel Herranz Date: Sat, 21 Jan 2017 00:59:04 +0100 Subject: [PATCH 1/4] Add gray peer list housekeeping system A random peer from the gray peer list is selected and a connection is made to check if the peer is alive. If the connection and handshake are successful the peer is promoted to the white peer list, in case of failure the peer is evicted from the gray peer list. The connection is closed after the check in either case. --- src/p2p/net_node.h | 4 +++ src/p2p/net_node.inl | 71 ++++++++++++++++++++++++++++++++++++++++++ src/p2p/net_peerlist.h | 46 +++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 3f5a5ad93..f5309b1c3 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -229,6 +229,9 @@ namespace nodetool bool has_too_many_connections(const uint32_t ip); + bool check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp); + bool gray_peerlist_housekeeping(); + void kill() { ///< will be called e.g. from deinit() _info("Killing the net_node"); is_closing = true; @@ -289,6 +292,7 @@ namespace nodetool epee::math_helper::once_a_time_seconds m_peer_handshake_idle_maker_interval; epee::math_helper::once_a_time_seconds<1> m_connections_maker_interval; epee::math_helper::once_a_time_seconds<60*30, false> m_peerlist_store_interval; + epee::math_helper::once_a_time_seconds<60> m_gray_peerlist_housekeeping_interval; std::string m_bind_ip; std::string m_port; diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 60e51c222..3933fe65b 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -926,6 +926,50 @@ namespace nodetool return true; } + template + bool node_server::check_connection_and_handshake_with_peer(const net_address& na, uint64_t last_seen_stamp) + { + LOG_PRINT_L1("Connecting to " << epee::string_tools::get_ip_string_from_int32(na.ip) << ":" + << epee::string_tools::num_to_string_fast(na.port) << "(last_seen: " + << (last_seen_stamp ? epee::misc_utils::get_time_interval_string(time(NULL) - last_seen_stamp):"never") + << ")..."); + + typename net_server::t_connection_context con = AUTO_VAL_INIT(con); + bool res = m_net_server.connect(epee::string_tools::get_ip_string_from_int32(na.ip), + epee::string_tools::num_to_string_fast(na.port), + m_config.m_net_config.connection_timeout, + con); + + if (!res) { + bool is_priority = is_priority_node(na); + + LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Connect failed to " + << epee::string_tools::get_ip_string_from_int32(na.ip) + << ":" << epee::string_tools::num_to_string_fast(na.port)); + + return false; + } + + peerid_type pi = AUTO_VAL_INIT(pi); + res = do_handshake_with_peer(pi, con, true); + + if (!res) { + bool is_priority = is_priority_node(na); + + LOG_PRINT_CC_PRIORITY_NODE(is_priority, con, "Failed to HANDSHAKE with peer " + << epee::string_tools::get_ip_string_from_int32(na.ip) + << ":" << epee::string_tools::num_to_string_fast(na.port)); + + return false; + } + + m_net_server.get_config_object().close(con.m_connection_id); + + LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK AND CLOSED.", LOG_LEVEL_2); + + return true; + } + #undef LOG_PRINT_CC_PRIORITY_NODE //----------------------------------------------------------------------------------- @@ -1097,6 +1141,7 @@ namespace nodetool { m_peer_handshake_idle_maker_interval.do_call(boost::bind(&node_server::peer_sync_idle_maker, this)); m_connections_maker_interval.do_call(boost::bind(&node_server::connections_maker, this)); + m_gray_peerlist_housekeeping_interval.do_call(boost::bind(&node_server::gray_peerlist_housekeeping, this)); m_peerlist_store_interval.do_call(boost::bind(&node_server::store_config, this)); return true; } @@ -1704,4 +1749,30 @@ namespace nodetool return count > max_connections; } + + template + bool node_server::gray_peerlist_housekeeping() + { + peerlist_entry pe = AUTO_VAL_INIT(pe); + + if (!m_peerlist.get_gray_peer_random(pe)) { + return false; + } + + bool success = check_connection_and_handshake_with_peer(pe.adr, pe.last_seen); + + if (!success) { + m_peerlist.remove_from_peer_gray(pe); + + LOG_PRINT_L2("PEER EVICTED FROM GRAY PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id); + + return true; + } + + m_peerlist.append_with_peer_white(pe); + + LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id); + + return true; + } } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index db9387ceb..c230c8c71 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -81,6 +81,8 @@ namespace nodetool bool set_peer_just_seen(peerid_type peer, const net_address& addr); bool set_peer_unreachable(const peerlist_entry& pr); bool is_ip_allowed(uint32_t ip); + bool get_gray_peer_random(peerlist_entry& pe); + bool remove_from_peer_gray(const peerlist_entry& pe); private: @@ -396,6 +398,50 @@ namespace nodetool return true; } //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::get_gray_peer_random(peerlist_entry& pe) + { + TRY_ENTRY(); + + CRITICAL_REGION_LOCAL(m_peerlist_lock); + + if (m_peers_gray.empty()) { + return false; + } + + size_t x = crypto::rand() % (m_peers_gray.size() + 1); + size_t res = (x * x * x) / (m_peers_gray.size() * m_peers_gray.size()); //parabola \/ + + LOG_PRINT_L3("Random gray peer index=" << res << "(x="<< x << ", max_index=" << m_peers_gray.size() << ")"); + + peers_indexed::index::type& by_time_index = m_peers_gray.get(); + pe = *epee::misc_utils::move_it_backward(--by_time_index.end(), res); + + return true; + + CATCH_ENTRY_L0("peerlist_manager::get_gray_peer_random()", false); + return true; + } + //-------------------------------------------------------------------------------------------------- + inline + bool peerlist_manager::remove_from_peer_gray(const peerlist_entry& pe) + { + TRY_ENTRY(); + + CRITICAL_REGION_LOCAL(m_peerlist_lock); + + peers_indexed::index_iterator::type iterator = m_peers_gray.get().find(pe.adr); + + if (iterator != m_peers_gray.get().end()) { + m_peers_gray.erase(iterator); + } + + return true; + + CATCH_ENTRY_L0("peerlist_manager::remove_from_peer_gray()", false); + return true; + } + //-------------------------------------------------------------------------------------------------- } BOOST_CLASS_VERSION(nodetool::peerlist_manager, CURRENT_PEERLIST_STORAGE_ARCHIVE_VER) From 6bdd3a59b57a9194e15bb0dc8ce33e62e93cad95 Mon Sep 17 00:00:00 2001 From: Miguel Herranz Date: Sat, 21 Jan 2017 10:11:32 +0100 Subject: [PATCH 2/4] Use set_peer_just_seen to keep last_seen updated --- src/p2p/net_node.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 3933fe65b..5a20781ed 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1769,7 +1769,7 @@ namespace nodetool return true; } - m_peerlist.append_with_peer_white(pe); + m_peerlist.set_peer_just_seen(pe.id, pe.adr); LOG_PRINT_L2("PEER PROMOTED TO WHITE PEER LIST IP address: " << epee::string_tools::get_ip_string_from_int32(pe.adr.ip) << " Peer ID: " << std::hex << pe.id); From 03a54ee0c9e1d86b6aa43e77a30423ed14483892 Mon Sep 17 00:00:00 2001 From: Miguel Herranz Date: Sat, 21 Jan 2017 11:22:04 +0100 Subject: [PATCH 3/4] Fix logging that broke after rebasing --- src/p2p/net_node.inl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index 5a20781ed..ebe1ba5a2 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -965,7 +965,7 @@ namespace nodetool m_net_server.get_config_object().close(con.m_connection_id); - LOG_PRINT_CC_GREEN(con, "CONNECTION HANDSHAKED OK AND CLOSED.", LOG_LEVEL_2); + LOG_DEBUG_CC(con, "CONNECTION HANDSHAKED OK AND CLOSED."); return true; } From 1c4d65c011e8619e083899c7a52a470b6b9e17f7 Mon Sep 17 00:00:00 2001 From: Miguel Herranz Date: Sat, 21 Jan 2017 13:04:49 +0100 Subject: [PATCH 4/4] Rename method to get_random_gray_peer --- src/p2p/net_node.inl | 2 +- src/p2p/net_peerlist.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index ebe1ba5a2..99ce94eb4 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -1755,7 +1755,7 @@ namespace nodetool { peerlist_entry pe = AUTO_VAL_INIT(pe); - if (!m_peerlist.get_gray_peer_random(pe)) { + if (!m_peerlist.get_random_gray_peer(pe)) { return false; } diff --git a/src/p2p/net_peerlist.h b/src/p2p/net_peerlist.h index c230c8c71..4797eb82b 100644 --- a/src/p2p/net_peerlist.h +++ b/src/p2p/net_peerlist.h @@ -81,7 +81,7 @@ namespace nodetool bool set_peer_just_seen(peerid_type peer, const net_address& addr); bool set_peer_unreachable(const peerlist_entry& pr); bool is_ip_allowed(uint32_t ip); - bool get_gray_peer_random(peerlist_entry& pe); + bool get_random_gray_peer(peerlist_entry& pe); bool remove_from_peer_gray(const peerlist_entry& pe); @@ -399,7 +399,7 @@ namespace nodetool } //-------------------------------------------------------------------------------------------------- inline - bool peerlist_manager::get_gray_peer_random(peerlist_entry& pe) + bool peerlist_manager::get_random_gray_peer(peerlist_entry& pe) { TRY_ENTRY(); @@ -419,7 +419,7 @@ namespace nodetool return true; - CATCH_ENTRY_L0("peerlist_manager::get_gray_peer_random()", false); + CATCH_ENTRY_L0("peerlist_manager::get_random_gray_peer()", false); return true; } //--------------------------------------------------------------------------------------------------