added documentation of udp-tracker protocol and finalized support for it.

This commit is contained in:
Arvid Norberg 2004-01-22 22:45:52 +00:00
parent b897315abb
commit a3b47ec826
12 changed files with 799 additions and 174 deletions

View File

@ -59,8 +59,8 @@ example client.</p>
</div>
<div class="section" id="aknowledgements">
<h1><a name="aknowledgements">Aknowledgements</a></h1>
<p>Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003</p>
<p>Contributions by Magnus Jonsson</p>
<p>Written by Arvid Norberg. Copyright (c) 2003</p>
<p>Contributions by Magnus Jonsson and Daniel Wallin</p>
<p>Thanks to Reimond Retz for bugfixes, suggestions and testing</p>
<p>Project is hosted by sourceforge.</p>
<p><a class="reference" href="http://sourceforge.net"><img alt="sf_logo" src="http://sourceforge.net/sflogo.php?group_id=7994" /></a></p>

View File

@ -60,9 +60,9 @@ You can usually find me as hydri in ``#btports @ irc.freenode.net``.
Aknowledgements
===============
Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003
Written by Arvid Norberg. Copyright (c) 2003
Contributions by Magnus Jonsson
Contributions by Magnus Jonsson and Daniel Wallin
Thanks to Reimond Retz for bugfixes, suggestions and testing

View File

