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; }
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;

View File

@ -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<address_v4::bytes_type> m_ip4s;
boost::unordered_multiset<address_v6::bytes_type> 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<address_v4::bytes_type> m_ips;
// per IP in the whole table.
ip_set m_ips;
// constant called k in paper
int m_bucket_size;

View File

@ -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
};
}

View File

@ -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)
{

View File

@ -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<boost::uint32_t*>(&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<address_v4::bytes_type> 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());
}
}