*** empty log message ***

This commit is contained in:
Arvid Norberg 2004-01-04 23:51:54 +00:00
parent 1baef63b99
commit e2baa0a646
12 changed files with 682 additions and 515 deletions

View File

@ -24,52 +24,52 @@
<div class="contents topic" id="contents"> <div class="contents topic" id="contents">
<p class="topic-title"><a name="contents">Contents</a></p> <p class="topic-title"><a name="contents">Contents</a></p>
<ul class="simple"> <ul class="simple">
<li><a class="reference" href="#introduction" id="id7" name="id7">introduction</a></li> <li><a class="reference" href="#introduction" id="id8" name="id8">introduction</a></li>
<li><a class="reference" href="#building" id="id8" name="id8">building</a></li> <li><a class="reference" href="#building" id="id9" name="id9">building</a></li>
<li><a class="reference" href="#using" id="id9" name="id9">using</a><ul> <li><a class="reference" href="#using" id="id10" name="id10">using</a><ul>
<li><a class="reference" href="#session" id="id10" name="id10">session</a></li> <li><a class="reference" href="#session" id="id11" name="id11">session</a></li>
<li><a class="reference" href="#parsing-torrent-files" id="id11" name="id11">parsing torrent files</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="id12" name="id12">entry</a></li> <li><a class="reference" href="#entry" id="id13" name="id13">entry</a></li>
<li><a class="reference" href="#torrent-info" id="id13" name="id13">torrent_info</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="id14" name="id14">torrent_handle</a><ul> <li><a class="reference" href="#torrent-handle" id="id15" name="id15">torrent_handle</a><ul>
<li><a class="reference" href="#status" id="id15" name="id15">status()</a></li> <li><a class="reference" href="#status" id="id16" name="id16">status()</a></li>
<li><a class="reference" href="#get-download-queue" id="id16" name="id16">get_download_queue()</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="id17" name="id17">get_peer_info()</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="id18" name="id18">get_torrent_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="id19" name="id19">is_valid()</a></li> <li><a class="reference" href="#is-valid" id="id20" name="id20">is_valid()</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#address" id="id20" name="id20">address</a></li> <li><a class="reference" href="#address" id="id21" name="id21">address</a></li>
<li><a class="reference" href="#http-settings" id="id21" name="id21">http_settings</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="id22" name="id22">big_number</a></li> <li><a class="reference" href="#big-number" id="id23" name="id23">big_number</a></li>
<li><a class="reference" href="#hasher" id="id23" name="id23">hasher</a></li> <li><a class="reference" href="#hasher" id="id24" name="id24">hasher</a></li>
<li><a class="reference" href="#fingerprint" id="id24" name="id24">fingerprint</a></li> <li><a class="reference" href="#fingerprint" id="id25" name="id25">fingerprint</a></li>
<li><a class="reference" href="#alert" id="id25" name="id25">alert</a></li> <li><a class="reference" href="#alert" id="id26" name="id26">alert</a></li>
<li><a class="reference" href="#exceptions" id="id26" name="id26">exceptions</a><ul> <li><a class="reference" href="#exceptions" id="id27" name="id27">exceptions</a><ul>
<li><a class="reference" href="#invalid-handle" id="id27" name="id27">invalid_handle</a></li> <li><a class="reference" href="#invalid-handle" id="id28" name="id28">invalid_handle</a></li>
<li><a class="reference" href="#duplicate-torrent" id="id28" name="id28">duplicate_torrent</a></li> <li><a class="reference" href="#duplicate-torrent" id="id29" name="id29">duplicate_torrent</a></li>
<li><a class="reference" href="#invalid-encoding" id="id29" name="id29">invalid_encoding</a></li> <li><a class="reference" href="#invalid-encoding" id="id30" name="id30">invalid_encoding</a></li>
<li><a class="reference" href="#type-error" id="id30" name="id30">type_error</a></li> <li><a class="reference" href="#type-error" id="id31" name="id31">type_error</a></li>
<li><a class="reference" href="#invalid-torrent-file" id="id31" name="id31">invalid_torrent_file</a></li> <li><a class="reference" href="#invalid-torrent-file" id="id32" name="id32">invalid_torrent_file</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#example-usage" id="id32" name="id32">example usage</a><ul> <li><a class="reference" href="#example-usage" id="id33" name="id33">example usage</a><ul>
<li><a class="reference" href="#dump-torrent" id="id33" name="id33">dump_torrent</a></li> <li><a class="reference" href="#dump-torrent" id="id34" name="id34">dump_torrent</a></li>
<li><a class="reference" href="#simple-client" id="id34" name="id34">simple client</a></li> <li><a class="reference" href="#simple-client" id="id35" name="id35">simple client</a></li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#fast-resume" id="id35" name="id35">fast resume</a><ul> <li><a class="reference" href="#fast-resume" id="id36" name="id36">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id36" name="id36">file format</a></li> <li><a class="reference" href="#file-format" id="id37" name="id37">file format</a></li>
</ul> </ul>
</li> </li>
</ul> </ul>
</li> </li>
<li><a class="reference" href="#feedback" id="id37" name="id37">Feedback</a></li> <li><a class="reference" href="#feedback" id="id38" name="id38">Feedback</a></li>
<li><a class="reference" href="#aknowledgements" id="id38" name="id38">Aknowledgements</a></li> <li><a class="reference" href="#aknowledgements" id="id39" name="id39">Aknowledgements</a></li>
</ul> </ul>
</div> </div>
<div class="section" id="introduction"> <div class="section" id="introduction">
<h1><a class="toc-backref" href="#id7" name="introduction">introduction</a></h1> <h1><a class="toc-backref" href="#id8" name="introduction">introduction</a></h1>
<p>libtorrent is a C++ library that aims to be a good alternative to all the <p>libtorrent is a C++ library that aims to be a good alternative to all the
<a class="reference" href="links.html">other bittorrent implementations</a> around. It is a <a class="reference" href="links.html">other bittorrent implementations</a> around. It is a
library and not a full featured client, although it comes with a working library and not a full featured client, although it comes with a working
@ -105,7 +105,6 @@ of a resumed torrent. Saves the storage state in a separate fast-resume file.</l
<p>Functions that are yet to be implemented:</p> <p>Functions that are yet to be implemented:</p>
<blockquote> <blockquote>
<ul class="simple"> <ul class="simple">
<li>choke/unchoke policy for seed-mode</li>
<li>number of connections limit</li> <li>number of connections limit</li>
<li>better handling of peers that send bad data</li> <li>better handling of peers that send bad data</li>
<li>ip-filters</li> <li>ip-filters</li>
@ -113,7 +112,7 @@ of a resumed torrent. Saves the storage state in a separate fast-resume file.</l
</ul> </ul>
</blockquote> </blockquote>
<p>libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread, <p>libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread,
boost.filesystem boost.date_time and various other boost libraries and zlib.</p> boost.filesystem, boost.date_time and various other boost libraries as well as zlib.</p>
<p>libtorrent has been successfully compiled and tested on:</p> <p>libtorrent has been successfully compiled and tested on:</p>
<blockquote> <blockquote>
<ul class="simple"> <ul class="simple">
@ -130,7 +129,7 @@ boost.filesystem boost.date_time and various other boost libraries and zlib.</p>
</blockquote> </blockquote>
</div> </div>
<div class="section" id="building"> <div class="section" id="building">
<h1><a class="toc-backref" href="#id8" name="building">building</a></h1> <h1><a class="toc-backref" href="#id9" name="building">building</a></h1>
<p>To build libtorrent you need <a class="reference" href="http://www.boost.org">boost</a> and bjam installed. <p>To build libtorrent you need <a class="reference" href="http://www.boost.org">boost</a> and bjam installed.
Then you can use <tt class="literal"><span class="pre">bjam</span></tt> to build libtorrent.</p> Then you can use <tt class="literal"><span class="pre">bjam</span></tt> to build libtorrent.</p>
<p>To make bjam work, you need to set the environment variable <tt class="literal"><span class="pre">BOOST_ROOT</span></tt> to the <p>To make bjam work, you need to set the environment variable <tt class="literal"><span class="pre">BOOST_ROOT</span></tt> to the
@ -162,11 +161,11 @@ loop scope&quot; and &quot;treat wchar_t as built-in type&quot; to Yes.</p>
<p>TODO: more detailed build instructions.</p> <p>TODO: more detailed build instructions.</p>
</div> </div>
<div class="section" id="using"> <div class="section" id="using">
<h1><a class="toc-backref" href="#id9" name="using">using</a></h1> <h1><a class="toc-backref" href="#id10" name="using">using</a></h1>
<p>The interface of libtorrent consists of a few classes. The main class is <p>The interface of libtorrent consists of a few classes. The main class is
the <tt class="literal"><span class="pre">session</span></tt>, it contains the main loop that serves all torrents.</p> the <tt class="literal"><span class="pre">session</span></tt>, it contains the main loop that serves all torrents.</p>
<div class="section" id="session"> <div class="section" id="session">
<h2><a class="toc-backref" href="#id10" name="session">session</a></h2> <h2><a class="toc-backref" href="#id11" name="session">session</a></h2>
<p>The <tt class="literal"><span class="pre">session</span></tt> class has the following synopsis:</p> <p>The <tt class="literal"><span class="pre">session</span></tt> class has the following synopsis:</p>
<pre class="literal-block"> <pre class="literal-block">
class session: public boost::noncopyable class session: public boost::noncopyable
@ -310,7 +309,7 @@ struct hash_failed_alert: alert
</pre> </pre>
</div> </div>
<div class="section" id="parsing-torrent-files"> <div class="section" id="parsing-torrent-files">
<h2><a class="toc-backref" href="#id11" name="parsing-torrent-files">parsing torrent files</a></h2> <h2><a class="toc-backref" href="#id12" name="parsing-torrent-files">parsing torrent files</a></h2>
<p>The torrent files are <a class="reference" href="http://bitconjurer.org/BitTorrent/protocol.html">bencoded</a>. There are two functions in libtorrent that can encode and decode <p>The torrent files are <a class="reference" href="http://bitconjurer.org/BitTorrent/protocol.html">bencoded</a>. There are two functions in libtorrent that can encode and decode
bencoded data. They are:</p> bencoded data. They are:</p>
<pre class="literal-block"> <pre class="literal-block">
@ -349,7 +348,7 @@ entry e = bdecode(buf, buf + data_size);
it will throw <a class="reference" href="#invalid-encoding">invalid_encoding</a>.</p> it will throw <a class="reference" href="#invalid-encoding">invalid_encoding</a>.</p>
</div> </div>
<div class="section" id="entry"> <div class="section" id="entry">
<h2><a class="toc-backref" href="#id12" name="entry">entry</a></h2> <h2><a class="toc-backref" href="#id13" name="entry">entry</a></h2>
<p>The <tt class="literal"><span class="pre">entry</span></tt> class represents one node in a bencoded hierarchy. It works as a <p>The <tt class="literal"><span class="pre">entry</span></tt> class represents one node in a bencoded hierarchy. It works as a
variant type, it can be either a list, a dictionary (<tt class="literal"><span class="pre">std::map</span></tt>), an integer variant type, it can be either a list, a dictionary (<tt class="literal"><span class="pre">std::map</span></tt>), an integer
or a string. This is its synopsis:</p> or a string. This is its synopsis:</p>
@ -419,7 +418,7 @@ if (i != dict.end())
exists.</p> exists.</p>
</div> </div>
<div class="section" id="torrent-info"> <div class="section" id="torrent-info">
<h2><a class="toc-backref" href="#id13" name="torrent-info">torrent_info</a></h2> <h2><a class="toc-backref" href="#id14" name="torrent-info">torrent_info</a></h2>
<p>The <tt class="literal"><span class="pre">torrent_info</span></tt> has the following synopsis:</p> <p>The <tt class="literal"><span class="pre">torrent_info</span></tt> has the following synopsis:</p>
<pre class="literal-block"> <pre class="literal-block">
class torrent_info class torrent_info
@ -506,7 +505,7 @@ object, representing the time when this torrent file was created. If there's no
in the torrent file, this will return a date of january 1:st 1970.</p> in the torrent file, this will return a date of january 1:st 1970.</p>
</div> </div>
<div class="section" id="torrent-handle"> <div class="section" id="torrent-handle">
<h2><a class="toc-backref" href="#id14" name="torrent-handle">torrent_handle</a></h2> <h2><a class="toc-backref" href="#id15" name="torrent-handle">torrent_handle</a></h2>
<p>You will usually have to store your torrent handles somewhere, since it's the <p>You will usually have to store your torrent handles somewhere, since it's the
object through which you retrieve infromation about the torrent and aborts the torrent. object through which you retrieve infromation about the torrent and aborts the torrent.
Its declaration looks like this:</p> Its declaration looks like this:</p>
@ -545,7 +544,7 @@ torrent. If you set this to -1, there will be no limit.</p>
<p><tt class="literal"><span class="pre">write_resume_data()</span></tt> takes a non-const reference to a char-vector, that vector will be filled <p><tt class="literal"><span class="pre">write_resume_data()</span></tt> takes a non-const reference to a char-vector, that vector will be filled
with the fast-resume data. For more information about how fast-resume works, see <a class="reference" href="#fast-resume">fast resume</a>.</p> with the fast-resume data. For more information about how fast-resume works, see <a class="reference" href="#fast-resume">fast resume</a>.</p>
<div class="section" id="status"> <div class="section" id="status">
<h3><a class="toc-backref" href="#id15" name="status">status()</a></h3> <h3><a class="toc-backref" href="#id16" name="status">status()</a></h3>
<p><tt class="literal"><span class="pre">status()</span></tt> will return a structure with information about the status of this <p><tt class="literal"><span class="pre">status()</span></tt> will return a structure with information about the status of this
torrent. If the <a class="reference" href="#torrent-handle">torrent_handle</a> is invalid, it will throw <a class="reference" href="#invalid-handle">invalid_handle</a> exception. torrent. If the <a class="reference" href="#torrent-handle">torrent_handle</a> is invalid, it will throw <a class="reference" href="#invalid-handle">invalid_handle</a> exception.
It contains the following fields:</p> It contains the following fields:</p>
@ -627,7 +626,7 @@ all peers. The rates are given as the number of bytes per second.</p>
<p><tt class="literal"><span class="pre">total_done</span></tt> is the total number of bytes of the file(s) that we have.</p> <p><tt class="literal"><span class="pre">total_done</span></tt> is the total number of bytes of the file(s) that we have.</p>
</div> </div>
<div class="section" id="get-download-queue"> <div class="section" id="get-download-queue">
<h3><a class="toc-backref" href="#id16" name="get-download-queue">get_download_queue()</a></h3> <h3><a class="toc-backref" href="#id17" name="get-download-queue">get_download_queue()</a></h3>
<p><tt class="literal"><span class="pre">get_download_queue()</span></tt> takes a non-const reference to a vector which it will fill <p><tt class="literal"><span class="pre">get_download_queue()</span></tt> takes a non-const reference to a vector which it will fill
information about pieces that are partially downloaded or not downloaded at all but partially information about pieces that are partially downloaded or not downloaded at all but partially
requested. The entry in the vector (<tt class="literal"><span class="pre">partial_piece_info</span></tt>) looks like this:</p> requested. The entry in the vector (<tt class="literal"><span class="pre">partial_piece_info</span></tt>) looks like this:</p>
@ -659,7 +658,7 @@ When a piece fails a hash verification, single blocks may be redownloaded to see
may pass then.</p> may pass then.</p>
</div> </div>
<div class="section" id="get-peer-info"> <div class="section" id="get-peer-info">
<h3><a class="toc-backref" href="#id17" name="get-peer-info">get_peer_info()</a></h3> <h3><a class="toc-backref" href="#id18" name="get-peer-info">get_peer_info()</a></h3>
<p><tt class="literal"><span class="pre">get_peer_info()</span></tt> takes a reference to a vector that will be cleared and filled <p><tt class="literal"><span class="pre">get_peer_info()</span></tt> takes a reference to a vector that will be cleared and filled
with one entry for each peer connected to this torrent, given the handle is valid. If the with one entry for each peer connected to this torrent, given the handle is valid. If the
<a class="reference" href="#torrent-handle">torrent_handle</a> is invalid, it will throw <tt class="literal"><span class="pre">invalid_handle</span></tt> exception. Each entry in <a class="reference" href="#torrent-handle">torrent_handle</a> is invalid, it will throw <tt class="literal"><span class="pre">invalid_handle</span></tt> exception. Each entry in
@ -673,7 +672,8 @@ struct peer_info
interesting = 0x1, interesting = 0x1,
choked = 0x2, choked = 0x2,
remote_interested = 0x4, remote_interested = 0x4,
remote_choked = 0x8 remote_choked = 0x8,
supports_extensions = 0x10
}; };
unsigned int flags; unsigned int flags;
address ip; address ip;
@ -699,7 +699,8 @@ any combination of the four enums above. Where <tt class="literal"><span class="
are interested in pieces from this peer. <tt class="literal"><span class="pre">choked</span></tt> means that <strong>we</strong> have are interested in pieces from this peer. <tt class="literal"><span class="pre">choked</span></tt> means that <strong>we</strong> have
choked this peer. <tt class="literal"><span class="pre">remote_interested</span></tt> and <tt class="literal"><span class="pre">remote_choked</span></tt> means the choked this peer. <tt class="literal"><span class="pre">remote_interested</span></tt> and <tt class="literal"><span class="pre">remote_choked</span></tt> means the
same thing but that the peer is interested in pieces from us and the peer has choked same thing but that the peer is interested in pieces from us and the peer has choked
<strong>us</strong>.</p> <strong>us</strong>. <tt class="literal"><span class="pre">support_extensions</span></tt> means that this peer supports the <a class="reference" href="http://nolar.com/azureus/extended.htm">extension protocol
as described by nolar</a>.</p>
<p>The <tt class="literal"><span class="pre">ip</span></tt> field is the IP-address to this peer. Its type is a wrapper around the <p>The <tt class="literal"><span class="pre">ip</span></tt> field is the IP-address to this peer. Its type is a wrapper around the
actual address and the port number. See <a class="reference" href="#address">address</a> class.</p> actual address and the port number. See <a class="reference" href="#address">address</a> class.</p>
<p><tt class="literal"><span class="pre">up_speed</span></tt> and <tt class="literal"><span class="pre">down_speed</span></tt> is the current upload and download speed <p><tt class="literal"><span class="pre">up_speed</span></tt> and <tt class="literal"><span class="pre">down_speed</span></tt> is the current upload and download speed
@ -734,19 +735,19 @@ of bytes of this block we have received from the peer, and <tt class="literal"><
the total number of bytes in this block.</p> the total number of bytes in this block.</p>
</div> </div>
<div class="section" id="get-torrent-info"> <div class="section" id="get-torrent-info">
<h3><a class="toc-backref" href="#id18" name="get-torrent-info">get_torrent_info()</a></h3> <h3><a class="toc-backref" href="#id19" name="get-torrent-info">get_torrent_info()</a></h3>
<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 <tt class="literal"><span class="pre">torrent_info</span></tt> 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 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> <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> </div>
<div class="section" id="is-valid"> <div class="section" id="is-valid">
<h3><a class="toc-backref" href="#id19" name="is-valid">is_valid()</a></h3> <h3><a class="toc-backref" href="#id20" name="is-valid">is_valid()</a></h3>
<p>Returns true if this handle refers to a valid torrent and false if it hasn't been initialized <p>Returns true if this handle refers to a valid torrent and false if it hasn't been initialized
or if the torrent it refers to has been aborted.</p> or if the torrent it refers to has been aborted.</p>
</div> </div>
</div> </div>
<div class="section" id="address"> <div class="section" id="address">
<h2><a class="toc-backref" href="#id20" name="address">address</a></h2> <h2><a class="toc-backref" href="#id21" name="address">address</a></h2>
<p>The <tt class="literal"><span class="pre">address</span></tt> class represents a name of a network endpoint (usually referred to as <p>The <tt class="literal"><span class="pre">address</span></tt> class represents a name of a network endpoint (usually referred to as
IP-address) and a port number. This is the same thing as a <tt class="literal"><span class="pre">sockaddr_in</span></tt> would contain. IP-address) and a port number. This is the same thing as a <tt class="literal"><span class="pre">sockaddr_in</span></tt> would contain.
Its declaration looks like this:</p> Its declaration looks like this:</p>
@ -779,7 +780,7 @@ while it does the DNS lookup, it returns a string that points to the address rep
<p><tt class="literal"><span class="pre">ip()</span></tt> will return the 32-bit ip-address as an integer. <tt class="literal"><span class="pre">port()</span></tt> returns the port number.</p> <p><tt class="literal"><span class="pre">ip()</span></tt> will return the 32-bit ip-address as an integer. <tt class="literal"><span class="pre">port()</span></tt> returns the port number.</p>
</div> </div>
<div class="section" id="http-settings"> <div class="section" id="http-settings">
<h2><a class="toc-backref" href="#id21" name="http-settings">http_settings</a></h2> <h2><a class="toc-backref" href="#id22" name="http-settings">http_settings</a></h2>
<p>You have some control over tracker requests through the <tt class="literal"><span class="pre">http_settings</span></tt> object. You <p>You have some control over tracker requests through the <tt class="literal"><span class="pre">http_settings</span></tt> object. You
create it and fill it with your settings and the use <tt class="literal"><span class="pre">session::set_http_settings()</span></tt> create it and fill it with your settings and the use <tt class="literal"><span class="pre">session::set_http_settings()</span></tt>
to apply them. You have control over proxy and authorization settings and also the user-agent to apply them. You have control over proxy and authorization settings and also the user-agent
@ -819,7 +820,7 @@ uncompressed (given your limit is lower than 2 megs). Default limit is
1 megabyte.</p> 1 megabyte.</p>
</div> </div>
<div class="section" id="big-number"> <div class="section" id="big-number">
<h2><a class="toc-backref" href="#id22" name="big-number">big_number</a></h2> <h2><a class="toc-backref" href="#id23" name="big-number">big_number</a></h2>
<p>Both the <tt class="literal"><span class="pre">peer_id</span></tt> and <tt class="literal"><span class="pre">sha1_hash</span></tt> types are typedefs of the class <p>Both the <tt class="literal"><span class="pre">peer_id</span></tt> and <tt class="literal"><span class="pre">sha1_hash</span></tt> types are typedefs of the class
<tt class="literal"><span class="pre">big_number</span></tt>. It represents 20 bytes of data. Its synopsis follows:</p> <tt class="literal"><span class="pre">big_number</span></tt>. It represents 20 bytes of data. Its synopsis follows:</p>
<pre class="literal-block"> <pre class="literal-block">
@ -840,7 +841,7 @@ public:
<p>The iterators gives you access to individual bytes.</p> <p>The iterators gives you access to individual bytes.</p>
</div> </div>
<div class="section" id="hasher"> <div class="section" id="hasher">
<h2><a class="toc-backref" href="#id23" name="hasher">hasher</a></h2> <h2><a class="toc-backref" href="#id24" name="hasher">hasher</a></h2>
<p>This class creates sha1-hashes. Its declaration looks like this:</p> <p>This class creates sha1-hashes. Its declaration looks like this:</p>
<pre class="literal-block"> <pre class="literal-block">
class hasher class hasher
@ -864,7 +865,7 @@ call <tt class="literal"><span class="pre">reset()</span></tt> to reinitialize i
For more info, see <tt class="literal"><span class="pre">src/sha1.c</span></tt>.</p> For more info, see <tt class="literal"><span class="pre">src/sha1.c</span></tt>.</p>
</div> </div>
<div class="section" id="fingerprint"> <div class="section" id="fingerprint">
<h2><a class="toc-backref" href="#id24" name="fingerprint">fingerprint</a></h2> <h2><a class="toc-backref" href="#id25" name="fingerprint">fingerprint</a></h2>
<p>The fingerprint class represents information about a client and its version. It is used <p>The fingerprint class represents information about a client and its version. It is used
to encode this information into the client's peer id.</p> to encode this information into the client's peer id.</p>
<p>This is the class declaration:</p> <p>This is the class declaration:</p>
@ -913,7 +914,7 @@ version of your client. All these numbers must be within the range [0, 9].</p>
<p><tt class="literal"><span class="pre">to_string()</span></tt> will generate the actual string put in the peer-id, and return it.</p> <p><tt class="literal"><span class="pre">to_string()</span></tt> will generate the actual string put in the peer-id, and return it.</p>
</div> </div>
<div class="section" id="alert"> <div class="section" id="alert">
<h2><a class="toc-backref" href="#id25" name="alert">alert</a></h2> <h2><a class="toc-backref" href="#id26" name="alert">alert</a></h2>
<p>The <tt class="literal"><span class="pre">alert</span></tt> class is used to pass messages of events from the libtorrent code <p>The <tt class="literal"><span class="pre">alert</span></tt> class is used to pass messages of events from the libtorrent code
to the user. It is a base class that specific messages are derived from. This to the user. It is a base class that specific messages are derived from. This
is its synopsis:</p> is its synopsis:</p>
@ -936,11 +937,11 @@ public:
</pre> </pre>
</div> </div>
<div class="section" id="exceptions"> <div class="section" id="exceptions">
<h2><a class="toc-backref" href="#id26" name="exceptions">exceptions</a></h2> <h2><a class="toc-backref" href="#id27" name="exceptions">exceptions</a></h2>
<p>There are a number of exceptions that can be thrown from different places in libtorrent, <p>There are a number of exceptions that can be thrown from different places in libtorrent,
here's a complete list with description.</p> here's a complete list with description.</p>
<div class="section" id="invalid-handle"> <div class="section" id="invalid-handle">
<h3><a class="toc-backref" href="#id27" name="invalid-handle">invalid_handle</a></h3> <h3><a class="toc-backref" href="#id28" name="invalid-handle">invalid_handle</a></h3>
<p>This exception is thrown when querying information from a <a class="reference" href="#torrent-handle">torrent_handle</a> that hasn't <p>This exception is thrown when querying information from a <a class="reference" href="#torrent-handle">torrent_handle</a> that hasn't
been initialized or that has become invalid.</p> been initialized or that has become invalid.</p>
<pre class="literal-block"> <pre class="literal-block">
@ -951,7 +952,7 @@ struct invalid_handle: std::exception
</pre> </pre>
</div> </div>
<div class="section" id="duplicate-torrent"> <div class="section" id="duplicate-torrent">
<h3><a class="toc-backref" href="#id28" name="duplicate-torrent">duplicate_torrent</a></h3> <h3><a class="toc-backref" href="#id29" name="duplicate-torrent">duplicate_torrent</a></h3>
<p>This is thrown by <tt class="literal"><span class="pre">session::add_torrent()</span></tt> if the torrent already has been added to <p>This is thrown by <tt class="literal"><span class="pre">session::add_torrent()</span></tt> if the torrent already has been added to
the session.</p> the session.</p>
<pre class="literal-block"> <pre class="literal-block">
@ -962,7 +963,7 @@ struct duplicate_torrent: std::exception
</pre> </pre>
</div> </div>
<div class="section" id="invalid-encoding"> <div class="section" id="invalid-encoding">
<h3><a class="toc-backref" href="#id29" name="invalid-encoding">invalid_encoding</a></h3> <h3><a class="toc-backref" href="#id30" name="invalid-encoding">invalid_encoding</a></h3>
<p>This is thrown by <tt class="literal"><span class="pre">bdecode()</span></tt> if the input data is not a valid bencoding.</p> <p>This is thrown by <tt class="literal"><span class="pre">bdecode()</span></tt> if the input data is not a valid bencoding.</p>
<pre class="literal-block"> <pre class="literal-block">
struct invalid_encoding: std::exception struct invalid_encoding: std::exception
@ -972,7 +973,7 @@ struct invalid_encoding: std::exception
</pre> </pre>
</div> </div>
<div class="section" id="type-error"> <div class="section" id="type-error">
<h3><a class="toc-backref" href="#id30" name="type-error">type_error</a></h3> <h3><a class="toc-backref" href="#id31" name="type-error">type_error</a></h3>
<p>This is thrown from the accessors of <tt class="literal"><span class="pre">entry</span></tt> if the data type of the <tt class="literal"><span class="pre">entry</span></tt> doesn't <p>This is thrown from the accessors of <tt class="literal"><span class="pre">entry</span></tt> if the data type of the <tt class="literal"><span class="pre">entry</span></tt> doesn't
match the type you want to extract from it.</p> match the type you want to extract from it.</p>
<pre class="literal-block"> <pre class="literal-block">
@ -983,7 +984,7 @@ struct type_error: std::runtime_error
</pre> </pre>
</div> </div>
<div class="section" id="invalid-torrent-file"> <div class="section" id="invalid-torrent-file">
<h3><a class="toc-backref" href="#id31" name="invalid-torrent-file">invalid_torrent_file</a></h3> <h3><a class="toc-backref" href="#id32" name="invalid-torrent-file">invalid_torrent_file</a></h3>
<p>This exception is thrown from the constructor of <tt class="literal"><span class="pre">torrent_info</span></tt> if the given bencoded information <p>This exception is thrown from the constructor of <tt class="literal"><span class="pre">torrent_info</span></tt> if the given bencoded information
doesn't meet the requirements on what information has to be present in a torrent file.</p> doesn't meet the requirements on what information has to be present in a torrent file.</p>
<pre class="literal-block"> <pre class="literal-block">
@ -995,9 +996,9 @@ struct invalid_torrent_file: std::exception
</div> </div>
</div> </div>
<div class="section" id="example-usage"> <div class="section" id="example-usage">
<h2><a class="toc-backref" href="#id32" name="example-usage">example usage</a></h2> <h2><a class="toc-backref" href="#id33" name="example-usage">example usage</a></h2>
<div class="section" id="dump-torrent"> <div class="section" id="dump-torrent">
<h3><a class="toc-backref" href="#id33" name="dump-torrent">dump_torrent</a></h3> <h3><a class="toc-backref" href="#id34" name="dump-torrent">dump_torrent</a></h3>
<p>This is an example of a program that will take a torrent-file as a parameter and <p>This is an example of a program that will take a torrent-file as a parameter and
print information about it to std out:</p> print information about it to std out:</p>
<pre class="literal-block"> <pre class="literal-block">
@ -1061,7 +1062,7 @@ int main(int argc, char* argv[])
</pre> </pre>
</div> </div>
<div class="section" id="simple-client"> <div class="section" id="simple-client">
<h3><a class="toc-backref" href="#id34" name="simple-client">simple client</a></h3> <h3><a class="toc-backref" href="#id35" name="simple-client">simple client</a></h3>
<p>This is a simple client. It doesn't have much output to keep it simple:</p> <p>This is a simple client. It doesn't have much output to keep it simple:</p>
<pre class="literal-block"> <pre class="literal-block">
#include &lt;iostream&gt; #include &lt;iostream&gt;
@ -1113,7 +1114,7 @@ int main(int argc, char* argv[])
</div> </div>
</div> </div>
<div class="section" id="fast-resume"> <div class="section" id="fast-resume">
<h2><a class="toc-backref" href="#id35" name="fast-resume">fast resume</a></h2> <h2><a class="toc-backref" href="#id36" name="fast-resume">fast resume</a></h2>
<p>The fast resume mechanism is a way to remember which pieces are downloaded and where they <p>The fast resume mechanism is a way to remember which pieces are downloaded and where they
are put between sessions. You can generate fast resume data by calling are put between sessions. You can generate fast resume data by calling
<tt class="literal"><span class="pre">torrent_handle::write_resume_data()</span></tt> on <a class="reference" href="#torrent-handle">torrent_handle</a>. You can then save this data <tt class="literal"><span class="pre">torrent_handle::write_resume_data()</span></tt> on <a class="reference" href="#torrent-handle">torrent_handle</a>. You can then save this data
@ -1126,7 +1127,7 @@ will skip the time consuming checks. It may have to do the checking anyway, if t
fast-resume data is corrupt or doesn't fit the storage for that torrent, then it will fast-resume data is corrupt or doesn't fit the storage for that torrent, then it will
not trust the fast-resume data and just do the checking.</p> not trust the fast-resume data and just do the checking.</p>
<div class="section" id="file-format"> <div class="section" id="file-format">
<h3><a class="toc-backref" href="#id36" name="file-format">file format</a></h3> <h3><a class="toc-backref" href="#id37" name="file-format">file format</a></h3>
<p>The format of the fast-resume data is as follows, given that all <p>The format of the fast-resume data is as follows, given that all
4-byte integers are stored as big-endian:</p> 4-byte integers are stored as big-endian:</p>
<pre class="literal-block"> <pre class="literal-block">
@ -1149,12 +1150,12 @@ for each unfinished piece
</div> </div>
</div> </div>
<div class="section" id="feedback"> <div class="section" id="feedback">
<h1><a class="toc-backref" href="#id37" name="feedback">Feedback</a></h1> <h1><a class="toc-backref" href="#id38" name="feedback">Feedback</a></h1>
<p>There's a <a class="reference" href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a>.</p> <p>There's a <a class="reference" href="http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss">mailing list</a>.</p>
<p>You can usually find me as hydri in <tt class="literal"><span class="pre">#btports</span> <span class="pre">&#64;</span> <span class="pre">irc.freenode.net</span></tt>.</p> <p>You can usually find me as hydri in <tt class="literal"><span class="pre">#btports</span> <span class="pre">&#64;</span> <span class="pre">irc.freenode.net</span></tt>.</p>
</div> </div>
<div class="section" id="aknowledgements"> <div class="section" id="aknowledgements">
<h1><a class="toc-backref" href="#id38" name="aknowledgements">Aknowledgements</a></h1> <h1><a class="toc-backref" href="#id39" name="aknowledgements">Aknowledgements</a></h1>
<p>Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003</p> <p>Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003</p>
<p>Contributions by Magnus Jonsson</p> <p>Contributions by Magnus Jonsson</p>
<p>Thanks to Reimond Retz for bugfixes, suggestions and testing</p> <p>Thanks to Reimond Retz for bugfixes, suggestions and testing</p>

