added first version of an IPv6 extension and docs
This commit is contained in:
parent
978fe778ec
commit
004d3771cb
|
@ -0,0 +1,39 @@
|
||||||
|
:Author: Arvid Norberg, arvid@rasterbar.com
|
||||||
|
|
||||||
|
Mainline DHT extensions
|
||||||
|
=======================
|
||||||
|
|
||||||
|
libtorrent implements a few extensions to the Mainline DHT protocol.
|
||||||
|
|
||||||
|
client identification
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
In each DHT packet, an extra key is inserted named "v". This is a string
|
||||||
|
describing the client and version used. This can help alot when debugging
|
||||||
|
and finding errors in client implementations. The string is encoded as four
|
||||||
|
characters, two characters describing the client and two characters interpreted
|
||||||
|
as a binary number describing the client version.
|
||||||
|
|
||||||
|
Currently known clients:
|
||||||
|
|
||||||
|
+---------------+--------+
|
||||||
|
| uTorrent | ``UT`` |
|
||||||
|
+---------------+--------+
|
||||||
|
| libtorrent | ``LT`` |
|
||||||
|
+---------------+--------+
|
||||||
|
| MooPolice | ``MP`` |
|
||||||
|
+---------------+--------+
|
||||||
|
| GetRight | ``GR`` |
|
||||||
|
+---------------+--------+
|
||||||
|
|
||||||
|
IPv6 support
|
||||||
|
------------
|
||||||
|
|
||||||
|
The only DHT messages that don't support IPv6 is the ``nodes`` reply. It
|
||||||
|
encodes all the contacts as 6 bytes sequences packet together in sequence in
|
||||||
|
string. The problem is that IPv6 endpoints cannot be encoded as 6 bytes, but
|
||||||
|
18 bytes. The extension libtorrent applies is to add another key, called
|
||||||
|
``nodes2`` which is encoded as a list of strings. Each string represents one
|
||||||
|
contact and is encoded as 20 bytes node-id and then a variable length encoded
|
||||||
|
IP address (6 bytes in IPv4 case and 18 bytes in IPv6 case).
|
||||||
|
|
|
@ -103,6 +103,25 @@ namespace
|
||||||
return boost::optional<node_id>(
|
return boost::optional<node_id>(
|
||||||
boost::lexical_cast<node_id>(nid->string()));
|
boost::lexical_cast<node_id>(nid->string()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class EndpointType>
|
||||||
|
void read_endpoint_list(libtorrent::entry const* n, std::vector<EndpointType>& epl)
|
||||||
|
{
|
||||||
|
using namespace libtorrent;
|
||||||
|
entry::list_type const& contacts = n->list();
|
||||||
|
for (entry::list_type::const_iterator i = contacts.begin()
|
||||||
|
, end(contacts.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
std::string const& p = i->string();
|
||||||
|
if (p.size() < 6) continue;
|
||||||
|
std::string::const_iterator in = p.begin();
|
||||||
|
if (p.size() == 6)
|
||||||
|
epl.push_back(read_v4_endpoint<EndpointType>(in));
|
||||||
|
else if (p.size() == 18)
|
||||||
|
epl.push_back(read_v6_endpoint<EndpointType>(in));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace libtorrent { namespace dht
|
namespace libtorrent { namespace dht
|
||||||
|
@ -161,24 +180,11 @@ namespace libtorrent { namespace dht
|
||||||
|
|
||||||
if (bootstrap.type() == entry::dictionary_t)
|
if (bootstrap.type() == entry::dictionary_t)
|
||||||
{
|
{
|
||||||
if (entry const* nodes = bootstrap.find_key("nodes"))
|
try
|
||||||
{
|
{
|
||||||
if (nodes->type() == entry::list_t)
|
if (entry const* nodes = bootstrap.find_key("nodes"))
|
||||||
{
|
read_endpoint_list<udp::endpoint>(nodes, initial_nodes);
|
||||||
entry::list_type const& node_list = nodes->list();
|
} catch (std::exception&) {}
|
||||||
for (entry::list_type::const_iterator i = node_list.begin()
|
|
||||||
, end(node_list.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
if (i->type() != entry::string_t) continue;
|
|
||||||
std::string const& str = i->string();
|
|
||||||
std::string::const_iterator in(str.begin());
|
|
||||||
if (str.length() == 6)
|
|
||||||
initial_nodes.push_back(read_v4_endpoint<udp::endpoint>(in));
|
|
||||||
else if (str.length() == 18)
|
|
||||||
initial_nodes.push_back(read_v6_endpoint<udp::endpoint>(in));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dht.bootstrap(initial_nodes, bind(&dht_tracker::on_bootstrap, this));
|
m_dht.bootstrap(initial_nodes, bind(&dht_tracker::on_bootstrap, this));
|
||||||
|
@ -436,26 +442,15 @@ namespace libtorrent { namespace dht
|
||||||
if (entry const* n = r.find_key("values"))
|
if (entry const* n = r.find_key("values"))
|
||||||
{
|
{
|
||||||
m.peers.clear();
|
m.peers.clear();
|
||||||
entry::list_type const& peers = n->list();
|
read_endpoint_list<tcp::endpoint>(n, m.peers);
|
||||||
for (entry::list_type::const_iterator i = peers.begin()
|
|
||||||
, end(peers.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
std::string const& p = i->string();
|
|
||||||
if (p.size() < 6) continue;
|
|
||||||
std::string::const_iterator in = p.begin();
|
|
||||||
if (p.size() == 6)
|
|
||||||
m.peers.push_back(read_v4_endpoint<tcp::endpoint>(in));
|
|
||||||
else if (p.size() == 18)
|
|
||||||
m.peers.push_back(read_v6_endpoint<tcp::endpoint>(in));
|
|
||||||
}
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size();
|
TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.nodes.clear();
|
||||||
if (entry const* n = r.find_key("nodes"))
|
if (entry const* n = r.find_key("nodes"))
|
||||||
{
|
{
|
||||||
m.nodes.clear();
|
|
||||||
std::string const& nodes = n->string();
|
std::string const& nodes = n->string();
|
||||||
std::string::const_iterator i = nodes.begin();
|
std::string::const_iterator i = nodes.begin();
|
||||||
std::string::const_iterator end = nodes.end();
|
std::string::const_iterator end = nodes.end();
|
||||||
|
@ -473,6 +468,31 @@ namespace libtorrent { namespace dht
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entry const* n = r.find_key("nodes2"))
|
||||||
|
{
|
||||||
|
entry::list_type const& contacts = n->list();
|
||||||
|
for (entry::list_type::const_iterator i = contacts.begin()
|
||||||
|
, end(contacts.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
std::string const& p = i->string();
|
||||||
|
if (p.size() < 6 + 20) continue;
|
||||||
|
std::string::const_iterator in = p.begin();
|
||||||
|
|
||||||
|
node_id id;
|
||||||
|
std::copy(in, in + 20, id.begin());
|
||||||
|
in += 20;
|
||||||
|
if (p.size() == 6 + 20)
|
||||||
|
m.nodes.push_back(libtorrent::dht::node_entry(
|
||||||
|
id, read_v4_endpoint<udp::endpoint>(in)));
|
||||||
|
else if (p.size() == 18 + 20)
|
||||||
|
m.nodes.push_back(libtorrent::dht::node_entry(
|
||||||
|
id, read_v6_endpoint<udp::endpoint>(in)));
|
||||||
|
}
|
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
|
TORRENT_LOG(dht_tracker) << " nodes2 + nodes: " << m.nodes.size();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
entry const* token = r.find_key("token");
|
entry const* token = r.find_key("token");
|
||||||
if (token) m.write_token = *token;
|
if (token) m.write_token = *token;
|
||||||
}
|
}
|
||||||
|
@ -697,17 +717,39 @@ namespace libtorrent { namespace dht
|
||||||
break;
|
break;
|
||||||
case messages::find_node:
|
case messages::find_node:
|
||||||
{
|
{
|
||||||
|
bool ipv6_nodes = false;
|
||||||
r["nodes"] = entry(entry::string_t);
|
r["nodes"] = entry(entry::string_t);
|
||||||
entry& n = r["nodes"];
|
entry& n = r["nodes"];
|
||||||
std::back_insert_iterator<std::string> out(n.string());
|
std::back_insert_iterator<std::string> out(n.string());
|
||||||
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
||||||
, end(m.nodes.end()); i != end; ++i)
|
, end(m.nodes.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
|
if (!i->addr.address().is_v4())
|
||||||
|
{
|
||||||
|
ipv6_nodes = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
std::copy(i->id.begin(), i->id.end(), out);
|
std::copy(i->id.begin(), i->id.end(), out);
|
||||||
write_endpoint(i->addr, out);
|
write_endpoint(i->addr, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ipv6_nodes)
|
||||||
|
{
|
||||||
|
r["nodes2"] = entry(entry::list_t);
|
||||||
|
entry& p = r["nodes2"];
|
||||||
|
std::string endpoint;
|
||||||
|
endpoint.resize(6);
|
||||||
|
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
||||||
|
, end(m.nodes.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
std::string::iterator out = endpoint.begin();
|
||||||
|
std::copy(i->id.begin(), i->id.end(), out);
|
||||||
|
write_endpoint(i->addr, out);
|
||||||
|
p.list().push_back(entry(endpoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
|
TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -721,6 +763,7 @@ namespace libtorrent { namespace dht
|
||||||
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
||||||
, end(m.nodes.end()); i != end; ++i)
|
, end(m.nodes.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
|
if (!i->addr.address().is_v4()) continue;
|
||||||
std::copy(i->id.begin(), i->id.end(), out);
|
std::copy(i->id.begin(), i->id.end(), out);
|
||||||
write_endpoint(i->addr, out);
|
write_endpoint(i->addr, out);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue