implement a sligthtly more aggressive DHT lookup mechanism
This commit is contained in:
parent
002d69a9fc
commit
ab7369fee9
|
@ -1,3 +1,4 @@
|
||||||
|
* improve DHT lookup speed
|
||||||
* improve support for windows XP and earlier
|
* improve support for windows XP and earlier
|
||||||
* introduce global connection priority for improved swarm performance
|
* introduce global connection priority for improved swarm performance
|
||||||
* make files deleted alert non-discardable
|
* make files deleted alert non-discardable
|
||||||
|
|
|
@ -1433,6 +1433,7 @@ struct has the following members::
|
||||||
bool restrict_routing_ips;
|
bool restrict_routing_ips;
|
||||||
bool restrict_search_ips;
|
bool restrict_search_ips;
|
||||||
bool extended_routing_table;
|
bool extended_routing_table;
|
||||||
|
bool aggressive_lookups;
|
||||||
};
|
};
|
||||||
|
|
||||||
``max_peers_reply`` is the maximum number of peers the node will send in
|
``max_peers_reply`` is the maximum number of peers the node will send in
|
||||||
|
@ -1474,6 +1475,12 @@ which port the DHT would listen on and send messages from. This field is depreca
|
||||||
and ignored. libtorrent always tries to open the UDP socket on the same port
|
and ignored. libtorrent always tries to open the UDP socket on the same port
|
||||||
as the TCP socket.
|
as the TCP socket.
|
||||||
|
|
||||||
|
``aggressive_lookups`` slightly changes the lookup behavior in terms of how
|
||||||
|
many outstanding requests we keep. Instead of having branch factor be a hard
|
||||||
|
limit, we always keep *branch factor* outstanding requests to the closest nodes.
|
||||||
|
i.e. every time we get results back with closer nodes, we query them right away.
|
||||||
|
It lowers the lookup times at the cost of more outstanding queries.
|
||||||
|
|
||||||
``is_dht_running()`` returns true if the DHT support has been started and false
|
``is_dht_running()`` returns true if the DHT support has been started and false
|
||||||
otherwise.
|
otherwise.
|
||||||
|
|
||||||
|
|
|
@ -1,540 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8" ?>
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
|
||||||
<head>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
||||||
<meta name="generator" content="Docutils 0.5: http://docutils.sourceforge.net/" />
|
|
||||||
<title>Bittorrent udp-tracker protocol extension</title>
|
|
||||||
<meta name="author" content="Arvid Norberg, arvid@rasterbar.com" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../css/base.css" />
|
|
||||||
<link rel="stylesheet" type="text/css" href="../../css/rst.css" />
|
|
||||||
<script type="text/javascript">
|
|
||||||
/* <![CDATA[ */
|
|
||||||
(function() {
|
|
||||||
var s = document.createElement('script'), t = document.getElementsByTagName('script')[0];
|
|
||||||
s.type = 'text/javascript';
|
|
||||||
s.async = true;
|
|
||||||
s.src = 'http://api.flattr.com/js/0.6/load.js?mode=auto';
|
|
||||||
t.parentNode.insertBefore(s, t);
|
|
||||||
})();
|
|
||||||
/* ]]> */
|
|
||||||
</script>
|
|
||||||
<link rel="stylesheet" href="style.css" type="text/css" />
|
|
||||||
<style type="text/css">
|
|
||||||
/* Hides from IE-mac \*/
|
|
||||||
* html pre { height: 1%; }
|
|
||||||
/* End hide from IE-mac */
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="document" id="bittorrent-udp-tracker-protocol-extension">
|
|
||||||
<div id="container">
|
|
||||||
<div id="headerNav">
|
|
||||||
<ul>
|
|
||||||
<li class="first"><a href="/">Home</a></li>
|
|
||||||
<li><a href="../../products.html">Products</a></li>
|
|
||||||
<li><a href="../../contact.html">Contact</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div id="header">
|
|
||||||
<h1><span>Rasterbar Software</span></h1>
|
|
||||||
<h2><span>Software developement and consulting</span></h2>
|
|
||||||
</div>
|
|
||||||
<div id="main">
|
|
||||||
<h1 class="title">Bittorrent udp-tracker protocol extension</h1>
|
|
||||||
<table class="docinfo" frame="void" rules="none">
|
|
||||||
<col class="docinfo-name" />
|
|
||||||
<col class="docinfo-content" />
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><th class="docinfo-name">Author:</th>
|
|
||||||
<td>Arvid Norberg, <a class="last reference external" href="mailto:arvid@rasterbar.com">arvid@rasterbar.com</a></td></tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<div class="contents topic" id="table-of-contents">
|
|
||||||
<p class="topic-title first">Table of contents</p>
|
|
||||||
<ul class="simple">
|
|
||||||
<li><a class="reference internal" href="#introduction" id="id2">introduction</a></li>
|
|
||||||
<li><a class="reference internal" href="#connecting" id="id3">connecting</a></li>
|
|
||||||
<li><a class="reference internal" href="#announcing" id="id4">announcing</a></li>
|
|
||||||
<li><a class="reference internal" href="#scraping" id="id5">scraping</a></li>
|
|
||||||
<li><a class="reference internal" href="#errors" id="id6">errors</a></li>
|
|
||||||
<li><a class="reference internal" href="#actions" id="id7">actions</a></li>
|
|
||||||
<li><a class="reference internal" href="#extensions" id="id8">extensions</a><ul>
|
|
||||||
<li><a class="reference internal" href="#authentication" id="id9">authentication</a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li><a class="reference internal" href="#credits" id="id10">credits</a></li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="introduction">
|
|
||||||
<h1>introduction</h1>
|
|
||||||
<p>A tracker with the protocol "udp://" in its URI
|
|
||||||
is supposed to be contacted using this protocol.</p>
|
|
||||||
<p>This protocol is supported by
|
|
||||||
<a class="reference external" href="http://xbtt.sourceforge.net">xbt-tracker</a>.</p>
|
|
||||||
<p>For additional information and descritptions of
|
|
||||||
the terminology used in this document, see
|
|
||||||
the <a class="reference external" href="http://wiki.theory.org/index.php/BitTorrentSpecification">protocol specification</a></p>
|
|
||||||
<p>All values are sent in network byte order (big endian). The sizes
|
|
||||||
are specified with ANSI-C standard types.</p>
|
|
||||||
<p>If no response to a request is received within 15 seconds, resend
|
|
||||||
the request. If no reply has been received after 60 seconds, stop
|
|
||||||
retrying.</p>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="connecting">
|
|
||||||
<h1>connecting</h1>
|
|
||||||
<p>Client sends packet:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int64_t</td>
|
|
||||||
<td>connection_id</td>
|
|
||||||
<td>Must be initialized to 0x41727101980
|
|
||||||
in network byte order. This will
|
|
||||||
identify the protocol.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>action</td>
|
|
||||||
<td>0 for a connection request</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>transaction_id</td>
|
|
||||||
<td>Randomized by client.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>Server replies with packet:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>action</td>
|
|
||||||
<td>Describes the type of packet, in this
|
|
||||||
case it should be 0, for connect.
|
|
||||||
If 3 (for error) see <a class="reference internal" href="#errors">errors</a>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>transaction_id</td>
|
|
||||||
<td>Must match the transaction_id sent
|
|
||||||
from the client.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int64_t</td>
|
|
||||||
<td>connection_id</td>
|
|
||||||
<td>A connection id, this is used when
|
|
||||||
further information is exchanged with
|
|
||||||
the tracker, to identify you.
|
|
||||||
This connection id can be reused for
|
|
||||||
multiple requests, but if it's cached
|
|
||||||
for too long, it will not be valid
|
|
||||||
anymore.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="announcing">
|
|
||||||
<h1>announcing</h1>
|
|
||||||
<p>Client sends packet:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int64_t</td>
|
|
||||||
<td>connection_id</td>
|
|
||||||
<td>The connection id acquired from
|
|
||||||
establishing the connection.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>action</td>
|
|
||||||
<td>Action. in this case, 1 for announce.
|
|
||||||
See <a class="reference internal" href="#actions">actions</a>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>transaction_id</td>
|
|
||||||
<td>Randomized by client.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int8_t[20]</td>
|
|
||||||
<td>info_hash</td>
|
|
||||||
<td>The info-hash of the torrent you want
|
|
||||||
announce yourself in.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int8_t[20]</td>
|
|
||||||
<td>peer_id</td>
|
|
||||||
<td>Your peer id.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int64_t</td>
|
|
||||||
<td>downloaded</td>
|
|
||||||
<td>The number of byte you've downloaded
|
|
||||||
in this session.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int64_t</td>
|
|
||||||
<td>left</td>
|
|
||||||
<td>The number of bytes you have left to
|
|
||||||
download until you're finished.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int64_t</td>
|
|
||||||
<td>uploaded</td>
|
|
||||||
<td>The number of bytes you have uploaded
|
|
||||||
in this session.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>event</td>
|
|
||||||
<td><p class="first">The event, one of</p>
|
|
||||||
<blockquote class="last">
|
|
||||||
<ul class="simple">
|
|
||||||
<li>none = 0</li>
|
|
||||||
<li>completed = 1</li>
|
|
||||||
<li>started = 2</li>
|
|
||||||
<li>stopped = 3</li>
|
|
||||||
</ul>
|
|
||||||
</blockquote>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>uint32_t</td>
|
|
||||||
<td>ip</td>
|
|
||||||
<td>Your ip address. Set to 0 if you want
|
|
||||||
the tracker to use the <tt class="docutils literal"><span class="pre">sender</span></tt> of
|
|
||||||
this udp packet.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>uint32_t</td>
|
|
||||||
<td>key</td>
|
|
||||||
<td>A unique key that is randomized by the
|
|
||||||
client.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>num_want</td>
|
|
||||||
<td>The maximum number of peers you want
|
|
||||||
in the reply. Use -1 for default.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>uint16_t</td>
|
|
||||||
<td>port</td>
|
|
||||||
<td>The port you're listening on.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>uint16_t</td>
|
|
||||||
<td>extensions</td>
|
|
||||||
<td>See <a class="reference internal" href="#extensions">extensions</a></td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>Server replies with packet:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>action</td>
|
|
||||||
<td>The action this is a reply to. Should
|
|
||||||
in this case be 1 for announce.
|
|
||||||
If 3 (for error) see <a class="reference internal" href="#errors">errors</a>.
|
|
||||||
See <a class="reference internal" href="#actions">actions</a>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>transaction_id</td>
|
|
||||||
<td>Must match the transaction_id sent
|
|
||||||
in the announce request.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>interval</td>
|
|
||||||
<td>the number of seconds you should wait
|
|
||||||
until reannouncing yourself.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>leechers</td>
|
|
||||||
<td>The number of peers in the swarm that
|
|
||||||
has not finished downloading.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>seeders</td>
|
|
||||||
<td>The number of peers in the swarm that
|
|
||||||
has finished downloading and are
|
|
||||||
seeding.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>The rest of the server reply is a variable number of the following structure:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>ip</td>
|
|
||||||
<td>The ip of a peer in the swarm.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>uint16_t</td>
|
|
||||||
<td>port</td>
|
|
||||||
<td>The peer's listen port.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="scraping">
|
|
||||||
<h1>scraping</h1>
|
|
||||||
<p>Client sends packet:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int64_t</td>
|
|
||||||
<td>connection_id</td>
|
|
||||||
<td>The connection id retreived from the
|
|
||||||
establishing of the connection.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>action</td>
|
|
||||||
<td>The action, in this case, 2 for
|
|
||||||
scrape. See <a class="reference internal" href="#actions">actions</a>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>transaction_id</td>
|
|
||||||
<td>Randomized by client.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>The following structure is repeated for each info-hash to scrape, but limited by
|
|
||||||
the MTU.</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int8_t[20]</td>
|
|
||||||
<td>info_hash</td>
|
|
||||||
<td>The info hash that is to be scraped.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>Server replies with packet:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>action</td>
|
|
||||||
<td>The action, should in this case be
|
|
||||||
2 for scrape.
|
|
||||||
If 3 (for error) see <a class="reference internal" href="#errors">errors</a>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>transaction_id</td>
|
|
||||||
<td>Must match the sent transaction id.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
<p>The rest of the packet contains the following structures once for each info-hash
|
|
||||||
you asked in the scrape request.</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>complete</td>
|
|
||||||
<td>The current number of connected seeds.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>downloaded</td>
|
|
||||||
<td>The number of times this torrent has
|
|
||||||
been downloaded.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>incomplete</td>
|
|
||||||
<td>The current number of connected
|
|
||||||
leechers.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="errors">
|
|
||||||
<h1>errors</h1>
|
|
||||||
<p>In case of a tracker error,</p>
|
|
||||||
<p>server replies packet:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>action</td>
|
|
||||||
<td>The action, in this case 3, for error.
|
|
||||||
See <a class="reference internal" href="#actions">actions</a>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int32_t</td>
|
|
||||||
<td>transaction_id</td>
|
|
||||||
<td>Must match the transaction_id sent
|
|
||||||
from the client.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int8_t[]</td>
|
|
||||||
<td>error_string</td>
|
|
||||||
<td>The rest of the packet is a string
|
|
||||||
describing the error.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="actions">
|
|
||||||
<h1>actions</h1>
|
|
||||||
<p>The action fields has the following encoding:</p>
|
|
||||||
<blockquote>
|
|
||||||
<ul class="simple">
|
|
||||||
<li>connect = 0</li>
|
|
||||||
<li>announce = 1</li>
|
|
||||||
<li>scrape = 2</li>
|
|
||||||
<li>error = 3 (only in server replies)</li>
|
|
||||||
</ul>
|
|
||||||
</blockquote>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="extensions">
|
|
||||||
<h1>extensions</h1>
|
|
||||||
<p>The extensions field is a bitmask. The following
|
|
||||||
bits are assigned:</p>
|
|
||||||
<blockquote>
|
|
||||||
<ul class="simple">
|
|
||||||
<li>1 = <a class="reference internal" href="#authentication">authentication</a>.</li>
|
|
||||||
</ul>
|
|
||||||
</blockquote>
|
|
||||||
<div class="section" id="authentication">
|
|
||||||
<h2>authentication</h2>
|
|
||||||
<p>The packet will have an authentication part
|
|
||||||
appended to it. It has the following format:</p>
|
|
||||||
<table border="1" class="docutils">
|
|
||||||
<colgroup>
|
|
||||||
<col width="18%" />
|
|
||||||
<col width="28%" />
|
|
||||||
<col width="54%" />
|
|
||||||
</colgroup>
|
|
||||||
<thead valign="bottom">
|
|
||||||
<tr><th class="head">size</th>
|
|
||||||
<th class="head">name</th>
|
|
||||||
<th class="head">description</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody valign="top">
|
|
||||||
<tr><td>int8_t</td>
|
|
||||||
<td>username_length</td>
|
|
||||||
<td>The number of characters in the
|
|
||||||
username.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>int8_t[]</td>
|
|
||||||
<td>username</td>
|
|
||||||
<td>The username, the number of characters
|
|
||||||
as specified in the previous field.</td>
|
|
||||||
</tr>
|
|
||||||
<tr><td>uint8_t[8]</td>
|
|
||||||
<td>passwd_hash</td>
|
|
||||||
<td>sha1(packet + sha1(password))
|
|
||||||
The packet in this case means the
|
|
||||||
entire packet except these 8 bytes
|
|
||||||
that are the password hash. These are
|
|
||||||
the 8 first bytes (most significant)
|
|
||||||
from the 20 bytes hash calculated.</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="section" id="credits">
|
|
||||||
<h1>credits</h1>
|
|
||||||
<p>Protocol designed by Olaf van der Spek</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div id="footer">
|
|
||||||
<span>Copyright © 2005 Rasterbar Software.</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
|
|
||||||
</script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
_uacct = "UA-1599045-1";
|
|
||||||
urchinTracker();
|
|
||||||
</script>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
|
@ -79,10 +79,14 @@ struct traversal_algorithm : boost::noncopyable
|
||||||
void add_entry(node_id const& id, udp::endpoint addr, unsigned char flags);
|
void add_entry(node_id const& id, udp::endpoint addr, unsigned char flags);
|
||||||
|
|
||||||
traversal_algorithm(node_impl& node, node_id target);
|
traversal_algorithm(node_impl& node, node_id target);
|
||||||
|
int invoke_count() const { return m_invoke_count; }
|
||||||
|
int branch_factor() const { return m_branch_factor; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
void add_requests();
|
// returns true if we're done
|
||||||
|
bool add_requests();
|
||||||
|
|
||||||
void add_router_entries();
|
void add_router_entries();
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
|
|
@ -959,6 +959,7 @@ namespace libtorrent
|
||||||
, restrict_routing_ips(true)
|
, restrict_routing_ips(true)
|
||||||
, restrict_search_ips(true)
|
, restrict_search_ips(true)
|
||||||
, extended_routing_table(true)
|
, extended_routing_table(true)
|
||||||
|
, aggressive_lookups(true)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// the maximum number of peers to send in a
|
// the maximum number of peers to send in a
|
||||||
|
@ -1005,6 +1006,11 @@ namespace libtorrent
|
||||||
// table are enlarged, to make room for more nodes in order
|
// table are enlarged, to make room for more nodes in order
|
||||||
// to lower the look-up times
|
// to lower the look-up times
|
||||||
bool extended_routing_table;
|
bool extended_routing_table;
|
||||||
|
|
||||||
|
// makes lookups waste less time finding results,
|
||||||
|
// at the cost of being more likely to keep more
|
||||||
|
// outstanding requests
|
||||||
|
bool aggressive_lookups;
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
138
parse_dht_log.py
138
parse_dht_log.py
|
@ -1,6 +1,8 @@
|
||||||
#! /usr/bin/env python
|
#! /usr/bin/env python
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
import time
|
||||||
|
import calendar
|
||||||
|
|
||||||
up_time_quanta = 2000
|
up_time_quanta = 2000
|
||||||
|
|
||||||
|
@ -11,20 +13,34 @@ node_uptime_histogram = {}
|
||||||
|
|
||||||
counter = 0;
|
counter = 0;
|
||||||
|
|
||||||
|
# maps search_id to a list of events. Each event is a dict containing:
|
||||||
|
# t: timestamp
|
||||||
|
# d: distance (from target)
|
||||||
|
# o: outstanding searches
|
||||||
|
# e: event (NEW, COMPLETED, ADD, INVOKE, TIMEOUT)
|
||||||
|
outstanding_searches = {}
|
||||||
|
|
||||||
|
# list of completed searches
|
||||||
|
searches = []
|
||||||
|
|
||||||
|
def convert_timestamp(t):
|
||||||
|
parts = t.split('.')
|
||||||
|
posix = time.strptime(parts[0], '%H:%M:%S')
|
||||||
|
return (posix.tm_hour * 3600 + posix.tm_min * 60 + posix.tm_sec) * 1000 + int(parts[1])
|
||||||
|
|
||||||
for line in f:
|
for line in f:
|
||||||
counter += 1
|
counter += 1
|
||||||
# if counter % 1000 == 0:
|
# if counter % 1000 == 0:
|
||||||
# print '\r%d' % counter,
|
# print '\r%d' % counter,
|
||||||
try:
|
try:
|
||||||
if 'distance:' in line:
|
l = line.split(' ')
|
||||||
l = line.split(' ')
|
if 'announce-distance:' in line:
|
||||||
idx = l.index('distance:')
|
idx = l.index('announce-distance:')
|
||||||
|
|
||||||
d = int(l[idx+1].strip())
|
d = int(l[idx+1].strip())
|
||||||
if not d in announce_histogram: announce_histogram[d] = 0
|
if not d in announce_histogram: announce_histogram[d] = 0
|
||||||
announce_histogram[d] += 1
|
announce_histogram[d] += 1
|
||||||
if 'NODE FAILED' in line:
|
if 'NODE FAILED' in line:
|
||||||
l = line.split(' ')
|
|
||||||
idx = l.index('fails:')
|
idx = l.index('fails:')
|
||||||
if int(l[idx+1].strip()) != 1: continue;
|
if int(l[idx+1].strip()) != 1: continue;
|
||||||
idx = l.index('up-time:')
|
idx = l.index('up-time:')
|
||||||
|
@ -33,9 +49,77 @@ for line in f:
|
||||||
d = d - (d % up_time_quanta)
|
d = d - (d % up_time_quanta)
|
||||||
if not d in node_uptime_histogram: node_uptime_histogram[d] = 0
|
if not d in node_uptime_histogram: node_uptime_histogram[d] = 0
|
||||||
node_uptime_histogram[d] += 1
|
node_uptime_histogram[d] += 1
|
||||||
|
|
||||||
|
search_id = l[2]
|
||||||
|
ts = l[0]
|
||||||
|
event = l[3]
|
||||||
|
|
||||||
|
if event == 'NEW':
|
||||||
|
outstanding_searches[search_id] = [{ 't': ts, 'd': 160, 'o': 0, 'e': 'NEW'}]
|
||||||
|
elif event == 'INVOKE' or event == 'ADD' or event == '1ST_TIMEOUT' or event == 'TIMEOUT' or event == 'PEERS':
|
||||||
|
if not search_id in outstanding_searches:
|
||||||
|
print 'orphaned event: %s' % line
|
||||||
|
else:
|
||||||
|
outstanding = int(l[l.index('invoke-count:')+1])
|
||||||
|
distance = int(l[l.index('distance:')+1])
|
||||||
|
outstanding_searches[search_id].append({ 't': ts, 'd': distance, 'o': outstanding + 1, 'e': event})
|
||||||
|
elif event == 'COMPLETED':
|
||||||
|
distance = int(l[l.index('distance:')+1])
|
||||||
|
outstanding_searches[search_id].append({ 't': ts, 'd': distance, 'o': 0, 'e': event})
|
||||||
|
|
||||||
|
s = outstanding_searches[search_id]
|
||||||
|
|
||||||
|
try:
|
||||||
|
start_time = convert_timestamp(s[0]['t'])
|
||||||
|
for i in range(len(s)):
|
||||||
|
s[i]['t'] = convert_timestamp(s[i]['t']) - start_time
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
searches.append(s)
|
||||||
|
del outstanding_searches[search_id]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
print line.split(' ')
|
print line.split(' ')
|
||||||
|
|
||||||
|
lookup_times_min = []
|
||||||
|
lookup_times_max = []
|
||||||
|
for s in searches:
|
||||||
|
for i in s:
|
||||||
|
if i['e'] != 'PEERS': continue
|
||||||
|
lookup_times_min.append(i['t'])
|
||||||
|
break
|
||||||
|
for i in reversed(s):
|
||||||
|
if i['e'] != 'PEERS': continue
|
||||||
|
lookup_times_max.append(i['t'])
|
||||||
|
break
|
||||||
|
|
||||||
|
lookup_times_min.sort()
|
||||||
|
lookup_times_max.sort()
|
||||||
|
out = open('dht_lookup_times_cdf.txt', 'w+')
|
||||||
|
counter = 0
|
||||||
|
for i in range(len(lookup_times_min)):
|
||||||
|
counter += 1
|
||||||
|
print >>out, '%d\t%d\t%f' % (lookup_times_min[i], lookup_times_max[i], counter / float(len(lookup_times_min)))
|
||||||
|
out.close()
|
||||||
|
|
||||||
|
out = open('dht_lookups.txt', 'w+')
|
||||||
|
for s in searches:
|
||||||
|
for i in s:
|
||||||
|
if i['e'] == 'INVOKE':
|
||||||
|
print >>out, ' ->', i['t'], i['d']
|
||||||
|
elif i['e'] == '1ST_TIMEOUT':
|
||||||
|
print >>out, ' x ', i['t'], i['d']
|
||||||
|
elif i['e'] == 'TIMEOUT':
|
||||||
|
print >>out, ' X ', i['t'], i['d']
|
||||||
|
elif i['e'] == 'PEERS':
|
||||||
|
print >>out, ' <-', i['t'], i['d']
|
||||||
|
elif i['e'] == 'COMPLETED':
|
||||||
|
print >>out, '***', i['t'], i['d'], '\n'
|
||||||
|
break
|
||||||
|
out.close()
|
||||||
|
|
||||||
out = open('dht_announce_distribution.dat', 'w+')
|
out = open('dht_announce_distribution.dat', 'w+')
|
||||||
print 'announce distribution items: %d' % len(announce_histogram)
|
print 'announce distribution items: %d' % len(announce_histogram)
|
||||||
for k,v in announce_histogram.items():
|
for k,v in announce_histogram.items():
|
||||||
|
@ -51,8 +135,44 @@ out.close()
|
||||||
|
|
||||||
out = open('dht.gnuplot', 'w+')
|
out = open('dht.gnuplot', 'w+')
|
||||||
out.write('''
|
out.write('''
|
||||||
|
set term png size 1200,700 small
|
||||||
|
set output "dht_lookup_times_cdf.png"
|
||||||
|
set title "portion of lookups that have received at least one data response"
|
||||||
|
set ylabel "portion of lookups"
|
||||||
|
set xlabel "time from start of lookup (ms)"
|
||||||
|
set grid
|
||||||
|
plot "dht_lookup_times_cdf.txt" using 1:3 with lines title "time to first result", \
|
||||||
|
"dht_lookup_times_cdf.txt" using 2:3 with lines title "time to last result"
|
||||||
|
|
||||||
|
set terminal postscript
|
||||||
|
set output "dht_lookup_times_cdf.ps"
|
||||||
|
replot
|
||||||
|
|
||||||
|
set term png size 1200,700 small
|
||||||
|
set xtics 100
|
||||||
|
set xrange [0:2000]
|
||||||
|
set output "dht_min_lookup_times_cdf.png"
|
||||||
|
plot "dht_lookup_times_cdf.txt" using 1:3 with lines title "time to first result"
|
||||||
|
|
||||||
|
set terminal postscript
|
||||||
|
set output "dht_min_lookup_times_cdf.ps"
|
||||||
|
replot
|
||||||
|
|
||||||
|
set term png size 1200,700 small
|
||||||
|
set output "dht_node_uptime_distribution.png"
|
||||||
|
set xrange [*:*]
|
||||||
|
set title "node up time"
|
||||||
|
set ylabel "# of nodes"
|
||||||
|
set xlabel "uptime (seconds)"
|
||||||
|
set xtics auto
|
||||||
|
unset grid
|
||||||
|
set boxwidth %f
|
||||||
|
set style fill solid border -1 pattern 2
|
||||||
|
plot "dht_node_uptime_distribution.dat" using 1:2 title "nodes" with boxes
|
||||||
|
|
||||||
set term png size 1200,700 small
|
set term png size 1200,700 small
|
||||||
set output "dht_announce_distribution.png"
|
set output "dht_announce_distribution.png"
|
||||||
|
set xrange [0:*]
|
||||||
set title "bucket # announces are made against relative to target node-id"
|
set title "bucket # announces are made against relative to target node-id"
|
||||||
set ylabel "# of announces"
|
set ylabel "# of announces"
|
||||||
set style fill solid border -1 pattern 2
|
set style fill solid border -1 pattern 2
|
||||||
|
@ -62,15 +182,9 @@ set terminal postscript
|
||||||
set output "dht_announce_distribution.ps"
|
set output "dht_announce_distribution.ps"
|
||||||
replot
|
replot
|
||||||
|
|
||||||
set term png size 1200,700 small
|
|
||||||
set output "dht_node_uptime_distribution.png"
|
|
||||||
set title "node up time"
|
|
||||||
set ylabel "# of nodes"
|
|
||||||
set xlabel "uptime (seconds)"
|
|
||||||
set boxwidth %f
|
|
||||||
set style fill solid border -1 pattern 2
|
|
||||||
plot "dht_node_uptime_distribution.dat" using 1:2 title "nodes" with boxes
|
|
||||||
''' % up_time_quanta)
|
''' % up_time_quanta)
|
||||||
|
|
||||||
|
|
||||||
out.close()
|
out.close()
|
||||||
|
|
||||||
os.system('gnuplot dht.gnuplot');
|
os.system('gnuplot dht.gnuplot');
|
||||||
|
|
|
@ -234,7 +234,7 @@ namespace libtorrent { namespace dht
|
||||||
|
|
||||||
rpc_log().enable(false);
|
rpc_log().enable(false);
|
||||||
node_log().enable(false);
|
node_log().enable(false);
|
||||||
traversal_log().enable(false);
|
// traversal_log().enable(false);
|
||||||
// dht_tracker_log.enable(false);
|
// dht_tracker_log.enable(false);
|
||||||
|
|
||||||
TORRENT_LOG(dht_tracker) << "starting DHT tracker with node id: " << m_dht.nid();
|
TORRENT_LOG(dht_tracker) << "starting DHT tracker with node id: " << m_dht.nid();
|
||||||
|
|
|
@ -56,11 +56,6 @@ using detail::read_v6_endpoint;
|
||||||
|
|
||||||
void find_data_observer::reply(msg const& m)
|
void find_data_observer::reply(msg const& m)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
||||||
std::stringstream log_line;
|
|
||||||
log_line << "[" << m_algorithm.get() << "] incoming get_peer response [ ";
|
|
||||||
#endif
|
|
||||||
|
|
||||||
lazy_entry const* r = m.message.dict_find_dict("r");
|
lazy_entry const* r = m.message.dict_find_dict("r");
|
||||||
if (!r)
|
if (!r)
|
||||||
{
|
{
|
||||||
|
@ -78,16 +73,11 @@ void find_data_observer::reply(msg const& m)
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_entry const* token = r->dict_find_string("token");
|
lazy_entry const* token = r->dict_find_string("token");
|
||||||
if (token)
|
if (token)
|
||||||
{
|
{
|
||||||
static_cast<find_data*>(m_algorithm.get())->got_write_token(
|
static_cast<find_data*>(m_algorithm.get())->got_write_token(
|
||||||
node_id(id->string_ptr()), token->string_value());
|
node_id(id->string_ptr()), token->string_value());
|
||||||
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
||||||
log_line << " token: " << to_hex(token->string_value());
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// look for peers
|
// look for peers
|
||||||
|
@ -102,7 +92,14 @@ void find_data_observer::reply(msg const& m)
|
||||||
char const* end = peers + n->list_at(0)->string_length();
|
char const* end = peers + n->list_at(0)->string_length();
|
||||||
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
log_line << " p: " << ((end - peers) / 6);
|
TORRENT_LOG(traversal)
|
||||||
|
<< "[" << m_algorithm.get() << "] PEERS"
|
||||||
|
<< " invoke-count: " << m_algorithm->invoke_count()
|
||||||
|
<< " branch-factor: " << m_algorithm->branch_factor()
|
||||||
|
<< " addr: " << m.addr
|
||||||
|
<< " id: " << node_id(id->string_ptr())
|
||||||
|
<< " distance: " << distance_exp(m_algorithm->target(), node_id(id->string_ptr()))
|
||||||
|
<< " p: " << ((end - peers) / 6);
|
||||||
#endif
|
#endif
|
||||||
while (end - peers >= 6)
|
while (end - peers >= 6)
|
||||||
peer_list.push_back(read_v4_endpoint<tcp::endpoint>(peers));
|
peer_list.push_back(read_v4_endpoint<tcp::endpoint>(peers));
|
||||||
|
@ -112,7 +109,14 @@ void find_data_observer::reply(msg const& m)
|
||||||
// assume it's uTorrent/libtorrent format
|
// assume it's uTorrent/libtorrent format
|
||||||
read_endpoint_list<tcp::endpoint>(n, peer_list);
|
read_endpoint_list<tcp::endpoint>(n, peer_list);
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
log_line << " p: " << n->list_size();
|
TORRENT_LOG(traversal)
|
||||||
|
<< "[" << m_algorithm.get() << "] PEERS"
|
||||||
|
<< " invoke-count: " << m_algorithm->invoke_count()
|
||||||
|
<< " branch-factor: " << m_algorithm->branch_factor()
|
||||||
|
<< " addr: " << m.addr
|
||||||
|
<< " id: " << node_id(id->string_ptr())
|
||||||
|
<< " distance: " << distance_exp(m_algorithm->target(), node_id(id->string_ptr()))
|
||||||
|
<< " p: " << n->list_size();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
static_cast<find_data*>(m_algorithm.get())->got_peers(peer_list);
|
static_cast<find_data*>(m_algorithm.get())->got_peers(peer_list);
|
||||||
|
@ -126,9 +130,6 @@ void find_data_observer::reply(msg const& m)
|
||||||
char const* nodes = n->string_ptr();
|
char const* nodes = n->string_ptr();
|
||||||
char const* end = nodes + n->string_length();
|
char const* end = nodes + n->string_length();
|
||||||
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
||||||
log_line << " nodes: " << ((end - nodes) / 26);
|
|
||||||
#endif
|
|
||||||
while (end - nodes >= 26)
|
while (end - nodes >= 26)
|
||||||
{
|
{
|
||||||
node_id id;
|
node_id id;
|
||||||
|
@ -141,9 +142,6 @@ void find_data_observer::reply(msg const& m)
|
||||||
n = r->dict_find_list("nodes2");
|
n = r->dict_find_list("nodes2");
|
||||||
if (n)
|
if (n)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
||||||
log_line << " nodes2: " << n->list_size();
|
|
||||||
#endif
|
|
||||||
for (int i = 0; i < n->list_size(); ++i)
|
for (int i = 0; i < n->list_size(); ++i)
|
||||||
{
|
{
|
||||||
lazy_entry const* p = n->list_at(0);
|
lazy_entry const* p = n->list_at(0);
|
||||||
|
@ -162,10 +160,6 @@ void find_data_observer::reply(msg const& m)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
|
||||||
log_line << " ]";
|
|
||||||
TORRENT_LOG(traversal) << log_line.str();
|
|
||||||
#endif
|
|
||||||
done();
|
done();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,7 +226,7 @@ void find_data::done()
|
||||||
m_done = true;
|
m_done = true;
|
||||||
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << time_now_string() << "[" << this << "] get_peers DONE";
|
TORRENT_LOG(traversal) << "[" << this << "] get_peers DONE";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<std::pair<node_entry, std::string> > results;
|
std::vector<std::pair<node_entry, std::string> > results;
|
||||||
|
|
|
@ -266,7 +266,7 @@ namespace
|
||||||
, end(v.end()); i != end; ++i)
|
, end(v.end()); i != end; ++i)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(node) << " distance: " << (160 - distance_exp(ih, i->first.id));
|
TORRENT_LOG(node) << " announce-distance: " << (160 - distance_exp(ih, i->first.id));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void* ptr = node.m_rpc.allocate_observer();
|
void* ptr = node.m_rpc.allocate_observer();
|
||||||
|
@ -666,7 +666,10 @@ void node_impl::incoming_request(msg const& m, entry& e)
|
||||||
if (msg_keys[3] && msg_keys[3]->int_value() != 0) scrape = true;
|
if (msg_keys[3] && msg_keys[3]->int_value() != 0) scrape = true;
|
||||||
lookup_peers(info_hash, prefix, reply, noseed, scrape);
|
lookup_peers(info_hash, prefix, reply, noseed, scrape);
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
if (reply.find_key("values")) TORRENT_LOG(node) << " values: " << reply["values"].list().size();
|
if (reply.find_key("values"))
|
||||||
|
{
|
||||||
|
TORRENT_LOG(node) << " values: " << reply["values"].list().size();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
else if (strcmp(query, "find_node") == 0)
|
else if (strcmp(query, "find_node") == 0)
|
||||||
|
|
|
@ -69,10 +69,11 @@ traversal_algorithm::traversal_algorithm(
|
||||||
, m_branch_factor(3)
|
, m_branch_factor(3)
|
||||||
, m_responses(0)
|
, m_responses(0)
|
||||||
, m_timeouts(0)
|
, m_timeouts(0)
|
||||||
, m_num_target_nodes(m_node.m_table.bucket_size() * 2)
|
, m_num_target_nodes(m_node.m_table.bucket_size())
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << " [" << this << "] new traversal process. Target: " << target;
|
TORRENT_LOG(traversal) << "[" << this << "] NEW"
|
||||||
|
" target: " << target << " k: " << m_node.m_table.bucket_size();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,8 +99,7 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig
|
||||||
if (ptr == 0)
|
if (ptr == 0)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << "[" << this << ":" << name()
|
TORRENT_LOG(traversal) << "[" << this << "] failed to allocate memory for observer. aborting!";
|
||||||
<< "] failed to allocate memory for observer. aborting!";
|
|
||||||
#endif
|
#endif
|
||||||
done();
|
done();
|
||||||
return;
|
return;
|
||||||
|
@ -139,19 +139,24 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig
|
||||||
// close to this one. We know that it's not the same, because
|
// close to this one. We know that it's not the same, because
|
||||||
// it claims a different node-ID. Ignore this to avoid attacks
|
// it claims a different node-ID. Ignore this to avoid attacks
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << "ignoring DHT search entry: " << o->id()
|
TORRENT_LOG(traversal) << "[" << this << "] IGNORING result "
|
||||||
<< " " << o->target_addr()
|
<< "id: " << o->id()
|
||||||
|
<< " address: " << o->target_addr()
|
||||||
<< " existing node: "
|
<< " existing node: "
|
||||||
<< (*j)->id() << " " << (*j)->target_addr();
|
<< (*j)->id() << " " << (*j)->target_addr()
|
||||||
|
<< " distance: " << distance_exp(m_target, o->id());
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
|
TORRENT_ASSERT(std::find_if(m_results.begin(), m_results.end()
|
||||||
, boost::bind(&observer::id, _1) == id) == m_results.end());
|
, boost::bind(&observer::id, _1) == id) == m_results.end());
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << "[" << this << ":" << name()
|
TORRENT_LOG(traversal) << "[" << this << "] ADD id: " << id
|
||||||
<< "] adding result: " << id << " " << addr;
|
<< " address: " << addr
|
||||||
|
<< " distance: " << distance_exp(m_target, id)
|
||||||
|
<< " invoke-count: " << m_invoke_count;
|
||||||
#endif
|
#endif
|
||||||
i = m_results.insert(i, o);
|
i = m_results.insert(i, o);
|
||||||
}
|
}
|
||||||
|
@ -189,8 +194,9 @@ void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
if (id.is_all_zeros())
|
if (id.is_all_zeros())
|
||||||
TORRENT_LOG(traversal) << time_now_string() << "[" << this << ":" << name()
|
{
|
||||||
<< "] WARNING: node returned a list which included a node with id 0";
|
TORRENT_LOG(traversal) << time_now_string() << "[" << this << "] WARNING node returned a list which included a node with id 0";
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
add_entry(id, addr, 0);
|
add_entry(id, addr, 0);
|
||||||
}
|
}
|
||||||
|
@ -215,8 +221,8 @@ void traversal_algorithm::finished(observer_ptr o)
|
||||||
++m_responses;
|
++m_responses;
|
||||||
--m_invoke_count;
|
--m_invoke_count;
|
||||||
TORRENT_ASSERT(m_invoke_count >= 0);
|
TORRENT_ASSERT(m_invoke_count >= 0);
|
||||||
add_requests();
|
bool is_done = add_requests();
|
||||||
if (m_invoke_count == 0) done();
|
if (is_done) done();
|
||||||
}
|
}
|
||||||
|
|
||||||
// prevent request means that the total number of requests has
|
// prevent request means that the total number of requests has
|
||||||
|
@ -241,9 +247,10 @@ void traversal_algorithm::failed(observer_ptr o, int flags)
|
||||||
++m_branch_factor;
|
++m_branch_factor;
|
||||||
o->flags |= observer::flag_short_timeout;
|
o->flags |= observer::flag_short_timeout;
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << " [" << this << ":" << name()
|
TORRENT_LOG(traversal) << "[" << this << "] 1ST_TIMEOUT "
|
||||||
<< "] first chance timeout: "
|
<< " id: " << o->id()
|
||||||
<< o->id() << " " << o->target_ep()
|
<< " distance: " << distance_exp(m_target, o->id())
|
||||||
|
<< " addr: " << o->target_ep()
|
||||||
<< " branch-factor: " << m_branch_factor
|
<< " branch-factor: " << m_branch_factor
|
||||||
<< " invoke-count: " << m_invoke_count;
|
<< " invoke-count: " << m_invoke_count;
|
||||||
#endif
|
#endif
|
||||||
|
@ -257,8 +264,10 @@ void traversal_algorithm::failed(observer_ptr o, int flags)
|
||||||
--m_branch_factor;
|
--m_branch_factor;
|
||||||
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << " [" << this << ":" << name()
|
TORRENT_LOG(traversal) << "[" << this << "] TIMEOUT "
|
||||||
<< "] failed: " << o->id() << " " << o->target_ep()
|
<< " id: " << o->id()
|
||||||
|
<< " distance: " << distance_exp(m_target, o->id())
|
||||||
|
<< " addr: " << o->target_ep()
|
||||||
<< " branch-factor: " << m_branch_factor
|
<< " branch-factor: " << m_branch_factor
|
||||||
<< " invoke-count: " << m_invoke_count;
|
<< " invoke-count: " << m_invoke_count;
|
||||||
#endif
|
#endif
|
||||||
|
@ -276,49 +285,122 @@ void traversal_algorithm::failed(observer_ptr o, int flags)
|
||||||
--m_branch_factor;
|
--m_branch_factor;
|
||||||
if (m_branch_factor <= 0) m_branch_factor = 1;
|
if (m_branch_factor <= 0) m_branch_factor = 1;
|
||||||
}
|
}
|
||||||
add_requests();
|
bool is_done = add_requests();
|
||||||
if (m_invoke_count == 0) done();
|
if (is_done) done();
|
||||||
}
|
}
|
||||||
|
|
||||||
void traversal_algorithm::done()
|
void traversal_algorithm::done()
|
||||||
{
|
{
|
||||||
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
|
int results_target = m_num_target_nodes;
|
||||||
|
int closest_target = 160;
|
||||||
|
|
||||||
|
for (std::vector<observer_ptr>::iterator i = m_results.begin()
|
||||||
|
, end(m_results.end()); i != end && results_target > 0; ++i)
|
||||||
|
{
|
||||||
|
boost::intrusive_ptr<observer> o = *i;
|
||||||
|
if (o->flags & observer::flag_alive)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(o->flags & observer::flag_queried);
|
||||||
|
TORRENT_LOG(traversal) << "[" << this << "] "
|
||||||
|
<< results_target
|
||||||
|
<< " id: " << o->id()
|
||||||
|
<< " distance: " << distance_exp(m_target, o->id())
|
||||||
|
<< " address: " << o->target_ep();
|
||||||
|
--results_target;
|
||||||
|
int dist = distance_exp(m_target, o->id());
|
||||||
|
if (dist < closest_target) closest_target = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_LOG(traversal) << "[" << this << "] COMPLETED "
|
||||||
|
<< "distance: " << closest_target;
|
||||||
|
|
||||||
|
#endif
|
||||||
// delete all our references to the observer objects so
|
// delete all our references to the observer objects so
|
||||||
// they will in turn release the traversal algorithm
|
// they will in turn release the traversal algorithm
|
||||||
m_results.clear();
|
m_results.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void traversal_algorithm::add_requests()
|
bool traversal_algorithm::add_requests()
|
||||||
{
|
{
|
||||||
int results_target = m_num_target_nodes;
|
int results_target = m_num_target_nodes;
|
||||||
|
|
||||||
|
// this only counts outstanding requests at the top of the
|
||||||
|
// target list. This is <= m_invoke count. m_invoke_count
|
||||||
|
// is the total number of outstanding requests, including
|
||||||
|
// old ones that may be waiting on nodes much farther behind
|
||||||
|
// the current point we've reached in the search.
|
||||||
|
int outstanding = 0;
|
||||||
|
|
||||||
|
// if we're doing aggressive lookups, we keep branch-factor
|
||||||
|
// outstanding requests _at the tops_ of the result list. Otherwise
|
||||||
|
// we just keep any branch-factor outstanding requests
|
||||||
|
bool agg = m_node.settings().aggressive_lookups;
|
||||||
|
|
||||||
// Find the first node that hasn't already been queried.
|
// Find the first node that hasn't already been queried.
|
||||||
|
// and make sure that the 'm_branch_factor' top nodes
|
||||||
|
// stay queried at all times (obviously ignoring failed nodes)
|
||||||
|
// and without surpassing the 'result_target' nodes (i.e. k=8)
|
||||||
|
// this is a slight variation of the original paper which instead
|
||||||
|
// limits the number of outstanding requests, this limits the
|
||||||
|
// number of good outstanding requests. It will use more traffic,
|
||||||
|
// but is intended to speed up lookups
|
||||||
for (std::vector<observer_ptr>::iterator i = m_results.begin()
|
for (std::vector<observer_ptr>::iterator i = m_results.begin()
|
||||||
, end(m_results.end()); i != end
|
, end(m_results.end()); i != end
|
||||||
&& results_target > 0 && m_invoke_count < m_branch_factor; ++i)
|
&& results_target > 0
|
||||||
|
&& (agg ? outstanding < m_branch_factor
|
||||||
|
: m_invoke_count < m_branch_factor);
|
||||||
|
++i)
|
||||||
{
|
{
|
||||||
if ((*i)->flags & observer::flag_alive) --results_target;
|
observer* o = i->get();
|
||||||
if ((*i)->flags & observer::flag_queried) continue;
|
if (o->flags & observer::flag_alive)
|
||||||
|
{
|
||||||
|
TORRENT_ASSERT(o->flags & observer::flag_queried);
|
||||||
|
--results_target;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (o->flags & observer::flag_queried)
|
||||||
|
{
|
||||||
|
// if it's queried, not alive and not failed, it
|
||||||
|
// must be currently in flight
|
||||||
|
if ((o->flags & observer::flag_failed) == 0)
|
||||||
|
++outstanding;
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << " [" << this << ":" << name() << "]"
|
TORRENT_LOG(traversal) << "[" << this << "] INVOKE "
|
||||||
<< " nodes-left: " << (m_results.end() - i)
|
<< " nodes-left: " << (m_results.end() - i)
|
||||||
|
<< " top-invoke-count: " << outstanding
|
||||||
<< " invoke-count: " << m_invoke_count
|
<< " invoke-count: " << m_invoke_count
|
||||||
<< " branch-factor: " << m_branch_factor;
|
<< " branch-factor: " << m_branch_factor
|
||||||
|
<< " distance: " << distance_exp(m_target, (*i)->id())
|
||||||
|
;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (invoke(*i))
|
if (invoke(*i))
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(m_invoke_count >= 0);
|
TORRENT_ASSERT(m_invoke_count >= 0);
|
||||||
++m_invoke_count;
|
++m_invoke_count;
|
||||||
(*i)->flags |= observer::flag_queried;
|
o->flags |= observer::flag_queried;
|
||||||
|
++outstanding;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this is the completion condition. If we found m_num_target_nodes
|
||||||
|
// (i.e. k=8) completed results, without finding any still
|
||||||
|
// outstanding requests, we're done.
|
||||||
|
// also, if invoke count is 0, it means we didn't even find 'k'
|
||||||
|
// working nodes, we still have to terminate though.
|
||||||
|
return (results_target == 0 && outstanding == 0) || m_invoke_count == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void traversal_algorithm::add_router_entries()
|
void traversal_algorithm::add_router_entries()
|
||||||
{
|
{
|
||||||
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
#ifdef TORRENT_DHT_VERBOSE_LOGGING
|
||||||
TORRENT_LOG(traversal) << " using router nodes to initiate traversal algorithm. "
|
TORRENT_LOG(traversal) << "[" << this << "] using router nodes to initiate traversal algorithm. "
|
||||||
<< std::distance(m_node.m_table.router_begin(), m_node.m_table.router_end()) << " routers";
|
<< std::distance(m_node.m_table.router_begin(), m_node.m_table.router_end()) << " routers";
|
||||||
#endif
|
#endif
|
||||||
for (routing_table::router_iterator i = m_node.m_table.router_begin()
|
for (routing_table::router_iterator i = m_node.m_table.router_begin()
|
||||||
|
|
Loading…
Reference in New Issue