From b3a91f67d74bea3f3ad25665714e0a242cbd12ed Mon Sep 17 00:00:00 2001 From: Antonio Juarez Date: Mon, 20 Jul 2015 17:52:27 +0100 Subject: [PATCH] P2P network stability improvement --- src/cryptonote_config.h | 3 +- .../cryptonote_protocol_handler.h | 8 +- src/p2p/LevinProtocol.cpp | 8 +- src/p2p/net_node.cpp | 111 ++++++++++++------ src/p2p/net_node.h | 3 +- src/version.h.in | 4 +- 6 files changed, 87 insertions(+), 50 deletions(-) diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 6c2086b0..5e5e1e13 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -153,7 +153,8 @@ const CheckpointData CHECKPOINTS[] = { {713000, "a03f836c4a19f907cd6cac095eb6f56f5279ca2d1303fb7f826750dcb9025495"}, {750300, "5117631dbeb5c14748a91127a515ecbf13f6849e14fda7ee03cd55da41f1710c"}, {780000, "8dd55a9bae429e3685b90317281e633917023d3512eb7f37372209d1a5fc1070"}, - {785500, "de1a487d70964d25ed6f7de196866f357a293e867ee81313e7fd0352d0126bdd"} + {785500, "de1a487d70964d25ed6f7de196866f357a293e867ee81313e7fd0352d0126bdd"}, + {789000, "acef490bbccce3b7b7ae8554a414f55413fbf4ca1472c6359b126a4439bd9f01"} }; } // CryptoNote diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 9fccc75f..bdd8261d 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -51,8 +51,8 @@ namespace CryptoNote cryptonote_protocol_handler(const Currency& currency, System::Dispatcher& dispatcher, ICore& rcore, i_p2p_endpoint* p_net_layout, Logging::ILogger& log); - virtual bool addObserver(ICryptonoteProtocolObserver* observer); - virtual bool removeObserver(ICryptonoteProtocolObserver* observer); + virtual bool addObserver(ICryptonoteProtocolObserver* observer) override; + virtual bool removeObserver(ICryptonoteProtocolObserver* observer) override; void set_p2p_endpoint(i_p2p_endpoint* p2p); // ICore& get_core() { return m_core; } @@ -69,8 +69,8 @@ namespace CryptoNote bool get_payload_sync_data(CORE_SYNC_DATA& hshd); bool process_payload_sync_data(const CORE_SYNC_DATA& hshd, cryptonote_connection_context& context, bool is_inital); int handleCommand(bool is_notify, int command, const std::string& in_buff, std::string& buff_out, cryptonote_connection_context& context, bool& handled); - virtual size_t getPeerCount() const; - virtual uint64_t getObservedHeight() const; + virtual size_t getPeerCount() const override; + virtual uint64_t getObservedHeight() const override; void requestMissingPoolTransactions(const cryptonote_connection_context& context); private: diff --git a/src/p2p/LevinProtocol.cpp b/src/p2p/LevinProtocol.cpp index 9e0f6601..29baaaa1 100644 --- a/src/p2p/LevinProtocol.cpp +++ b/src/p2p/LevinProtocol.cpp @@ -66,7 +66,9 @@ std::string LevinProtocol::sendBuf(uint32_t command, const std::string& out, boo std::string response; if (readResponse) { - m_conn.read(reinterpret_cast(&head), sizeof(head)); + if (!readStrict(reinterpret_cast(&head), sizeof(head))) { + throw std::runtime_error("Levin::sendBuf, failed to read header, peer closed connection"); + } if (head.m_signature != LEVIN_SIGNATURE) { throw std::runtime_error("Levin signature mismatch"); @@ -79,7 +81,9 @@ std::string LevinProtocol::sendBuf(uint32_t command, const std::string& out, boo response.resize(head.m_cb); if (response.size()) { - readStrict(&response[0], head.m_cb); + if (!readStrict(&response[0], head.m_cb)) { + throw std::runtime_error("Levin::sendBuf, failed to read body, peer closed connection"); + } } } diff --git a/src/p2p/net_node.cpp b/src/p2p/net_node.cpp index 128c3e88..c77ad260 100644 --- a/src/p2p/net_node.cpp +++ b/src/p2p/net_node.cpp @@ -18,6 +18,7 @@ #include "net_node.h" #include +#include #include #include @@ -435,11 +436,7 @@ namespace CryptoNote m_idleTimer.stop(); m_timedSyncTimer.stop(); - logger(INFO) << "Stopping " << m_connections.size() + m_raw_connections.size() << " connections"; - - for (auto& conn : m_raw_connections) { - conn.second.connection.stop(); - } + logger(INFO) << "Stopping " << m_connections.size() << " connections"; for (auto& conn : m_connections) { conn.second.connection.stop(); @@ -639,35 +636,38 @@ namespace CryptoNote try { System::TcpConnector connector(m_dispatcher); - - System::Event timeoutEvent(m_dispatcher); - System::Timer timeoutTimer(m_dispatcher); - m_dispatcher.spawn([&](){ + System::Event connectorTimeoutEvent(m_dispatcher); + System::Timer connectorTimeoutTimer(m_dispatcher); + + m_dispatcher.spawn([&]() { try { - timeoutTimer.sleep(std::chrono::milliseconds(m_config.m_net_config.connection_timeout)); + connectorTimeoutTimer.sleep(std::chrono::milliseconds(m_config.m_net_config.connection_timeout)); connector.stop(); - } catch (std::exception&) {} - timeoutEvent.set(); + } catch (std::exception&) { + } + + connectorTimeoutEvent.set(); }); System::TcpConnection connection; try { - connection = connector.connect(System::Ipv4Address(Common::ipAddressToString(na.ip)), static_cast(na.port)); + connection = + connector.connect(System::Ipv4Address(Common::ipAddressToString(na.ip)), static_cast(na.port)); } catch (System::InterruptedException&) { - timeoutEvent.wait(); + connectorTimeoutEvent.wait(); return false; - } catch (std::exception&) { - timeoutTimer.stop(); - timeoutEvent.wait(); + } catch (std::exception& e) { + connectorTimeoutTimer.stop(); + connectorTimeoutEvent.wait(); throw; } p2p_connection_context ctx(m_dispatcher, std::move(connection)); - timeoutTimer.stop(); - timeoutEvent.wait(); + connectorTimeoutTimer.stop(); + connectorTimeoutEvent.wait(); // p2p_connection_context ctx(m_dispatcher, std::move(connector.connect())); @@ -677,39 +677,68 @@ namespace CryptoNote ctx.m_is_income = false; ctx.m_started = time(nullptr); - auto raw = m_raw_connections.emplace(ctx.m_connection_id, std::move(ctx)).first; - try { - CryptoNote::LevinProtocol proto(raw->second.connection); - - if (!handshake(proto, raw->second, just_take_peerlist)) { - logger(WARNING) << "Failed to HANDSHAKE with peer " << na; - m_raw_connections.erase(raw); - return false; + System::Event handshakeTimeoutFinishedEvent(m_dispatcher); + System::Event handshakeFinishedEvent(m_dispatcher); + System::Timer handshakeTimeoutTimer(m_dispatcher); + m_dispatcher.spawn([&] { + try { + handshakeTimeoutTimer.sleep(std::chrono::milliseconds(m_config.m_net_config.connection_timeout)); + ctx.connection.stop(); + } catch (std::exception& e) { } - } catch (...) { - m_raw_connections.erase(raw); - throw; + + handshakeTimeoutFinishedEvent.set(); + }); + + CryptoNote::LevinProtocol proto(ctx.connection); + bool error = false; + std::exception_ptr exceptionHolder; + m_dispatcher.spawn([&] { + try { + if (!handshake(proto, ctx, just_take_peerlist)) { + logger(WARNING) << "Failed to HANDSHAKE with peer " << na; + error = true; + } + + } catch (System::InterruptedException&) { + error = true; + handshakeFinishedEvent.set(); + return; + } catch (...) { + exceptionHolder = std::current_exception(); + } + + handshakeTimeoutTimer.stop(); + handshakeFinishedEvent.set(); + }); + + handshakeFinishedEvent.wait(); + handshakeTimeoutFinishedEvent.wait(); + if (error) { + return false; + } + + if (exceptionHolder != nullptr) { + std::rethrow_exception(exceptionHolder); } if (just_take_peerlist) { - logger(Logging::DEBUGGING, Logging::BRIGHT_GREEN) << raw->second << "CONNECTION HANDSHAKED OK AND CLOSED."; - m_raw_connections.erase(raw); + logger(Logging::DEBUGGING, Logging::BRIGHT_GREEN) << ctx << "CONNECTION HANDSHAKED OK AND CLOSED."; return true; } peerlist_entry pe_local = boost::value_initialized(); pe_local.adr = na; - pe_local.id = raw->second.peer_id; + pe_local.id = ctx.peer_id; time(&pe_local.last_seen); m_peerlist.append_with_peer_white(pe_local); if (m_stop) { - m_raw_connections.erase(raw); throw System::InterruptedException(); } - auto iter = m_connections.emplace(raw->first, std::move(raw->second)).first; - m_raw_connections.erase(raw); + auto key = ctx.m_connection_id; + auto iter = m_connections.emplace(key, std::move(ctx)).first; const boost::uuids::uuid& connectionId = iter->first; p2p_connection_context& connectionContext = iter->second; @@ -784,7 +813,7 @@ namespace CryptoNote size_t try_count = 0; size_t current_index = crypto::rand()%m_seed_nodes.size(); - while(true) { + while(true) { if(try_to_connect_and_handshake_with_new_peer(m_seed_nodes[current_index], true)) break; @@ -855,8 +884,12 @@ namespace CryptoNote //----------------------------------------------------------------------------------- bool node_server::idle_worker() { - m_connections_maker_interval.call(std::bind(&node_server::connections_maker, this)); - m_peerlist_store_interval.call(std::bind(&node_server::store_config, this)); + try { + m_connections_maker_interval.call(std::bind(&node_server::connections_maker, this)); + m_peerlist_store_interval.call(std::bind(&node_server::store_config, this)); + } catch (std::exception& e) { + logger(DEBUGGING) << "exception in idle_worker: " << e.what(); + } return true; } diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index cc57c41a..a1c1c707 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -102,7 +102,7 @@ namespace CryptoNote // debug functions bool log_peerlist(); bool log_connections(); - virtual uint64_t get_connections_count(); + virtual uint64_t get_connections_count() override; size_t get_outgoing_connections_count(); CryptoNote::peerlist_manager& get_peerlist_manager() { return m_peerlist; } @@ -171,7 +171,6 @@ namespace CryptoNote typedef std::unordered_map> ConnectionContainer; typedef ConnectionContainer::iterator ConnectionIterator; - ConnectionContainer m_raw_connections; ConnectionContainer m_connections; void acceptLoop(); diff --git a/src/version.h.in b/src/version.h.in index ff691919..3818b7ac 100644 --- a/src/version.h.in +++ b/src/version.h.in @@ -1,4 +1,4 @@ #define BUILD_COMMIT_ID "@VERSION@" -#define PROJECT_VERSION "1.0.5" -#define PROJECT_VERSION_BUILD_NO "503" +#define PROJECT_VERSION "1.0.5.1" +#define PROJECT_VERSION_BUILD_NO "505" #define PROJECT_VERSION_LONG PROJECT_VERSION "." PROJECT_VERSION_BUILD_NO "(" BUILD_COMMIT_ID ")"