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)