@ -13,57 +13,57 @@
<div class="contents topic" id="contents">
<p class="topic-title"><a name="contents">Contents</a></p>
<ul class="simple">
<li><a class="reference" href="#introduction" id="id8" name="id8">introduction</a></li>
<li><a class="reference" href="#building" id="id9" name="id9">building</a></li>
<li><a class="reference" href="#using" id="id10" name="id10">using</a></li>
<li><a class="reference" href="#session" id="id11" name="id11">session</a></li>
<li><a class="reference" href="#parsing-torrent-files" id="id12" name="id12">parsing torrent files</a></li>
<li><a class="reference" href="#entry" id="id13" name="id13">entry</a></li>
<li><a class="reference" href="#torrent-info" id="id14" name="id14">torrent_info</a></li>
<li><a class="reference" href="#torrent-handle" id="id15" name="id15">torrent_handle</a><ul>
<li><a class="reference" href="#status" id="id16" name="id16">status()</a></li>
<li><a class="reference" href="#get-download-queue" id="id17" name="id17">get_download_queue()</a></li>
<li><a class="reference" href="#get-peer-info" id="id18" name="id18">get_peer_info()</a></li>
<li><a class="reference" href="#get-torrent-info" id="id19" name="id19">get_torrent_info()</a></li>
<li><a class="reference" href="#is-valid" id="id20" name="id20">is_valid()</a></li>
<li><a class="reference" href="#introduction" id="id9" name="id9">introduction</a></li>
<li><a class="reference" href="#building" id="id10" name="id10">building</a></li>
<li><a class="reference" href="#using" id="id11" name="id11">using</a></li>
<li><a class="reference" href="#session" id="id12" name="id12">session</a></li>
<li><a class="reference" href="#parsing-torrent-files" id="id13" name="id13">parsing torrent files</a></li>
<li><a class="reference" href="#entry" id="id14" name="id14">entry</a></li>
<li><a class="reference" href="#torrent-info" id="id15" name="id15">torrent_info</a></li>
<li><a class="reference" href="#torrent-handle" id="id16" name="id16">torrent_handle</a><ul>
<li><a class="reference" href="#status" id="id17" name="id17">status()</a></li>
<li><a class="reference" href="#get-download-queue" id="id18" name="id18">get_download_queue()</a></li>
<li><a class="reference" href="#get-peer-info" id="id19" name="id19">get_peer_info()</a></li>
<li><a class="reference" href="#get-torrent-info" id="id20" name="id20">get_torrent_info()</a></li>
<li><a class="reference" href="#is-valid" id="id21" name="id21">is_valid()</a></li>
</ul>
</li>
<li><a class="reference" href="#address" id="id21" name="id21">address</a></li>
<li><a class="reference" href="#http-settings" id="id22" name="id22">http_settings</a></li>
<li><a class="reference" href="#big-number" id="id23" name="id23">big_number</a></li>
<li><a class="reference" href="#hasher" id="id24" name="id24">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id25" name="id25">fingerprint</a><ul>
<li><a class="reference" href="#identify-client" id="id26" name="id26">identify_client</a></li>
<li><a class="reference" href="#address" id="id22" name="id22">address</a></li>
<li><a class="reference" href="#http-settings" id="id23" name="id23">http_settings</a></li>
<li><a class="reference" href="#big-number" id="id24" name="id24">big_number</a></li>
<li><a class="reference" href="#hasher" id="id25" name="id25">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id26" name="id26">fingerprint</a><ul>
<li><a class="reference" href="#identify-client" id="id27" name="id27">identify_client</a></li>
</ul>
</li>
<li><a class="reference" href="#alerts" id="id27" name="id27">alerts</a><ul>
<li><a class="reference" href="#tracker-alert" id="id28" name="id28">tracker_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id29" name="id29">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id30" name="id30">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id31" name="id31">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id32" name="id32">torrent_finished_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id33" name="id33">dispatcher</a></li>
<li><a class="reference" href="#alerts" id="id28" name="id28">alerts</a><ul>
<li><a class="reference" href="#tracker-alert" id="id29" name="id29">tracker_alert</a></li>
<li><a class="reference" href="#hash-failed-alert" id="id30" name="id30">hash_failed_alert</a></li>
<li><a class="reference" href="#peer-error-alert" id="id31" name="id31">peer_error_alert</a></li>
<li><a class="reference" href="#invalid-request-alert" id="id32" name="id32">invalid_request_alert</a></li>
<li><a class="reference" href="#torrent-finished-alert" id="id33" name="id33">torrent_finished_alert</a></li>
<li><a class="reference" href="#dispatcher" id="id34" name="id34">dispatcher</a></li>
</ul>
</li>
<li><a class="reference" href="#exceptions" id="id34" name="id34">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id35" name="id35">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id36" name="id36">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id37" name="id37">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id38" name="id38">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id39" name="id39">invalid_torrent_file</a></li>
<li><a class="reference" href="#exceptions" id="id35" name="id35">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id36" name="id36">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id37" name="id37">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id38" name="id38">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id39" name="id39">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id40" name="id40">invalid_torrent_file</a></li>
</ul>
</li>
<li><a class="reference" href="#examples" id="id40" name="id40">examples</a><ul>
<li><a class="reference" href="#dump-torrent" id="id41" name="id41">dump_torrent</a></li>
<li><a class="reference" href="#simple-client" id="id42" name="id42">simple client</a></li>
<li><a class="reference" href="#examples" id="id41" name="id41">examples</a><ul>
<li><a class="reference" href="#dump-torrent" id="id42" name="id42">dump_torrent</a></li>
<li><a class="reference" href="#simple-client" id="id43" name="id43">simple client</a></li>
</ul>
</li>
<li><a class="reference" href="#fast-resume" id="id43" name="id43">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id44" name="id44">file format</a></li>
<li><a class="reference" href="#fast-resume" id="id44" name="id44">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id45" name="id45">file format</a></li>
</ul>
</li>
<li><a class="reference" href="#extensions" id="id45" name="id45">extensions</a></li>
<li><a class="reference" href="#aknowledgements" id="id46" name="id46">Aknowledgements</a></li>
<li><a class="reference" href="#extensions" id="id46" name="id46">extensions</a></li>
<li><a class="reference" href="#aknowledgements" id="id47" name="id47">Aknowledgements</a></li>
</ul>
</div>
<div class="section" id="introduction">
@ -103,6 +103,7 @@ peers in a separate fast-resume file.</li>
<li>Supports the extension protocol <a class="reference" href="http://nolar.com/azureus/extended.htm">described by Nolar</a>. See <a class="reference" href="#extensions">extensions</a>.</li>
<li>Supports files &gt; 2 gigabytes (currently only on windows).</li>
<li>Supports the <tt class="literal"><span class="pre">no_peer_id=1</span></tt> extension that will ease the load off trackers.</li>
<li>Supports the <a class="reference" href="udp_tracker_protocol.html">udp-tracker protocol</a>.</li>
</ul>
</blockquote>
<p>Functions that are yet to be implemented:</p>
@ -223,7 +224,7 @@ The main thread will be idle as long it doesn't have any torrents to participate
You add torrents through the <tt class="literal"><span class="pre">add_torrent()</span></tt>-function where you give an
object representing the information found in the torrent file and the path where you
want to save the files. The <tt class="literal"><span class="pre">save_path</span></tt> will be prepended to the directory-
structure in the torrent-file. <tt class="literal"><span class="pre">add_torrent</span></tt> will throw <tt class="literal"><span class="pre">duplicate_torrent</span></tt> exception
structure in the torrent-file. <tt class="literal"><span class="pre">add_torrent</span></tt> will throw <a class="reference" href="#duplicate-torrent">duplicate_torrent</a> exception
if the torrent already exists in the session.</p>
<p>The optional last parameter, <tt class="literal"><span class="pre">resume_data</span></tt> can be given if up to date fast-resume data
is available. The fast-resume data can be acquired from a running torrent by calling
@ -232,7 +233,7 @@ is available. The fast-resume data can be acquired from a running torrent by cal
the tracker that we've stopped participating in the swarm.</p>
<p>If the torrent you are trying to add already exists in the session (is either queued
for checking, being checked or downloading) <tt class="literal"><span class="pre">add_torrent()</span></tt> will throw
<tt class="literal"><span class="pre">duplicate_torrent</span></tt> which derives from <tt class="literal"><span class="pre">std::exception</span></tt>.</p>
<a class="reference" href="#duplicate-torrent">duplicate_torrent</a> which derives from <tt class="literal"><span class="pre">std::exception</span></tt>.</p>
<p>The difference between the two constructors is that one of them takes a fingerprint
as argument. If this is ommited, the client will get a default fingerprint stating
the version of libtorrent. The fingerprint is a short string that will be used in
@ -246,7 +247,6 @@ If some trackers are down, they will timout. All this before the destructor of s
returns. So, it's adviced that any kind of interface (such as windows) are closed before
destructing the sessoin object. Because it can take a few second for it to finish. The
timeout can be set with <tt class="literal"><span class="pre">set_http_settings()</span></tt>.</p>
<p>How to parse a torrent file and create a <tt class="literal"><span class="pre">torrent_info</span></tt> object is described below.</p>
<p>The <a class="reference" href="#torrent-handle">torrent_handle</a> returned by <tt class="literal"><span class="pre">add_torrent</span></tt> can be used to retrieve information
about the torrent's progress, its peers etc. It is also used to abort a torrent.</p>
<p>The constructor takes a listen port as argument, if the given port is busy it will
@ -486,6 +486,7 @@ struct torrent_handle
boost::filsystem::path save_path() const;
void set_max_uploads(int max_uploads);
void set_max_connections(int max_connections);
sha1_hash info_hash() const;
@ -517,6 +518,10 @@ as a standard client.</p>
<p><tt class="literal"><span class="pre">info_hash()</span></tt> returns the info hash for the torrent.</p>
<p><tt class="literal"><span class="pre">set_max_uploads()</span></tt> sets the maximum number of peers that's unchoked at the same time on this
torrent. If you set this to -1, there will be no limit.</p>
<p><tt class="literal"><span class="pre">set_max_connections()</span></tt> sets the maximum number of connection this torrent will open. If all
connections are used up, incoming connections may be refused or poor connections may be closed.
This must be at least 2. The default is unlimited number of connections. If -1 is given to the
function, it means unlimited.</p>
<p><tt class="literal"><span class="pre">write_resume_data()</span></tt> generates fast-resume data and returns it as an entry. This entry
is suitable for being bencoded. For more information about how fast-resume works, see <a class="reference" href="#fast-resume">fast resume</a>.
It may throw <a class="reference" href="#invalid-handle">invalid_handle</a> if the torrent handle is invalid.</p>
@ -752,7 +757,7 @@ the total number of bytes in this block.</p>
</div>
<div class="section" id="get-torrent-info">
<h2><a name="get-torrent-info">get_torrent_info()</a></h2>
<p>Returns a const reference to the <tt class="literal"><span class="pre">torrent_info</span></tt> object associated with this torrent.
<p>Returns a const reference to the <a class="reference" href="#torrent-info">torrent_info</a> object associated with this torrent.
This reference is valid as long as the <a class="reference" href="#torrent-handle">torrent_handle</a> is valid, no longer. If the
<a class="reference" href="#torrent-handle">torrent_handle</a> is invalid, <a class="reference" href="#invalid-handle">invalid_handle</a> exception will be thrown.</p>
</div>
@ -1440,8 +1445,8 @@ with future versions of bittorrent.</p>
</div>
<div class="section" id="aknowledgements">
<h1><a name="aknowledgements">Aknowledgements</a></h1>
<p>Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003</p>
<p>Contributions by Magnus Jonsson</p>
<p>Written by Arvid Norberg. Copyright (c) 2003</p>
<p>Contributions by Magnus Jonsson and Daniel Wallin</p>
<p>Thanks to Reimond Retz for bugfixes, suggestions and testing</p>
<p>Project is hosted by sourceforge.</p>
<p><a class="reference" href="http://sourceforge.net"><img alt="sf_logo" src="http://sourceforge.net/sflogo.php?group_id=7994" /></a></p>

