support IPv6 in node_entry and m_ips

This commit is contained in:
Steven Siloti 2015-08-16 16:21:10 -07:00
parent b5ecfa4f91
commit 11fa4f3e47
5 changed files with 141 additions and 88 deletions

View File

@ -55,10 +55,10 @@ struct TORRENT_EXTRA_EXPORT node_entry
void timed_out() { if (pinged() && timeout_count < 0xfe) ++timeout_count; } void timed_out() { if (pinged() && timeout_count < 0xfe) ++timeout_count; }
int fail_count() const { return pinged() ? timeout_count : 0; } int fail_count() const { return pinged() ? timeout_count : 0; }
void reset_fail_count() { if (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; } bool confirmed() const { return timeout_count == 0; }
address addr() const { return address_v4(a); } address addr() const { return endpoint.address(); }
int port() const { return p; } int port() const { return endpoint.port; }
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
time_point first_seen; time_point first_seen;
@ -69,8 +69,7 @@ struct TORRENT_EXTRA_EXPORT node_entry
node_id id; node_id id;
address_v4::bytes_type a; union_endpoint endpoint;
boost::uint16_t p;
// the average RTT of this node // the average RTT of this node
boost::uint16_t rtt; boost::uint16_t rtt;

View File

@ -73,6 +73,23 @@ struct routing_table_node
bucket_t live_nodes; 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<address_v4::bytes_type> m_ip4s;
boost::unordered_multiset<address_v6::bytes_type> m_ip6s;
};
// differences in the implementation from the description in // differences in the implementation from the description in
// the paper: // the paper:
// //
@ -256,9 +273,8 @@ private:
// these are all the IPs that are in the routing // these are all the IPs that are in the routing
// table. It's used to only allow a single entry // table. It's used to only allow a single entry
// per IP in the whole table. Currently only for // per IP in the whole table.
// IPv4 ip_set m_ips;
boost::unordered_multiset<address_v4::bytes_type> m_ips;
// constant called k in paper // constant called k in paper
int m_bucket_size; int m_bucket_size;

View File

@ -38,6 +38,71 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent 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 struct union_endpoint
{ {
@ -58,75 +123,35 @@ namespace libtorrent
union_endpoint& operator=(udp::endpoint const& ep) union_endpoint& operator=(udp::endpoint const& ep)
{ {
#if TORRENT_USE_IPV6 addr = ep.address();
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
port = ep.port(); port = ep.port();
return *this; return *this;
} }
operator udp::endpoint() const operator udp::endpoint() const
{ {
#if TORRENT_USE_IPV6 return udp::endpoint(addr, port);
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
} }
union_endpoint& operator=(tcp::endpoint const& ep) union_endpoint& operator=(tcp::endpoint const& ep)
{ {
#if TORRENT_USE_IPV6 addr = ep.address();
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
port = ep.port(); port = ep.port();
return *this; return *this;
} }
libtorrent::address address() const libtorrent::address address() const
{ {
#if TORRENT_USE_IPV6 return addr;
if (v4) return address_v4(addr.v4);
else return address_v6(addr.v6);
#else
return address_v4(addr.v4);
#endif
} }
operator tcp::endpoint() const operator tcp::endpoint() const
{ {
#if TORRENT_USE_IPV6 return tcp::endpoint(addr, port);
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
} }
TORRENT_UNION addr_t union_address addr;
{
address_v4::bytes_type v4;
#if TORRENT_USE_IPV6
address_v6::bytes_type v6;
#endif
} addr;
boost::uint16_t port; boost::uint16_t port;
#if TORRENT_USE_IPV6
bool v4:1;
#endif
}; };
} }

View File