View File

@ -51,14 +51,13 @@ __ http://home.elp.rr.com/tur/multitracker-spec.txt
Functions that are yet to be implemented: Functions that are yet to be implemented:
* choke/unchoke policy for seed-mode
* number of connections limit * number of connections limit
* better handling of peers that send bad data * better handling of peers that send bad data
* ip-filters * ip-filters
* file-level piece priority * file-level piece priority
libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread, libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread,
boost.filesystem boost.date_time and various other boost libraries and zlib. boost.filesystem, boost.date_time and various other boost libraries as well as zlib.
libtorrent has been successfully compiled and tested on: libtorrent has been successfully compiled and tested on:
@ -245,13 +244,17 @@ dispatcher mechanism that's available in libtorrent.
TODO: describe the type dispatching mechanism TODO: describe the type dispatching mechanism
The currently available alert types are: You can do a ``dynamic_cast`` to a specific alert type to get more message-specific information.
These are the different alert types.
* tracker_alert tracker_alert
* hash_failed_alert ~~~~~~~~~~~~~
You can try a ``dynamic_cast`` to these types to get more message-pecific information. Here This alert is generated on tracker time outs, premature disconnects, invalid response or
are their definitions:: a HTTP response other than "200 OK". From the alert you can get the handle to the torrent
the tracker belongs to. This alert is generated as severity level ``warning``.
::
struct tracker_alert: alert struct tracker_alert: alert
{ {
@ -261,6 +264,15 @@ are their definitions::
torrent_handle handle; torrent_handle handle;
}; };
hash_failed_alert
~~~~~~~~~~~~~~~~~
This alert is generated when a finished piece fails its hash check. You can get the handle
to the torrent which got the failed piece and the index of the piece itself from the alert.
This alert is generated as severity level ``info``.
::
struct hash_failed_alert: alert struct hash_failed_alert: alert
{ {
hash_failed_alert( hash_failed_alert(
@ -274,6 +286,22 @@ are their definitions::
int piece_index; int piece_index;
}; };
peer_error_alert
~~~~~~~~~~~~~~~~
This alert is generated when a peer sends invalid data over the peer-peer protocol. The peer
will be disconnected, but you get its peer-id from the alert. This alert is generated
as severity level ``debug``.
::
struct peer_error_alert: alert
{
peer_error_alert(const peer_id& pid, const std::string& msg);
virtual std::auto_ptr<alert> clone() const;
peer_id id;
};
parsing torrent files parsing torrent files
@ -690,7 +718,8 @@ fields::
interesting = 0x1, interesting = 0x1,
choked = 0x2, choked = 0x2,
remote_interested = 0x4, remote_interested = 0x4,
remote_choked = 0x8 remote_choked = 0x8,
supports_extensions = 0x10
}; };
unsigned int flags; unsigned int flags;
address ip; address ip;
@ -716,7 +745,10 @@ any combination of the four enums above. Where ``interesting`` means that we
are interested in pieces from this peer. ``choked`` means that **we** have are interested in pieces from this peer. ``choked`` means that **we** have
choked this peer. ``remote_interested`` and ``remote_choked`` means the choked this peer. ``remote_interested`` and ``remote_choked`` means the
same thing but that the peer is interested in pieces from us and the peer has choked same thing but that the peer is interested in pieces from us and the peer has choked
**us**. **us**. ``support_extensions`` means that this peer supports the `extension protocol
as described by nolar`__.
__ http://nolar.com/azureus/extended.htm
The ``ip`` field is the IP-address to this peer. Its type is a wrapper around the The ``ip`` field is the IP-address to this peer. Its type is a wrapper around the
actual address and the port number. See address_ class. actual address and the port number. See address_ class.