View File

@ -40,10 +40,13 @@ The current state includes the following features:
* Supports the extension protocol `described by Nolar`__. See extensions_.
* Supports files > 2 gigabytes (currently only on windows).
* Supports the ``no_peer_id=1`` extension that will ease the load off trackers.
* Supports the `udp-tracker protocol`__.
__ http://home.elp.rr.com/tur/multitracker-spec.txt
.. _Azureus: http://azureus.sourceforge.net
__ http://nolar.com/azureus/extended.htm
__ udp_tracker_protocol.html
Functions that are yet to be implemented:
@ -171,7 +174,7 @@ The main thread will be idle as long it doesn't have any torrents to participate
You add torrents through the ``add_torrent()``-function where you give an
object representing the information found in the torrent file and the path where you
want to save the files. The ``save_path`` will be prepended to the directory-
structure in the torrent-file. ``add_torrent`` will throw ``duplicate_torrent`` exception
structure in the torrent-file. ``add_torrent`` will throw duplicate_torrent_ exception
if the torrent already exists in the session.
The optional last parameter, ``resume_data`` can be given if up to date fast-resume data
@ -183,7 +186,7 @@ the tracker that we've stopped participating in the swarm.
If the torrent you are trying to add already exists in the session (is either queued
for checking, being checked or downloading) ``add_torrent()`` will throw
``duplicate_torrent`` which derives from ``std::exception``.
duplicate_torrent_ which derives from ``std::exception``.
The difference between the two constructors is that one of them takes a fingerprint
as argument. If this is ommited, the client will get a default fingerprint stating
@ -201,8 +204,6 @@ returns. So, it's adviced that any kind of interface (such as windows) are close
destructing the sessoin object. Because it can take a few second for it to finish. The
timeout can be set with ``set_http_settings()``.
How to parse a torrent file and create a ``torrent_info`` object is described below.
The torrent_handle_ returned by ``add_torrent`` can be used to retrieve information
about the torrent's progress, its peers etc. It is also used to abort a torrent.
@ -487,6 +488,7 @@ Its declaration looks like this::
boost::filsystem::path save_path() const;
void set_max_uploads(int max_uploads);
void set_max_connections(int max_connections);
sha1_hash info_hash() const;
@ -526,6 +528,11 @@ as a standard client.
``set_max_uploads()`` sets the maximum number of peers that's unchoked at the same time on this
torrent. If you set this to -1, there will be no limit.
``set_max_connections()`` sets the maximum number of connection this torrent will open. If all
connections are used up, incoming connections may be refused or poor connections may be closed.
This must be at least 2. The default is unlimited number of connections. If -1 is given to the
function, it means unlimited.
``write_resume_data()`` generates fast-resume data and returns it as an entry. This entry
is suitable for being bencoded. For more information about how fast-resume works, see `fast resume`_.
It may throw invalid_handle_ if the torrent handle is invalid.
@ -772,7 +779,7 @@ the total number of bytes in this block.
get_torrent_info()
------------------
Returns a const reference to the ``torrent_info`` object associated with this torrent.
Returns a const reference to the torrent_info_ object associated with this torrent.
This reference is valid as long as the torrent_handle_ is valid, no longer. If the
torrent_handle_ is invalid, invalid_handle_ exception will be thrown.
@ -1514,9 +1521,9 @@ with future versions of bittorrent.
Aknowledgements
===============
Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003
Written by Arvid Norberg. Copyright (c) 2003
Contributions by Magnus Jonsson
Contributions by Magnus Jonsson and Daniel Wallin
Thanks to Reimond Retz for bugfixes, suggestions and testing