@ -41,8 +41,7 @@ namespace libtorrent { namespace dht
, bool pinged) , bool pinged)
: last_queried(pinged ? aux::time_now() : min_time()) : last_queried(pinged ? aux::time_now() : min_time())
, id(id_) , id(id_)
, a(ep.address().to_v4().to_bytes()) , endpoint(ep)
, p(ep.port())
, rtt(roundtriptime & 0xffff) , rtt(roundtriptime & 0xffff)
, timeout_count(pinged ? 0 : 0xff) , timeout_count(pinged ? 0 : 0xff)
{ {
@ -54,8 +53,7 @@ namespace libtorrent { namespace dht
node_entry::node_entry(udp::endpoint ep) node_entry::node_entry(udp::endpoint ep)
: last_queried(min_time()) : last_queried(min_time())
, id(0) , id(0)
, a(ep.address().to_v4().to_bytes()) , endpoint(ep)
, p(ep.port())
, rtt(0xffff) , rtt(0xffff)
, timeout_count(0xff) , timeout_count(0xff)
{ {
@ -67,7 +65,6 @@ namespace libtorrent { namespace dht
node_entry::node_entry() node_entry::node_entry()
: last_queried(min_time()) : last_queried(min_time())
, id(0) , id(0)
, p(0)
, rtt(0xffff) , rtt(0xffff)
, timeout_count(0xff) , timeout_count(0xff)
{ {

View File

@ -58,15 +58,6 @@ POSSIBILITY OF SUCH DAMAGE.
using boost::uint8_t; 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<boost::uint32_t*>(&ip[0]));
}
}
#endif
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
namespace 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 routing_table::routing_table(node_id const& id, int bucket_size
, dht_settings const& settings , dht_settings const& settings
, dht_logger* log) , dht_logger* log)
@ -514,8 +529,8 @@ void routing_table::remove_node(node_entry* n
&& n < &bucket->replacements[0] + bucket->replacements.size()) && n < &bucket->replacements[0] + bucket->replacements.size())
{ {
int idx = n - &bucket->replacements[0]; int idx = n - &bucket->replacements[0];
TORRENT_ASSERT(m_ips.count(n->a) > 0); TORRENT_ASSERT(m_ips.count(n->addr()) > 0);
erase_one(m_ips, n->a); m_ips.erase(n->addr());
bucket->replacements.erase(bucket->replacements.begin() + idx); 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()) && n < &bucket->live_nodes[0] + bucket->live_nodes.size())
{ {
int idx = n - &bucket->live_nodes[0]; int idx = n - &bucket->live_nodes[0];
TORRENT_ASSERT(m_ips.count(n->a) > 0); TORRENT_ASSERT(m_ips.count(n->addr()) > 0);
erase_one(m_ips, n->a); m_ips.erase(n->addr());
bucket->live_nodes.erase(bucket->live_nodes.begin() + idx); 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; if (e.id == m_id) return failed_to_add;
// do we already have this IP in the table? // 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 // 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 // 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->timeout_count = 0;
j->update_rtt(e.rtt); j->update_rtt(e.rtt);
e = *j; e = *j;
erase_one(m_ips, j->addr().to_v4().to_bytes()); m_ips.erase(j->addr());
rb.erase(j); rb.erase(j);
} }
@ -737,7 +752,7 @@ ip_ok:
{ {
if (b.empty()) b.reserve(bucket_size_limit); if (b.empty()) b.reserve(bucket_size_limit);
b.push_back(e); b.push_back(e);
m_ips.insert(e.addr().to_v4().to_bytes()); m_ips.insert(e.addr());
return node_added; return node_added;
} }
@ -762,9 +777,9 @@ ip_ok:
{ {
// j points to a node that has not been pinged. // j points to a node that has not been pinged.
// Replace it with this new one // Replace it with this new one
erase_one(m_ips, j->addr().to_v4().to_bytes()); m_ips.erase(j->addr());
*j = e; *j = e;
m_ips.insert(e.addr().to_v4().to_bytes()); m_ips.insert(e.addr());
return node_added; return node_added;
} }
@ -783,9 +798,9 @@ ip_ok:
{ {
// i points to a node that has been marked // i points to a node that has been marked
// as stale. Replace it with this new one // 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; *j = e;
m_ips.insert(e.addr().to_v4().to_bytes()); m_ips.insert(e.addr());
return node_added; return node_added;
} }
@ -893,9 +908,9 @@ ip_ok:
if (j != b.end() && (force_replace || j->rtt > e.rtt)) 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; *j = e;
m_ips.insert(e.addr().to_v4().to_bytes()); m_ips.insert(e.addr());
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (m_log) if (m_log)
{ {
@ -940,13 +955,13 @@ ip_ok:
// less reliable than this one, that has been pinged // less reliable than this one, that has been pinged
j = std::find_if(rb.begin(), rb.end(), boost::bind(&node_entry::pinged, _1) == false); j = std::find_if(rb.begin(), rb.end(), boost::bind(&node_entry::pinged, _1) == false);
if (j == rb.end()) j = rb.begin(); 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); rb.erase(j);
} }
if (rb.empty()) rb.reserve(m_bucket_size); if (rb.empty()) rb.reserve(m_bucket_size);
rb.push_back(e); rb.push_back(e);
m_ips.insert(e.addr().to_v4().to_bytes()); m_ips.insert(e.addr());
return node_added; 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 // has never responded at all, remove it
if (j->fail_count() >= m_settings.max_fail_count || !j->pinged()) 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); b.erase(j);
} }
return; return;
} }
erase_one(m_ips, j->a); m_ips.erase(j->addr());
b.erase(j); b.erase(j);
// sort by RTT first, to find the node with the lowest // 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 #if TORRENT_USE_INVARIANT_CHECKS
void routing_table::check_invariant() const void routing_table::check_invariant() const
{ {
boost::unordered_multiset<address_v4::bytes_type> all_ips; ip_set all_ips;
for (table_t::const_iterator i = m_buckets.begin() for (table_t::const_iterator i = m_buckets.begin()
, end(m_buckets.end()); i != end; ++i) , 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(); for (bucket_t::const_iterator j = i->replacements.begin();
j != i->replacements.end(); ++j) 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(); for (bucket_t::const_iterator j = i->live_nodes.begin();
j != i->live_nodes.end(); ++j) 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());
} }
} }