From 11fa4f3e47ced4ecae8f485e625ee83ea06740c1 Mon Sep 17 00:00:00 2001 From: Steven Siloti Date: Sun, 16 Aug 2015 16:21:10 -0700 Subject: [PATCH] support IPv6 in node_entry and m_ips --- include/libtorrent/kademlia/node_entry.hpp | 9 +- include/libtorrent/kademlia/routing_table.hpp | 22 +++- include/libtorrent/union_endpoint.hpp | 117 +++++++++++------- src/kademlia/node_entry.cpp | 7 +- src/kademlia/routing_table.cpp | 74 ++++++----- 5 files changed, 141 insertions(+), 88 deletions(-) diff --git a/include/libtorrent/kademlia/node_entry.hpp b/include/libtorrent/kademlia/node_entry.hpp index 41b7acf07..5ed1d59fa 100644 --- a/include/libtorrent/kademlia/node_entry.hpp +++ b/include/libtorrent/kademlia/node_entry.hpp @@ -55,10 +55,10 @@ struct TORRENT_EXTRA_EXPORT node_entry void timed_out() { if (pinged() && timeout_count < 0xfe) ++timeout_count; } int fail_count() const { return pinged() ? timeout_count : 0; } void reset_fail_count() { if (pinged()) timeout_count = 0; } - udp::endpoint ep() const { return udp::endpoint(address_v4(a), p); } + udp::endpoint ep() const { return endpoint; } bool confirmed() const { return timeout_count == 0; } - address addr() const { return address_v4(a); } - int port() const { return p; } + address addr() const { return endpoint.address(); } + int port() const { return endpoint.port; } #ifndef TORRENT_DISABLE_LOGGING time_point first_seen; @@ -69,8 +69,7 @@ struct TORRENT_EXTRA_EXPORT node_entry node_id id; - address_v4::bytes_type a; - boost::uint16_t p; + union_endpoint endpoint; // the average RTT of this node boost::uint16_t rtt; diff --git a/include/libtorrent/kademlia/routing_table.hpp b/include/libtorrent/kademlia/routing_table.hpp index 24d8b0271..e4d38fb7a 100644 --- a/include/libtorrent/kademlia/routing_table.hpp +++ b/include/libtorrent/kademlia/routing_table.hpp @@ -73,6 +73,23 @@ struct routing_table_node bucket_t live_nodes; }; +struct ip_set +{ + void insert(address addr); + size_t count(address addr); + void erase(address addr); + + bool operator==(ip_set const& rh) + { + return m_ip4s == rh.m_ip4s && m_ip6s == rh.m_ip6s; + } + + // these must be multisets because there can be multiple routing table + // entries for a single IP when restrict_routing_ips is set to false + boost::unordered_multiset m_ip4s; + boost::unordered_multiset m_ip6s; +}; + // differences in the implementation from the description in // the paper: // @@ -256,9 +273,8 @@ private: // these are all the IPs that are in the routing // table. It's used to only allow a single entry - // per IP in the whole table. Currently only for - // IPv4 - boost::unordered_multiset m_ips; + // per IP in the whole table. + ip_set m_ips; // constant called k in paper int m_bucket_size; diff --git a/include/libtorrent/union_endpoint.hpp b/include/libtorrent/union_endpoint.hpp index 457c05839..e317ef92d 100644 --- a/include/libtorrent/union_endpoint.hpp +++ b/include/libtorrent/union_endpoint.hpp @@ -38,6 +38,71 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { + struct union_address + { + union_address() + { + *this = address(); + } + + union_address(address const& a) + { + *this = a; + } + + union_address& operator=(address const& a) + { +#if TORRENT_USE_IPV6 + v4 = a.is_v4(); + if (v4) + addr.v4 = a.to_v4().to_bytes(); + else + addr.v6 = a.to_v6().to_bytes(); +#else + addr.v4 = a.to_v4().to_bytes(); +#endif + return *this; + } + + bool operator==(union_address const& rh) const + { +#if TORRENT_USE_IPV6 + if (v4 != rh.v4) return false; + if (v4) + return addr.v4 == rh.addr.v4; + else + return addr.v6 == rh.addr.v6; +#else + return addr.v4 == rh.addr.v4; +#endif + } + + bool operator!=(union_address const& rh) const + { + return !(*this == rh); + } + + operator address() const + { +#if TORRENT_USE_IPV6 + if (v4) return address(address_v4(addr.v4)); + else return address(address_v6(addr.v6)); +#else + return address(address_v4(addr.v4)); +#endif + } + + TORRENT_UNION addr_t + { + address_v4::bytes_type v4; +#if TORRENT_USE_IPV6 + address_v6::bytes_type v6; +#endif + } addr; +#if TORRENT_USE_IPV6 + bool v4:1; +#endif + }; struct union_endpoint { @@ -58,75 +123,35 @@ namespace libtorrent union_endpoint& operator=(udp::endpoint const& ep) { -#if TORRENT_USE_IPV6 - v4 = ep.address().is_v4(); - if (v4) - addr.v4 = ep.address().to_v4().to_bytes(); - else - addr.v6 = ep.address().to_v6().to_bytes(); -#else - addr.v4 = ep.address().to_v4().to_bytes(); -#endif + addr = ep.address(); port = ep.port(); return *this; } operator udp::endpoint() const { -#if TORRENT_USE_IPV6 - if (v4) return udp::endpoint(address_v4(addr.v4), port); - else return udp::endpoint(address_v6(addr.v6), port); -#else - return udp::endpoint(address_v4(addr.v4), port); -#endif + return udp::endpoint(addr, port); } union_endpoint& operator=(tcp::endpoint const& ep) { -#if TORRENT_USE_IPV6 - v4 = ep.address().is_v4(); - if (v4) - addr.v4 = ep.address().to_v4().to_bytes(); - else - addr.v6 = ep.address().to_v6().to_bytes(); -#else - addr.v4 = ep.address().to_v4().to_bytes(); -#endif + addr = ep.address(); port = ep.port(); return *this; } libtorrent::address address() const { -#if TORRENT_USE_IPV6 - if (v4) return address_v4(addr.v4); - else return address_v6(addr.v6); -#else - return address_v4(addr.v4); -#endif + return addr; } operator tcp::endpoint() const { -#if TORRENT_USE_IPV6 - if (v4) return tcp::endpoint(address_v4(addr.v4), port); - else return tcp::endpoint(address_v6(addr.v6), port); -#else - return tcp::endpoint(address_v4(addr.v4), port); -#endif + return tcp::endpoint(addr, port); } - TORRENT_UNION addr_t - { - address_v4::bytes_type v4; -#if TORRENT_USE_IPV6 - address_v6::bytes_type v6; -#endif - } addr; + union_address addr; boost::uint16_t port; -#if TORRENT_USE_IPV6 - bool v4:1; -#endif }; } diff --git a/src/kademlia/node_entry.cpp b/src/kademlia/node_entry.cpp index 00ac3b01c..748faa84b 100644 --- a/src/kademlia/node_entry.cpp +++ b/src/kademlia/node_entry.cpp @@ -41,8 +41,7 @@ namespace libtorrent { namespace dht , bool pinged) : last_queried(pinged ? aux::time_now() : min_time()) , id(id_) - , a(ep.address().to_v4().to_bytes()) - , p(ep.port()) + , endpoint(ep) , rtt(roundtriptime & 0xffff) , timeout_count(pinged ? 0 : 0xff) { @@ -54,8 +53,7 @@ namespace libtorrent { namespace dht node_entry::node_entry(udp::endpoint ep) : last_queried(min_time()) , id(0) - , a(ep.address().to_v4().to_bytes()) - , p(ep.port()) + , endpoint(ep) , rtt(0xffff) , timeout_count(0xff) { @@ -67,7 +65,6 @@ namespace libtorrent { namespace dht node_entry::node_entry() : last_queried(min_time()) , id(0) - , p(0) , rtt(0xffff) , timeout_count(0xff) { diff --git a/src/kademlia/routing_table.cpp b/src/kademlia/routing_table.cpp index faeb0c9c8..09896eee0 100644 --- a/src/kademlia/routing_table.cpp +++ b/src/kademlia/routing_table.cpp @@ -58,15 +58,6 @@ POSSIBILITY OF SUCH DAMAGE. using boost::uint8_t; -#if BOOST_VERSION <= 104700 -namespace boost { -size_t hash_value(libtorrent::address_v4::bytes_type ip) -{ - return boost::hash_value(*reinterpret_cast(&ip[0])); -} -} -#endif - namespace libtorrent { namespace dht { namespace @@ -89,6 +80,30 @@ namespace } } +void ip_set::insert(address addr) +{ + if (addr.is_v4()) + m_ip4s.insert(addr.to_v4().to_bytes()); + else + m_ip6s.insert(addr.to_v6().to_bytes()); +} + +size_t ip_set::count(address addr) +{ + if (addr.is_v4()) + return m_ip4s.count(addr.to_v4().to_bytes()); + else + return m_ip6s.count(addr.to_v6().to_bytes()); +} + +void ip_set::erase(address addr) +{ + if (addr.is_v4()) + erase_one(m_ip4s, addr.to_v4().to_bytes()); + else + erase_one(m_ip6s, addr.to_v6().to_bytes()); +} + routing_table::routing_table(node_id const& id, int bucket_size , dht_settings const& settings , dht_logger* log) @@ -514,8 +529,8 @@ void routing_table::remove_node(node_entry* n && n < &bucket->replacements[0] + bucket->replacements.size()) { int idx = n - &bucket->replacements[0]; - TORRENT_ASSERT(m_ips.count(n->a) > 0); - erase_one(m_ips, n->a); + TORRENT_ASSERT(m_ips.count(n->addr()) > 0); + m_ips.erase(n->addr()); bucket->replacements.erase(bucket->replacements.begin() + idx); } @@ -524,8 +539,8 @@ void routing_table::remove_node(node_entry* n && n < &bucket->live_nodes[0] + bucket->live_nodes.size()) { int idx = n - &bucket->live_nodes[0]; - TORRENT_ASSERT(m_ips.count(n->a) > 0); - erase_one(m_ips, n->a); + TORRENT_ASSERT(m_ips.count(n->addr()) > 0); + m_ips.erase(n->addr()); bucket->live_nodes.erase(bucket->live_nodes.begin() + idx); } } @@ -582,7 +597,7 @@ routing_table::add_node_status_t routing_table::add_node_impl(node_entry e) if (e.id == m_id) return failed_to_add; // do we already have this IP in the table? - if (m_ips.count(e.addr().to_v4().to_bytes()) > 0) + if (m_ips.count(e.addr()) > 0) { // this exact IP already exists in the table. It might be the case // that the node changed IP. If pinged is true, and the port also @@ -688,7 +703,7 @@ routing_table::add_node_status_t routing_table::add_node_impl(node_entry e) j->timeout_count = 0; j->update_rtt(e.rtt); e = *j; - erase_one(m_ips, j->addr().to_v4().to_bytes()); + m_ips.erase(j->addr()); rb.erase(j); } @@ -737,7 +752,7 @@ ip_ok: { if (b.empty()) b.reserve(bucket_size_limit); b.push_back(e); - m_ips.insert(e.addr().to_v4().to_bytes()); + m_ips.insert(e.addr()); return node_added; } @@ -762,9 +777,9 @@ ip_ok: { // j points to a node that has not been pinged. // Replace it with this new one - erase_one(m_ips, j->addr().to_v4().to_bytes()); + m_ips.erase(j->addr()); *j = e; - m_ips.insert(e.addr().to_v4().to_bytes()); + m_ips.insert(e.addr()); return node_added; } @@ -783,9 +798,9 @@ ip_ok: { // i points to a node that has been marked // as stale. Replace it with this new one - erase_one(m_ips, j->addr().to_v4().to_bytes()); + m_ips.erase(j->addr()); *j = e; - m_ips.insert(e.addr().to_v4().to_bytes()); + m_ips.insert(e.addr()); return node_added; } @@ -893,9 +908,9 @@ ip_ok: if (j != b.end() && (force_replace || j->rtt > e.rtt)) { - erase_one(m_ips, j->addr().to_v4().to_bytes()); + m_ips.erase(j->addr()); *j = e; - m_ips.insert(e.addr().to_v4().to_bytes()); + m_ips.insert(e.addr()); #ifndef TORRENT_DISABLE_LOGGING if (m_log) { @@ -940,13 +955,13 @@ ip_ok: // less reliable than this one, that has been pinged j = std::find_if(rb.begin(), rb.end(), boost::bind(&node_entry::pinged, _1) == false); if (j == rb.end()) j = rb.begin(); - erase_one(m_ips, j->addr().to_v4().to_bytes()); + m_ips.erase(j->addr()); rb.erase(j); } if (rb.empty()) rb.reserve(m_bucket_size); rb.push_back(e); - m_ips.insert(e.addr().to_v4().to_bytes()); + m_ips.insert(e.addr()); return node_added; } @@ -1140,13 +1155,13 @@ void routing_table::node_failed(node_id const& nid, udp::endpoint const& ep) // has never responded at all, remove it if (j->fail_count() >= m_settings.max_fail_count || !j->pinged()) { - erase_one(m_ips, j->addr().to_v4().to_bytes()); + m_ips.erase(j->addr()); b.erase(j); } return; } - erase_one(m_ips, j->a); + m_ips.erase(j->addr()); b.erase(j); // sort by RTT first, to find the node with the lowest @@ -1277,7 +1292,7 @@ void routing_table::find_node(node_id const& target #if TORRENT_USE_INVARIANT_CHECKS void routing_table::check_invariant() const { - boost::unordered_multiset all_ips; + ip_set all_ips; for (table_t::const_iterator i = m_buckets.begin() , end(m_buckets.end()); i != end; ++i) @@ -1285,12 +1300,13 @@ void routing_table::check_invariant() const for (bucket_t::const_iterator j = i->replacements.begin(); j != i->replacements.end(); ++j) { - all_ips.insert(j->addr().to_v4().to_bytes()); + all_ips.insert(j->addr()); } for (bucket_t::const_iterator j = i->live_nodes.begin(); j != i->live_nodes.end(); ++j) { - all_ips.insert(j->addr().to_v4().to_bytes()); + TORRENT_ASSERT(j->addr().is_v4() == i->live_nodes.begin()->addr().is_v4()); + all_ips.insert(j->addr()); } }