View File

@ -0,0 +1,381 @@
<?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.3.1: http://docutils.sourceforge.net/" />
<title>Bittorrent udp-tracker protocol extension</title>
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div class="document" id="bittorrent-udp-tracker-protocol-extension">
<h1 class="title">Bittorrent udp-tracker protocol extension</h1>
<p>A tracker with the protocol &quot;udp://&quot; in its URI
is supposed to be contacted using this protocol.</p>
<p>This protocol is supported by
<a class="reference" 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" 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 class="section" id="connecting">
<h1><a name="connecting">connecting</a></h1>
<p>Client sends packet:</p>
<table border class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>description</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>int64_t</td>
<td>connection_id</td>
<td>Not used, ignored by tracker.</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 class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>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" 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><a name="announcing">announcing</a></h1>
<p>Client sends packet:</p>
<table border class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>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.</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="literal"><span class="pre">sender</span></tt> of
this udp packet.</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>
</tbody>
</table>
<p>Server replies with packet:</p>
<table border class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>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" href="#errors">errors</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>
</tbody>
</table>
<p>The rest of the server reply is a variable number of the following structure:</p>
<table border class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>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 peers listen port.</td>
</tr>
</tbody>
</table>
</div>
<div class="section" id="scraping">
<h1><a name="scraping">scraping</a></h1>
<p>Client sends packet:</p>
<table border class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>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.</td>
</tr>
<tr><td>int32_t</td>
<td>transaction_id</td>
<td>Randomized by client.</td>
</tr>
<tr><td>int8[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 class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>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" 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 a variable number of the following structures:</p>
<table border class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>description</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>int8_t[20]</td>
<td>info_hash</td>
<td>The info hash of this info.</td>
</tr>
<tr><td>int32_t</td>
<td>complete</td>
<td>The total number of completed
downloads.</td>
</tr>
<tr><td>int32_t</td>
<td>downloaded</td>
<td>The current number of connected seeds.</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><a name="errors">errors</a></h1>
<p>In case of a tracker error, the server replies with this packet:</p>
<table border class="table">
<colgroup>
<col width="18%" />
<col width="28%" />
<col width="54%" />
</colgroup>
<thead valign="bottom">
<tr><th>size</th>
<th>name</th>
<th>description</th>
</tr>
</thead>
<tbody valign="top">
<tr><td>int32_t</td>
<td>action</td>
<td>The action, in this case 3, for error.</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[]</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><a name="actions">actions</a></h1>
<p>The action fields has the followinf 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="credits">
<h1><a name="credits">credits</a></h1>
<p>Protocol designed by Olaf van der Spek</p>
</div>
</div>
</body>
</html>

218
docs/udp_tracker_protocol.rst Executable file
View File

@ -0,0 +1,218 @@
=========================================
Bittorrent udp-tracker protocol extension
=========================================
A tracker with the protocol "udp://" in its URI
is supposed to be contacted using this protocol.
This protocol is supported by
xbt-tracker_.
.. _xbt-tracker: http://xbtt.sourceforge.net
For additional information and descritptions of
the terminology used in this document, see
the `protocol specification`__
__ http://wiki.theory.org/index.php/BitTorrentSpecification
All values are sent in network byte order (big endian). The sizes
are specified with ANSI-C standard types.
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.
connecting
----------
Client sends packet:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int64_t | connection_id | Not used, ignored by tracker. |
+-------------+---------------------+----------------------------------------+
| int32_t | action | 0 for a connection request |
+-------------+---------------------+----------------------------------------+
| int32_t | transaction_id | Randomized by client. |
+-------------+---------------------+----------------------------------------+
Server replies with packet:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int32_t | action | Describes the type of packet, in this |
| | | case it should be 0, for connect. |
| | | If 3 (for error) see errors_. |
+-------------+---------------------+----------------------------------------+
| int32_t | transaction_id | Must match the transaction_id sent |
| | | from the client. |
+-------------+---------------------+----------------------------------------+
| int64_t | connection_id | 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. |
+-------------+---------------------+----------------------------------------+
announcing
----------
Client sends packet:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int64_t | connection_id | The connection id acquired from |
| | | establishing the connection. |
+-------------+---------------------+----------------------------------------+
| int32_t | action | Action. in this case, 1 for announce. |
+-------------+---------------------+----------------------------------------+
| int32_t | transaction_id | Randomized by client. |
+-------------+---------------------+----------------------------------------+
| int8_t[20] | info_hash | The info-hash of the torrent you want |
| | | announce yourself in. |
+-------------+---------------------+----------------------------------------+
| int8_t[20] | peer_id | Your peer id. |
+-------------+---------------------+----------------------------------------+
| int64_t | downloaded | The number of byte you've downloaded |
| | | in this session. |
+-------------+---------------------+----------------------------------------+
| int64_t | left | The number of bytes you have left to |
| | | download until you're finished. |
+-------------+---------------------+----------------------------------------+
| int64_t | uploaded | The number of bytes you have uploaded |
| | | in this session. |
+-------------+---------------------+----------------------------------------+
| int32_t | event | The event, one of |
| | | |
| | | * none = 0 |
| | | * completed = 1 |
| | | * started = 2 |
| | | * stopped = 3 |
+-------------+---------------------+----------------------------------------+
| uint32_t | ip | Your ip address. Set to 0 if you want |
| | | the tracker to use the ``sender`` of |
| | | this udp packet. |
+-------------+---------------------+----------------------------------------+
| int32_t | num_want | The maximum number of peers you want |
| | | in the reply. Use -1 for default. |
+-------------+---------------------+----------------------------------------+
| uint16_t | port | The port you're listening on. |
+-------------+---------------------+----------------------------------------+
Server replies with packet:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int32_t | action | The action this is a reply to. Should |
| | | in this case be 1 for announce. |
| | | If 3 (for error) see errors_. |
+-------------+---------------------+----------------------------------------+
| int32_t | transaction_id | Must match the transaction_id sent |
| | | in the announce request. |
+-------------+---------------------+----------------------------------------+
| int32_t | interval | the number of seconds you should wait |
| | | until reannouncing yourself. |
+-------------+---------------------+----------------------------------------+
The rest of the server reply is a variable number of the following structure:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int32_t | ip | The ip of a peer in the swarm. |
+-------------+---------------------+----------------------------------------+
| uint16_t | port | The peers listen port. |
+-------------+---------------------+----------------------------------------+
scraping
--------
Client sends packet:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int64_t | connection_id | The connection id retreived from the |
| | | establishing of the connection. |
+-------------+---------------------+----------------------------------------+
| int32_t | action | The action, in this case, 2 for |
| | | scrape. |
+-------------+---------------------+----------------------------------------+
| int32_t | transaction_id | Randomized by client. |
+-------------+---------------------+----------------------------------------+
| int8[20] | info_hash | The info hash that is to be scraped. |
+-------------+---------------------+----------------------------------------+
Server replies with packet:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int32_t | action | The action, should in this case be |
| | | 2 for scrape. |
| | | If 3 (for error) see errors_. |
+-------------+---------------------+----------------------------------------+
| int32_t | transaction_id | Must match the sent transaction id. |
+-------------+---------------------+----------------------------------------+
The rest of the packet contains a variable number of the following structures:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int8_t[20] | info_hash | The info hash of this info. |
+-------------+---------------------+----------------------------------------+
| int32_t | complete | The total number of completed |
| | | downloads. |
+-------------+---------------------+----------------------------------------+
| int32_t | downloaded | The current number of connected seeds. |
+-------------+---------------------+----------------------------------------+
| int32_t | incomplete | The current number of connected |
| | | leechers. |
+-------------+---------------------+----------------------------------------+
errors
------
In case of a tracker error, the server replies with this packet:
+-------------+---------------------+----------------------------------------+
| size | name | description |
+=============+=====================+========================================+
| int32_t | action | The action, in this case 3, for error. |
+-------------+---------------------+----------------------------------------+
| int32_t | transaction_id | Must match the transaction_id sent |
| | | from the client. |
+-------------+---------------------+----------------------------------------+
| int8[] | error_string | The rest of the packet is a string |
| | | describing the error. |
+-------------+---------------------+----------------------------------------+
actions
-------
The action fields has the followinf encoding:
* connect = 0
* announce = 1
* scrape = 2
* error = 3 (only in server replies)
credits
-------
Protocol designed by Olaf van der Spek

View File

@ -68,96 +68,101 @@ namespace libtorrent
{
struct session_impl;
template <class T> struct type {};
// reads an integer from a byte stream
// in big endian byte order and converts
// it to native endianess
template <class InIt>
unsigned int read_uint(InIt& start)
template <class T, class InIt>
inline T read_impl(InIt& start, type<T>)
{
unsigned int val = 0;
val |= static_cast<unsigned char>(*start) << 24; ++start;
val |= static_cast<unsigned char>(*start) << 16; ++start;
val |= static_cast<unsigned char>(*start) << 8; ++start;
val |= static_cast<unsigned char>(*start); ++start;
return val;
}
template <class InIt>
inline int read_int(InIt& start)
{
return static_cast<int>(read_uint(start));
}
template <class InIt>
inline unsigned char read_uchar(InIt& start)
{
unsigned char ret = static_cast<unsigned char>(*start);
++start;
return ret;
}
template <class InIt>
inline unsigned short read_ushort(InIt& start)
{
unsigned short val = 0;
val |= static_cast<unsigned char>(*start) << 8; ++start;
val |= static_cast<unsigned char>(*start); ++start;
return val;
}
// reads an integer to a byte stream
// and converts it from native endianess
template <class OutIt>
void write_uint(unsigned int val, OutIt& start)
{
*start = static_cast<unsigned char>((val >> 24) & 0xff); ++start;
*start = static_cast<unsigned char>((val >> 16) & 0xff); ++start;
*start = static_cast<unsigned char>((val >> 8) & 0xff); ++start;
*start = static_cast<unsigned char>((val) & 0xff); ++start;
}
template <class OutIt>
inline void write_int(int val, OutIt& start)
{
write_uint(static_cast<unsigned int>(val), start);
}
template <class OutIt>
void write_ushort(unsigned short val, OutIt& start)
{
*start = static_cast<unsigned char>((val >> 8) & 0xff); ++start;
*start = static_cast<unsigned char>((val) & 0xff); ++start;
}
template <class OutIt>
inline void write_uchar(unsigned char val, OutIt& start)
{
*start = static_cast<char>(val);
++start;
}
template <class OutIt>
inline void write_int64(boost::int64_t val, OutIt& start)
{
for (int i = 7; i <= 0; --i)
T ret = 0;
for (int i = 0; i < sizeof(T); ++i)
{
*start = static_cast<unsigned char>((val >> (i*8)) & 0xff);
++start;
}
}
template <class InIt>
inline boost::int64_t read_int64(InIt& start)
{
boost::int64_t ret = 0;
for (int i = 7; i <= 0; --i)
{
ret |= static_cast<unsigned char>(*start) << (i*8);
ret <<= 8;
ret |= static_cast<unsigned char>(*start);
++start;
}
return ret;
}
template <class T, class OutIt>
inline void write_impl(T val, OutIt& start)
{
for (int i = sizeof(T)-1; i >= 0; --i)
{
*start = static_cast<unsigned char>((val >> (i * 8)) & 0xff);
++start;
}
}
// -- adaptors
template <class InIt>
boost::int64_t read_int64(InIt& start)
{ return read_impl(start, type<boost::int64_t>()); }
template <class InIt>
boost::uint64_t read_uint64(InIt& start)
{ return read_impl(start, type<boost::uint64_t>()); }
template <class InIt>
boost::uint32_t read_uint32(InIt& start)
{ return read_impl(start, type<boost::uint32_t>()); }
template <class InIt>
boost::int32_t read_int32(InIt& start)
{ return read_impl(start, type<boost::int32_t>()); }
template <class InIt>
boost::int16_t read_int16(InIt& start)
{ return read_impl(start, type<boost::int16_t>()); }
template <class InIt>
boost::uint16_t read_uint16(InIt& start)
{ return read_impl(start, type<boost::uint16_t>()); }
template <class InIt>
boost::int8_t read_int8(InIt& start)
{ return read_impl(start, type<boost::int8_t>()); }
template <class InIt>
boost::uint8_t read_uint8(InIt& start)
{ return read_impl(start, type<boost::uint8_t>()); }
template <class OutIt>
void write_uint64(boost::uint64_t val, OutIt& start)
{ write_impl(val, start); }
template <class OutIt>
void write_int64(boost::int64_t val, OutIt& start)
{ write_impl(val, start); }
template <class OutIt>
void write_uint32(boost::uint32_t val, OutIt& start)
{ write_impl(val, start); }
template <class OutIt>
void write_int32(boost::int32_t val, OutIt& start)
{ write_impl(val, start); }
template <class OutIt>
void write_uint16(boost::uint16_t val, OutIt& start)
{ write_impl(val, start); }
template <class OutIt>
void write_int16(boost::int16_t val, OutIt& start)
{ write_impl(val, start); }
template <class OutIt>
void write_uint8(boost::uint8_t val, OutIt& start)
{ write_impl(val, start); }
template <class OutIt>
void write_int8(boost::int8_t val, OutIt& start)
{ write_impl(val, start); }
}
struct protocol_error: std::runtime_error

View File

@ -174,7 +174,7 @@ namespace libtorrent
// when this torrent got a response from its tracker request
virtual void tracker_response(std::vector<peer_entry>& e, int interval);
virtual void tracker_request_timed_out();
virtual void tracker_request_error(int response_code, const char* str);
virtual void tracker_request_error(int response_code, const std::string& str);
// generates a request string for sending
// to the tracker

View File

@ -49,11 +49,17 @@ namespace libtorrent {
void alert_manager::post_alert(const alert& alert_)
{
// TODO: have an internal buffer limit
boost::mutex::scoped_lock lock(m_mutex);
if (m_severity <= alert_.severity())
m_alerts.push(alert_.clone().release());
if (m_severity > alert_.severity()) return;
// the internal limit is 100 alerts
if (m_alerts.size() == 100)
{
alert* result = m_alerts.front();
m_alerts.pop();
delete result;
}
m_alerts.push(alert_.clone().release());
}
std::auto_ptr<alert> alert_manager::get()

View File

@ -285,8 +285,8 @@ namespace libtorrent
const char* ptr = &m_recv_buffer[1];
peer_request r;
r.piece = detail::read_int(ptr);
r.start = detail::read_int(ptr);
r.piece = detail::read_int32(ptr);
r.start = detail::read_int32(ptr);
r.length = m_packet_size - 9;
// is any of the piece message header data invalid?
@ -406,7 +406,7 @@ namespace libtorrent
if (m_recv_pos < m_packet_size) return;
const char* ptr = &m_recv_buffer[1];
int index = detail::read_int(ptr);
int index = detail::read_int32(ptr);
// if we got an invalid message, abort
if (index >= m_have_piece.size() || index < 0)
throw protocol_error("have message with higher index than the number of pieces");
@ -514,9 +514,9 @@ namespace libtorrent
peer_request r;
const char* ptr = &m_recv_buffer[1];
r.piece = detail::read_int(ptr);
r.start = detail::read_int(ptr);
r.length = detail::read_int(ptr);
r.piece = detail::read_int32(ptr);
r.start = detail::read_int32(ptr);
r.length = detail::read_int32(ptr);
// make sure this request
// is legal and taht the peer
@ -602,8 +602,8 @@ namespace libtorrent
const char* ptr = &m_recv_buffer[1];
peer_request p;
p.piece = detail::read_int(ptr);
p.start = detail::read_int(ptr);
p.piece = detail::read_int32(ptr);
p.start = detail::read_int32(ptr);
p.length = m_packet_size - 9;
if (!verify_piece(p))
@ -724,9 +724,9 @@ namespace libtorrent
peer_request r;
const char* ptr = &m_recv_buffer[1];
r.piece = detail::read_int(ptr);
r.start = detail::read_int(ptr);
r.length = detail::read_int(ptr);
r.piece = detail::read_int32(ptr);
r.start = detail::read_int32(ptr);
r.length = detail::read_int32(ptr);
std::deque<peer_request>::iterator i
= std::find(m_requests.begin(), m_requests.end(), r);
@ -812,7 +812,7 @@ namespace libtorrent
const char* ptr = &m_recv_buffer[1];
int extended_id = detail::read_int(ptr);
int extended_id = detail::read_int32(ptr);
switch (extended_id)
{
@ -929,11 +929,11 @@ namespace libtorrent
char* ptr = &m_send_buffer[start_offset];
// index
detail::write_int(block.piece_index, ptr);
detail::write_int32(block.piece_index, ptr);
// begin
detail::write_int(block_offset, ptr);
detail::write_int32(block_offset, ptr);
// length
detail::write_int(block_size, ptr);
detail::write_int32(block_size, ptr);
#ifndef NDEBUG
(*m_logger) << " ==> CANCEL [ piece: " << block.piece_index << " | s: " << block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n";
@ -968,13 +968,13 @@ namespace libtorrent
char* ptr = &m_send_buffer[start_offset+5];
// index
detail::write_int(block.piece_index, ptr);
detail::write_int32(block.piece_index, ptr);
// begin
detail::write_int(block_offset, ptr);
detail::write_int32(block_offset, ptr);
// length
detail::write_int(block_size, ptr);
detail::write_int32(block_size, ptr);
#ifndef NDEBUG
(*m_logger) << " ==> REQUEST [ "
@ -1005,9 +1005,9 @@ namespace libtorrent
bencode(std::back_inserter(message), e);
std::back_insert_iterator<std::vector<char> > ptr(m_send_buffer);
detail::write_uint(1 + 4 + message.size(), ptr);
detail::write_uchar(msg_extended, ptr);
detail::write_int(m_extension_messages[extended_chat_message], ptr);
detail::write_uint32(1 + 4 + message.size(), ptr);
detail::write_uint8(msg_extended, ptr);
detail::write_int32(m_extension_messages[extended_chat_message], ptr);
std::copy(message.begin(), message.end(), ptr);
send_buffer_updated();
}
@ -1021,7 +1021,7 @@ namespace libtorrent
const int old_size = m_send_buffer.size();
m_send_buffer.resize(old_size + packet_size);
char* ptr = &m_send_buffer[old_size];
detail::write_int(packet_size - 4, ptr);
detail::write_int32(packet_size - 4, ptr);
m_send_buffer[old_size+4] = msg_bitfield;
std::fill(m_send_buffer.begin()+old_size+5, m_send_buffer.end(), 0);
for (std::size_t i = 0; i < m_have_piece.size(); ++i)
@ -1056,7 +1056,7 @@ namespace libtorrent
// write the length of the message
char* ptr = &m_send_buffer[msg_size_pos];
detail::write_int(m_send_buffer.size() - msg_size_pos - 4, ptr);
detail::write_int32(m_send_buffer.size() - msg_size_pos - 4, ptr);
send_buffer_updated();
}
@ -1120,7 +1120,7 @@ namespace libtorrent
const int packet_size = 9;
char msg[packet_size] = {0,0,0,5,msg_have};
char* ptr = msg+5;
detail::write_int(index, ptr);
detail::write_int32(index, ptr);
m_send_buffer.insert(m_send_buffer.end(), msg, msg + packet_size);
#ifndef NDEBUG
(*m_logger) << " ==> HAVE [ piece: " << index << " ]\n";
@ -1406,7 +1406,7 @@ namespace libtorrent
// convert from big endian to native byte order
const char* ptr = &m_recv_buffer[0];
m_packet_size = detail::read_int(ptr);
m_packet_size = detail::read_int32(ptr);
// don't accept packets larger than 1 MB
if (m_packet_size > 1024*1024 || m_packet_size < 0)
{
@ -1492,10 +1492,10 @@ namespace libtorrent
const int packet_size = 4 + 5 + 4 + r.length;
m_send_buffer.resize(send_buffer_offset + packet_size);
char* ptr = &m_send_buffer[send_buffer_offset];
detail::write_int(packet_size-4, ptr);
detail::write_int32(packet_size-4, ptr);
*ptr = msg_piece; ++ptr;
detail::write_int(r.piece, ptr);
detail::write_int(r.start, ptr);
detail::write_int32(r.piece, ptr);
detail::write_int32(r.start, ptr);
m_torrent->filesystem().read(
&m_send_buffer[send_buffer_offset+13]

View File

@ -253,15 +253,17 @@ namespace libtorrent
#ifndef NDEBUG
std::stringstream s;
s << "interval: " << m_duration << "\n";
s << "peers:\n";
s << "TRACKER RESPONSE:\n"
"interval: " << m_duration << "\n"
"peers:\n";
for (std::vector<peer_entry>::const_iterator i = peer_list.begin();
i != peer_list.end();
++i)
{
s << " " << std::setfill(' ') << std::setw(16) << i->ip
<< " " << std::setw(5) << std::dec << i->port << " "
<< i->id << " " << identify_client(i->id) << "\n";
<< " " << std::setw(5) << std::dec << i->port << " ";
if (!i->id.is_all_zeros()) s << " " << i->id << " " << identify_client(i->id);
s << "\n";
}
debug_log(s.str());
#endif
@ -746,7 +748,7 @@ namespace libtorrent
// with some codes, we should just consider
// the tracker as a failure and not retry
// it anymore
void torrent::tracker_request_error(int response_code, const char* str)
void torrent::tracker_request_error(int response_code, const std::string& str)
{
#ifndef NDEBUG
debug_log(std::string("*** tracker error: ") + str);

View File

@ -94,6 +94,7 @@ namespace libtorrent
void torrent_handle::set_max_connections(int max_connections)
{
assert(max_connections >= 2);
if (m_ses == 0) throw invalid_handle();
{