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>(
|
||||
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
|
||||
|
@ -161,24 +180,11 @@ namespace libtorrent { namespace dht
|
|||
|
||||
if (bootstrap.type() == entry::dictionary_t)
|
||||
{
|
||||
if (entry const* nodes = bootstrap.find_key("nodes"))
|
||||
try
|
||||
{
|
||||
if (nodes->type() == entry::list_t)
|
||||
{
|
||||
entry::list_type const& node_list = nodes->list();
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (entry const* nodes = bootstrap.find_key("nodes"))
|
||||
read_endpoint_list<udp::endpoint>(nodes, initial_nodes);
|
||||
} catch (std::exception&) {}
|
||||
}
|
||||
|
||||
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"))
|
||||
{
|
||||
m.peers.clear();
|
||||
entry::list_type const& peers = n->list();
|
||||
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));
|
||||
}
|
||||
read_endpoint_list<tcp::endpoint>(n, m.peers);
|
||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||
TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size();
|
||||
#endif
|
||||
}
|
||||
|
||||
m.nodes.clear();
|
||||
if (entry const* n = r.find_key("nodes"))
|
||||
{
|
||||
m.nodes.clear();
|
||||
std::string const& nodes = n->string();
|
||||
std::string::const_iterator i = nodes.begin();
|
||||
std::string::const_iterator end = nodes.end();
|
||||
|
@ -473,6 +468,31 @@ namespace libtorrent { namespace dht
|
|||
#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");
|
||||
if (token) m.write_token = *token;
|
||||
}
|
||||
|
@ -697,17 +717,39 @@ namespace libtorrent { namespace dht
|
|||
break;
|
||||
case messages::find_node:
|
||||
{
|
||||
bool ipv6_nodes = false;
|
||||
r["nodes"] = entry(entry::string_t);
|
||||
entry& n = r["nodes"];
|
||||
std::back_insert_iterator<std::string> out(n.string());
|
||||
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
||||
, 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);
|
||||
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
|
||||
TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
|
||||
TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
@ -721,6 +763,7 @@ namespace libtorrent { namespace dht
|
|||
for (msg::nodes_t::const_iterator i = m.nodes.begin()
|
||||
, end(m.nodes.end()); i != end; ++i)
|
||||
{
|
||||
if (!i->addr.address().is_v4()) continue;
|
||||
std::copy(i->id.begin(), i->id.end(), out);
|
||||
write_endpoint(i->addr, out);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue