diff --git a/libp2p/NodeTable.cpp b/libp2p/NodeTable.cpp index 2837e8f07..1c0883b6a 100644 --- a/libp2p/NodeTable.cpp +++ b/libp2p/NodeTable.cpp @@ -178,6 +178,7 @@ void NodeTable::discover(NodeId _node, unsigned _round, shared_ptrendpoint.udp, _node); p.sign(m_secret); + m_findNodeTimeout.push_back(make_pair(_node, chrono::steady_clock::now())); m_socketPointer->send(p); } @@ -457,6 +458,20 @@ void NodeTable::onReceived(UDPSocketFace*, bi::udp::endpoint const& _from, bytes case Neighbours::type: { + bool expected = false; + m_findNodeTimeout.remove_if([&](NodeIdTimePoint const& t) + { + if (t.first == nodeid && chrono::steady_clock::now() - t.second < c_reqTimeout) + expected = true; + return t.first == nodeid; + }); + + if (!expected) + { + clog(NetConnect) << "Dropping unsolicited Neighbours packet from " << _from.address(); + break; + } + Neighbours in = Neighbours::fromBytesConstRef(_from, rlpBytes); for (auto n: in.nodes) addNode(n.node, bi::udp::endpoint(bi::address::from_string(n.ipAddress), n.port), bi::tcp::endpoint(bi::address::from_string(n.ipAddress), n.port)); diff --git a/libp2p/NodeTable.h b/libp2p/NodeTable.h index 4aee93e99..bd7d121f4 100644 --- a/libp2p/NodeTable.h +++ b/libp2p/NodeTable.h @@ -131,8 +131,9 @@ class NodeTable: UDPSocketEvents, public std::enable_shared_from_this { friend std::ostream& operator<<(std::ostream& _out, NodeTable const& _nodeTable); using NodeSocket = UDPSocket; - using TimePoint = std::chrono::steady_clock::time_point; - using EvictionTimeout = std::pair, NodeId>; ///< First NodeId may be evicted and replaced with second NodeId. + using TimePoint = std::chrono::steady_clock::time_point; ///< Steady time point. + using NodeIdTimePoint = std::pair; + using EvictionTimeout = std::pair; ///< First NodeId (NodeIdTimePoint) may be evicted and replaced with second NodeId. public: /// Constructor requiring host for I/O, credentials, and IP Address and port to listen on. @@ -271,6 +272,9 @@ private: Mutex x_pubkDiscoverPings; ///< LOCK x_nodes first if both x_nodes and x_pubkDiscoverPings locks are required. std::map m_pubkDiscoverPings; ///< List of pending pings where node entry wasn't created due to unkown pubk. + Mutex x_findNodeTimeout; + std::list m_findNodeTimeout; ///< Timeouts for pending Ping and FindNode requests. + ba::io_service& m_io; ///< Used by bucket refresh timer. std::shared_ptr m_socket; ///< Shared pointer for our UDPSocket; ASIO requires shared_ptr. NodeSocket* m_socketPointer; ///< Set to m_socket.get(). Socket is created in constructor and disconnected in destructor to ensure access to pointer is safe. diff --git a/test/net.cpp b/test/net.cpp index ec1efb360..75c67888d 100644 --- a/test/net.cpp +++ b/test/net.cpp @@ -145,6 +145,39 @@ public: bool success = false; }; +BOOST_AUTO_TEST_CASE(requestTimeout) +{ + using TimePoint = std::chrono::steady_clock::time_point; + using RequestTimeout = std::pair; + + std::chrono::milliseconds timeout(300); + std::list timeouts; + + NodeId nodeA(sha3("a")); + NodeId nodeB(sha3("b")); + timeouts.push_back(make_pair(nodeA, chrono::steady_clock::now())); + this_thread::sleep_for(std::chrono::milliseconds(100)); + timeouts.push_back(make_pair(nodeB, chrono::steady_clock::now())); + this_thread::sleep_for(std::chrono::milliseconds(210)); + + bool nodeAtriggered = false; + bool nodeBtriggered = false; + timeouts.remove_if([&](RequestTimeout const& t) + { + auto now = chrono::steady_clock::now(); + auto diff = now - t.second; + if (t.first == nodeA && diff < timeout) + nodeAtriggered = true; + if (t.first == nodeB && diff < timeout) + nodeBtriggered = true; + return (t.first == nodeA || t.first == nodeB); + }); + + BOOST_REQUIRE(nodeAtriggered == false); + BOOST_REQUIRE(nodeBtriggered == true); + BOOST_REQUIRE(timeouts.size() == 0); +} + BOOST_AUTO_TEST_CASE(isIPAddressType) { string wildcard = "0.0.0.0";