View File

@ -314,7 +314,7 @@ int main(int argc, char* argv[])
<< "u: " << add_suffix(i->up_speed) << "/s " << "u: " << add_suffix(i->up_speed) << "/s "
<< "(" << add_suffix(i->total_upload) << ") " << "(" << add_suffix(i->total_upload) << ") "
// << "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " " // << "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " "
<< "b: " << add_suffix(i->load_balancing) << " " << "q: " << i->download_queue_length << " "
<< "f: " << "f: "
<< static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_") << static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_")
<< static_cast<const char*>((i->flags & peer_info::choked)?"C":"_") << static_cast<const char*>((i->flags & peer_info::choked)?"C":"_")

View File

@ -305,6 +305,28 @@ namespace libtorrent
boost::shared_ptr<logger> m_logger; boost::shared_ptr<logger> m_logger;
#endif #endif
// the message handlers are called
// each time a recv() returns some new
// data, the last time it will be called
// is when the entire packet has been
// received, then it will no longer
// be called. i.e. most handlers need
// to check how much of the packet they
// have received before any processing
void on_choke(int received);
void on_unchoke(int received);
void on_interested(int received);
void on_not_interested(int received);
void on_have(int received);
void on_bitfield(int received);
void on_request(int received);
void on_piece(int received);
void on_cancel(int received);
void on_extension_list(int received);
void on_extended(int received);
typedef void (peer_connection::*message_handler)(int received);
private: private:
bool dispatch_message(int received); bool dispatch_message(int received);
@ -345,11 +367,14 @@ namespace libtorrent
msg_piece, msg_piece,
msg_cancel, msg_cancel,
// extension protocol message // extension protocol message
msg_extensions = 20, msg_extension_list = 20,
// extended messages msg_extended,
msg_gzip_piece
num_supported_messages
}; };
const static message_handler m_message_handler[num_supported_messages];
std::size_t m_packet_size; std::size_t m_packet_size;
std::size_t m_recv_pos; std::size_t m_recv_pos;
std::vector<char> m_recv_buffer; std::vector<char> m_recv_buffer;

View File

@ -62,6 +62,12 @@ namespace libtorrent
int load_balancing; int load_balancing;
// this is the number of requests
// we have sent to this peer
// that we haven't got a response
// for yet
int download_queue_length;
// the currently downloading piece // the currently downloading piece
// if piece index is -1 all associated // if piece index is -1 all associated
// members are just set to 0 // members are just set to 0

View File

@ -69,6 +69,19 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
struct peer_error_alert: alert
{
peer_error_alert(const peer_id& pid, const std::string& msg)
: alert(alert::debug, msg)
, id(pid)
{}
virtual std::auto_ptr<alert> clone() const
{ return std::auto_ptr<alert>(new peer_error_alert(*this)); }
peer_id id;
};
namespace detail namespace detail
{ {
// workaround for microsofts // workaround for microsofts

View File

@ -47,7 +47,7 @@ namespace libtorrent
{ {
namespace detail namespace detail
{ {
class piece_checker_data; struct piece_checker_data;
} }
class session; class session;

View File

@ -54,6 +54,23 @@ namespace libtorrent
const char* peer_connection::extension_names[] = const char* peer_connection::extension_names[] =
{ "gzip" }; { "gzip" };
const peer_connection::message_handler peer_connection::m_message_handler[] =
{
&peer_connection::on_choke,
&peer_connection::on_unchoke,
&peer_connection::on_interested,
&peer_connection::on_not_interested,
&peer_connection::on_have,
&peer_connection::on_bitfield,
&peer_connection::on_request,
&peer_connection::on_piece,
&peer_connection::on_cancel,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
&peer_connection::on_extension_list,
&peer_connection::on_extended
};
peer_connection::peer_connection( peer_connection::peer_connection(
detail::session_impl& ses detail::session_impl& ses
, selector& sel , selector& sel
@ -262,31 +279,23 @@ namespace libtorrent
return boost::optional<piece_block_progress>(p); return boost::optional<piece_block_progress>(p);
} }
bool peer_connection::dispatch_message(int received)
// message handlers
// -----------------------------
// ----------- CHOKE -----------
// -----------------------------
void peer_connection::on_choke(int received)
{ {
assert(m_recv_pos >= received);
assert(m_recv_pos > 0);
int packet_type = m_recv_buffer[0];
if (packet_type == 20)
{
int i = 0;
}
switch (packet_type)
{
// *************** CHOKE ***************
case msg_choke:
if (m_packet_size != 1) if (m_packet_size != 1)
throw protocol_error("'choke' message size != 1"); throw protocol_error("'choke' message size != 1");
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false; if (m_recv_pos < m_packet_size) return;
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== CHOKE\n"; (*m_logger) << m_socket->sender().as_string() << " <== CHOKE\n";
#endif #endif
m_peer_choked = true; m_peer_choked = true;
m_torrent->get_policy().choked(*this); m_torrent->get_policy().choked(*this);
@ -299,69 +308,78 @@ namespace libtorrent
m_torrent->picker().abort_download(*i); m_torrent->picker().abort_download(*i);
} }
m_download_queue.clear(); m_download_queue.clear();
#ifndef NDEBUG #ifndef NDEBUG
// m_torrent->picker().integrity_check(m_torrent); // m_torrent->picker().integrity_check(m_torrent);
#endif #endif
break; }
// -----------------------------
// ---------- UNCHOKE ----------
// -----------------------------
void peer_connection::on_unchoke(int received)
// *************** UNCHOKE *************** {
case msg_unchoke:
if (m_packet_size != 1) if (m_packet_size != 1)
throw protocol_error("'unchoke' message size != 1"); throw protocol_error("'unchoke' message size != 1");
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false; if (m_recv_pos < m_packet_size) return;
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== UNCHOKE\n"; (*m_logger) << m_socket->sender().as_string() << " <== UNCHOKE\n";
#endif #endif
m_peer_choked = false; m_peer_choked = false;
m_torrent->get_policy().unchoked(*this); m_torrent->get_policy().unchoked(*this);
break; }
// -----------------------------
// -------- INTERESTED ---------
// -----------------------------
// *************** INTERESTED *************** void peer_connection::on_interested(int received)
case msg_interested: {
if (m_packet_size != 1) if (m_packet_size != 1)
throw protocol_error("'interested' message size != 1"); throw protocol_error("'interested' message size != 1");
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false; if (m_recv_pos < m_packet_size) return;
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== INTERESTED\n"; (*m_logger) << m_socket->sender().as_string() << " <== INTERESTED\n";
#endif #endif
m_peer_interested = true; m_peer_interested = true;
m_torrent->get_policy().interested(*this); m_torrent->get_policy().interested(*this);
break; }
// -----------------------------
// ------ NOT INTERESTED -------
// -----------------------------
// *************** NOT INTERESTED *************** void peer_connection::on_not_interested(int received)
case msg_not_interested: {
if (m_packet_size != 1) if (m_packet_size != 1)
throw protocol_error("'not interested' message size != 1"); throw protocol_error("'not interested' message size != 1");
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false; if (m_recv_pos < m_packet_size) return;
// clear the request queue if the client isn't interested // clear the request queue if the client isn't interested
m_requests.clear(); m_requests.clear();
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== NOT_INTERESTED\n"; (*m_logger) << m_socket->sender().as_string() << " <== NOT_INTERESTED\n";
#endif #endif
m_peer_interested = false; m_peer_interested = false;
m_torrent->get_policy().not_interested(*this); m_torrent->get_policy().not_interested(*this);
break; }
// -----------------------------
// ----------- HAVE ------------
// -----------------------------
void peer_connection::on_have(int received)
// *************** HAVE ***************
case msg_have:
{ {
if (m_packet_size != 5) if (m_packet_size != 5)
throw protocol_error("'have' message size != 5"); throw protocol_error("'have' message size != 5");
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false; if (m_recv_pos < m_packet_size) return;
const char* ptr = &m_recv_buffer[1]; const char* ptr = &m_recv_buffer[1];
int index = detail::read_int(ptr); int index = detail::read_int(ptr);
@ -369,15 +387,15 @@ namespace libtorrent
if (index >= m_have_piece.size() || index < 0) if (index >= m_have_piece.size() || index < 0)
throw protocol_error("have message with higher index than the number of pieces"); throw protocol_error("have message with higher index than the number of pieces");
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== HAVE [ piece: " << index << "]\n"; (*m_logger) << m_socket->sender().as_string() << " <== HAVE [ piece: " << index << "]\n";
#endif #endif
if (m_have_piece[index]) if (m_have_piece[index])
{ {
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " oops.. we already knew that: " << index << "\n"; (*m_logger) << m_socket->sender().as_string() << " oops.. we already knew that: " << index << "\n";
#endif #endif
} }
else else
{ {
@ -387,23 +405,22 @@ namespace libtorrent
if (!m_torrent->have_piece(index) && !is_interesting()) if (!m_torrent->have_piece(index) && !is_interesting())
m_torrent->get_policy().peer_is_interesting(*this); m_torrent->get_policy().peer_is_interesting(*this);
} }
break;
} }
// -----------------------------
// --------- BITFIELD ----------
// -----------------------------
void peer_connection::on_bitfield(int received)
// *************** BITFIELD ***************
case msg_bitfield:
{ {
if (m_packet_size - 1 != (m_have_piece.size() + 7) / 8) if (m_packet_size - 1 != (m_have_piece.size() + 7) / 8)
throw protocol_error("bitfield with invalid size"); throw protocol_error("bitfield with invalid size");
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false; if (m_recv_pos < m_packet_size) return;
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== BITFIELD\n"; (*m_logger) << m_socket->sender().as_string() << " <== BITFIELD\n";
#endif #endif
// build a vector of all pieces // build a vector of all pieces
std::vector<int> piece_list; std::vector<int> piece_list;
for (std::size_t i = 0; i < m_have_piece.size(); ++i) for (std::size_t i = 0; i < m_have_piece.size(); ++i)
@ -439,19 +456,228 @@ namespace libtorrent
if (piece_list.empty()) if (piece_list.empty())
{ {
#ifndef NDEBUG #ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " *** THIS IS A SEED ***\n"; (*m_logger) << m_socket->sender().as_string() << " *** THIS IS A SEED ***\n";
#endif #endif
} }
if (interesting) m_torrent->get_policy().peer_is_interesting(*this); if (interesting) m_torrent->get_policy().peer_is_interesting(*this);
break;
} }
// -----------------------------
// ---------- REQUEST ----------
// -----------------------------
// *************** EXTENSIONS *************** void peer_connection::on_request(int received)
case msg_extensions: {
if (m_packet_size != 13)
throw protocol_error("'request' message size != 13");
m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return;
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);
// make sure this request
// is legal and taht the peer
// is not choked
if (r.piece >= 0
&& r.piece < m_torrent->torrent_file().num_pieces()
&& r.start >= 0
&& r.start < m_torrent->torrent_file().piece_size(r.piece)
&& r.length > 0
&& r.length + r.start < m_torrent->torrent_file().piece_size(r.piece)
&& m_peer_interested)
{
// if we have choked the client
// ignore the request
if (m_choked) return;
m_requests.push_back(r);
send_buffer_updated();
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== REQUEST [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
#endif
}
else
{
// TODO: log this illegal request
}
}
// -----------------------------
// ----------- PIECE -----------
// -----------------------------
void peer_connection::on_piece(int received)
{
if (m_recv_pos <= 9)
// only received protocol data
m_statistics.received_bytes(0, received);
else if (m_recv_pos - received >= 9)
// only received payload data
m_statistics.received_bytes(received, 0);
else
{
// received a bit of both
assert(m_recv_pos - received < 9);
assert(m_recv_pos > 9);
assert(9 - (m_recv_pos - received) <= 9);
m_statistics.received_bytes(
m_recv_pos - 9
, 9 - (m_recv_pos - received));
}
if (m_recv_pos < m_packet_size) return;
const char* ptr = &m_recv_buffer[1];
int index = detail::read_int(ptr);
if (index < 0 || index >= m_torrent->torrent_file().num_pieces())
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece index invalid\n";
#endif
throw protocol_error("invalid piece index in piece message");
}
int offset = detail::read_int(ptr);
int len = m_packet_size - 9;
if (offset < 0)
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " offset < 0\n";
#endif
throw protocol_error("offset < 0 in piece message");
}
if (offset + len > m_torrent->torrent_file().piece_size(index))
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains more data than the piece size\n";
#endif
throw protocol_error("piece message contains more data than the piece size");
}
// TODO: make sure that len is == block_size or less only
// if its's the last block.
if (offset % m_torrent->block_size() != 0)
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unaligned offset\n";
#endif
throw protocol_error("piece message contains unaligned offset");
}
/*
piece_block req = m_download_queue.front();
if (req.piece_index != index)
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unrequested index\n";
#endif
return false;
}
if (req.block_index != offset / m_torrent->block_size())
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unrequested offset\n";
#endif
return false;
}
*/
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== PIECE [ piece: " << index << " | s: " << offset << " | l: " << len << " ]\n";
#endif
piece_picker& picker = m_torrent->picker();
piece_block block_finished(index, offset / m_torrent->block_size());
std::deque<piece_block>::iterator b
= std::find(
m_download_queue.begin()
, m_download_queue.end()
, block_finished);
if (b != m_download_queue.end())
{
// pop the request that just finished
// from the download queue
m_download_queue.erase(b);
}
else
{
// TODO: cancel the block from the
// peer that has taken over it.
}
// if the block we got is already finished, then ignore it
if (picker.is_finished(block_finished)) return;
m_torrent->filesystem().write(&m_recv_buffer[9], index, offset, len);
picker.mark_as_finished(block_finished, m_peer_id);
m_torrent->get_policy().block_finished(*this, block_finished);
// did we just finish the piece?
if (picker.is_piece_finished(index))
{
bool verified = m_torrent->verify_piece(index);
if (verified)
{
m_torrent->announce_piece(index);
}
else
{
m_torrent->piece_failed(index);
}
m_torrent->get_policy().piece_finished(index, verified);
}
}
// -----------------------------
// ---------- CANCEL -----------
// -----------------------------
void peer_connection::on_cancel(int received)
{
if (m_packet_size != 13)
throw protocol_error("'cancel' message size != 13");
m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return;
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);
std::deque<peer_request>::iterator i
= std::find(m_requests.begin(), m_requests.end(), r);
if (i != m_requests.end())
{
m_requests.erase(i);
}
if (!has_data() && m_added_to_selector)
{
m_added_to_selector = false;
m_selector.remove_writable(m_socket);
}
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== CANCEL [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
#endif
}
// -----------------------------
// ------ EXTENSION LIST -------
// -----------------------------
void peer_connection::on_extension_list(int received)
{ {
if (m_packet_size > 100 * 1024) if (m_packet_size > 100 * 1024)
{ {
@ -459,7 +685,7 @@ namespace libtorrent
throw protocol_error("'extensions' message size > 100kB"); throw protocol_error("'extensions' message size > 100kB");
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false; if (m_recv_pos < m_packet_size) return;
try try
{ {
@ -484,219 +710,48 @@ namespace libtorrent
{ {
throw protocol_error("'extensions' packet contains incorrect types"); throw protocol_error("'extensions' packet contains incorrect types");
} }
break;
} }
// -----------------------------
// --------- EXTENDED ----------
// -----------------------------
// *************** REQUEST *************** void peer_connection::on_extended(int received)
case msg_request:
{ {
if (m_packet_size != 13)
throw protocol_error("'request' message size != 13");
m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false;
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);
// make sure this request
// is legal and taht the peer
// is not choked
if (r.piece >= 0
&& r.piece < m_torrent->torrent_file().num_pieces()
&& r.start >= 0
&& r.start < m_torrent->torrent_file().piece_size(r.piece)
&& r.length > 0
&& r.length + r.start < m_torrent->torrent_file().piece_size(r.piece)
&& !m_choked
&& m_peer_interested)
bool peer_connection::dispatch_message(int received)
{ {
m_requests.push_back(r); assert(m_recv_pos >= received);
send_buffer_updated(); assert(m_recv_pos > 0);
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== REQUEST [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n"; int packet_type = m_recv_buffer[0];
#endif if (packet_type < 0
} || packet_type >= num_supported_messages
else || m_message_handler[packet_type] == 0)
{ {
// TODO: log this illegal request
// if the only error is that the
// peer is choked, it may not be a
// mistake
}
break;
}
// *************** PIECE ***************
case msg_piece:
{
if (m_recv_pos <= 9)
// only received protocol data
m_statistics.received_bytes(0, received);
else if (m_recv_pos - received >= 9)
// only received payload data
m_statistics.received_bytes(received, 0);
else
{
// received a bit of both
assert(m_recv_pos - received < 9);
assert(m_recv_pos > 9);
assert(9 - (m_recv_pos - received) <= 9);
m_statistics.received_bytes(
m_recv_pos - 9
, 9 - (m_recv_pos - received));
}
if (m_recv_pos < m_packet_size) return false;
const char* ptr = &m_recv_buffer[1];
int index = detail::read_int(ptr);
if (index < 0 || index >= m_torrent->torrent_file().num_pieces())
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece index invalid\n";
#endif
throw protocol_error("invalid piece index in piece message");
}
int offset = detail::read_int(ptr);
int len = m_packet_size - 9;
if (offset < 0)
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " offset < 0\n";
#endif
throw protocol_error("offset < 0 in piece message");
}
if (offset + len > m_torrent->torrent_file().piece_size(index))
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains more data than the piece size\n";
#endif
throw protocol_error("piece message contains more data than the piece size");
}
// TODO: make sure that len is == block_size or less only
// if its's the last block.
if (offset % m_torrent->block_size() != 0)
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unaligned offset\n";
#endif
throw protocol_error("piece message contains unaligned offset");
}
/*
piece_block req = m_download_queue.front();
if (req.piece_index != index)
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unrequested index\n";
#endif
return false;
}
if (req.block_index != offset / m_torrent->block_size())
{
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " piece packet contains unrequested offset\n";
#endif
return false;
}
*/
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== PIECE [ piece: " << index << " | s: " << offset << " | l: " << len << " ]\n";
#endif
piece_picker& picker = m_torrent->picker();
piece_block block_finished(index, offset / m_torrent->block_size());
std::deque<piece_block>::iterator b
= std::find(
m_download_queue.begin()
, m_download_queue.end()
, block_finished);
if (b != m_download_queue.end())
{
// pop the request that just finished
// from the download queue
m_download_queue.erase(b);
}
else
{
// TODO: cancel the block from the
// peer that has taken over it.
}
if (picker.is_finished(block_finished)) break;
m_torrent->filesystem().write(&m_recv_buffer[9], index, offset, len);
picker.mark_as_finished(block_finished, m_peer_id);
m_torrent->get_policy().block_finished(*this, block_finished);
// did we just finish the piece?
if (picker.is_piece_finished(index))
{
bool verified = m_torrent->verify_piece(index);
if (verified)
{
m_torrent->announce_piece(index);
}
else
{
m_torrent->piece_failed(index);
}
m_torrent->get_policy().piece_finished(index, verified);
}
break;
}
// *************** CANCEL ***************
case msg_cancel:
{
if (m_packet_size != 13)
throw protocol_error("'cancel' message size != 13");
m_statistics.received_bytes(0, received);
if (m_recv_pos < m_packet_size) return false;
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);
std::deque<peer_request>::iterator i
= std::find(m_requests.begin(), m_requests.end(), r);
if (i != m_requests.end())
{
m_requests.erase(i);
}
if (!has_data() && m_added_to_selector)
{
m_added_to_selector = false;
m_selector.remove_writable(m_socket);
}
#ifndef NDEBUG
(*m_logger) << m_socket->sender().as_string() << " <== CANCEL [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
#endif
break;
}
default:
throw protocol_error("unknown message id"); throw protocol_error("unknown message id");
} }
assert(m_message_handler[packet_type] != 0);
// call the correct handler for this packet type
(this->*m_message_handler[packet_type])(received);
if (m_recv_pos < m_packet_size) return false;
assert(m_recv_pos == m_packet_size); assert(m_recv_pos == m_packet_size);
return true; return true;
} }
@ -820,7 +875,7 @@ namespace libtorrent
for (int i = 0; i < num_supported_extensions; ++i) for (int i = 0; i < num_supported_extensions; ++i)
{ {
entry msg_index(entry::int_t); entry msg_index(entry::int_t);
msg_index.integer() = msg_extensions + 1 + i; msg_index.integer() = i;
extension_list.dict()[extension_names[i]] = msg_index; extension_list.dict()[extension_names[i]] = msg_index;
} }
@ -832,7 +887,7 @@ namespace libtorrent
const int msg_size_pos = m_send_buffer.size(); const int msg_size_pos = m_send_buffer.size();
m_send_buffer.resize(msg_size_pos + 4); m_send_buffer.resize(msg_size_pos + 4);
m_send_buffer.push_back(msg_extensions); m_send_buffer.push_back(msg_extension_list);
bencode(std::back_inserter(m_send_buffer), extension_list); bencode(std::back_inserter(m_send_buffer), extension_list);
@ -919,11 +974,11 @@ namespace libtorrent
int diff = share_diff(); int diff = share_diff();
if (diff > 2*m_torrent->block_size()) if (diff > 2*m_torrent->block_size() || m_torrent->is_seed())
{ {
// if we have downloaded more than one piece more // if we have downloaded more than one piece more
// than we have uploaded, have an unlimited // than we have uploaded OR if we are a seed
// upload rate // have an unlimited upload rate
m_send_quota_limit = -1; m_send_quota_limit = -1;
} }
else else

View File

@ -368,7 +368,35 @@ namespace libtorrent
, m_torrent->end() , m_torrent->end()
, m_available_free_upload); , m_available_free_upload);
if (m_max_uploads != -1)
if (m_torrent->is_seed())
{
// make sure we have enough
// unchoked peers
while (m_num_unchoked < m_max_uploads)
{
peer* p = 0;
for (std::vector<peer>::iterator i = m_peers.begin();
i != m_peers.end();
++i)
{
peer_connection* c = i->connection;
if (c == 0) continue;
if (!c->is_choked()) continue;
if (!c->is_peer_interested()) continue;
// TODO: add some more criterion here. Maybe the peers
// that have less should be promoted? (to allow them to trade)
p = &(*i);
}
if (p == 0) break;
p->connection->unchoke();
p->last_optimistically_unchoked = boost::posix_time::second_clock::local_time();
++m_num_unchoked;
}
}
else if (m_max_uploads != -1)
{ {
// make sure we don't have too many // make sure we don't have too many
// unchoked peers // unchoked peers

View File

@ -497,6 +497,11 @@ namespace libtorrent
} }
catch(std::exception& e) catch(std::exception& e)
{ {
if (m_alerts.should_post(alert::debug))
{
m_alerts.post_alert(
peer_error_alert(p->second->get_peer_id(), e.what()));
}
// the connection wants to disconnect for some reason, remove it // the connection wants to disconnect for some reason, remove it
// from the connection-list // from the connection-list
m_selector.remove(*i); m_selector.remove(*i);

View File

@ -700,7 +700,7 @@ namespace libtorrent
<< m_torrent_file.trackers()[m_currently_trying_tracker].url << m_torrent_file.trackers()[m_currently_trying_tracker].url
<< "\" timed out"; << "\" timed out";
torrent_handle self(&m_ses, 0, m_torrent_file.info_hash()); torrent_handle self(&m_ses, 0, m_torrent_file.info_hash());
m_ses.m_alerts.post_alert(tracker_alert( self, s.str())); m_ses.m_alerts.post_alert(tracker_alert(self, s.str()));
} }
// TODO: increase the retry_delay for // TODO: increase the retry_delay for
// each failed attempt on the same tracker! // each failed attempt on the same tracker!

View File

@ -319,6 +319,8 @@ namespace libtorrent
p.load_balancing = peer->total_free_upload(); p.load_balancing = peer->total_free_upload();
p.download_queue_length = peer->download_queue().size();
boost::optional<piece_block_progress> ret = peer->downloading_piece(); boost::optional<piece_block_progress> ret = peer->downloading_piece();
if (ret) if (ret)
{ {