*** empty log message ***

This commit is contained in:
Arvid Norberg 2004-01-03 03:22:53 +00:00
parent 3033f16f47
commit 97b387b196
6 changed files with 157 additions and 28 deletions

View File

@ -58,10 +58,14 @@
<li><a class="reference" href="#simple-client" id="id34" name="id34">simple client</a></li>
</ul>
</li>
<li><a class="reference" href="#fast-resume" id="id35" name="id35">fast resume</a><ul>
<li><a class="reference" href="#file-format" id="id36" name="id36">file format</a></li>
</ul>
</li>
<li><a class="reference" href="#feedback" id="id35" name="id35">Feedback</a></li>
<li><a class="reference" href="#aknowledgements" id="id36" name="id36">Aknowledgements</a></li>
</ul>
</li>
<li><a class="reference" href="#feedback" id="id37" name="id37">Feedback</a></li>
<li><a class="reference" href="#aknowledgements" id="id38" name="id38">Aknowledgements</a></li>
</ul>
</div>
<div class="section" id="introduction">
@ -94,13 +98,14 @@ thread-safe library interface. (i.e. There's no way for the user to cause a dead
<li>piece-wise file allocation</li>
<li>tries to maintain a 1:1 share ratio between all peers but also shifts free
download to peers as free upload. To maintain a global 1:1 ratio.</li>
<li>fast resume support, a way to get rid of the costly piece check at the start
of a resumed torrent. Saves the storage state in a separate fast-resume file.</li>
</ul>
</blockquote>
<p>Functions that are yet to be implemented:</p>
<blockquote>
<ul class="simple">
<li>choke/unchoke policy for seed-mode</li>
<li>fast resume</li>
<li>number of connections limit</li>
<li>better handling of peers that send bad data</li>
<li>ip-filters</li>
@ -170,6 +175,11 @@ class session: public boost::noncopyable
session(int listen_port);
torrent_handle add_torrent(const torrent_info&amp; t, const std::string&amp; save_path);
torrent_handle add_torrent(
const torrent_info&amp; t
, const std::string&amp; save_path
, const std::vector&lt;char&gt;&amp; resume_data);
void remove_torrent(const torrent_handle&amp; h);
void set_http_settings(const http_settings&amp; settings);
@ -187,6 +197,9 @@ object representing the information found in the torrent file and the path where
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
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
<tt class="literal"><span class="pre">torrent_handle::write_resume_data()</span></tt>. See <a class="reference" href="#fast-resume">fast resume</a>.</p>
<p><tt class="literal"><span class="pre">remove_torrent()</span></tt> will close all peer connections associated with the torrent and tell
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
@ -506,6 +519,8 @@ struct torrent_handle
const torrent_info&amp; get_torrent_info();
bool is_valid();
void write_resume_data(std::vector&lt;char&gt;&amp; data);
boost::filsystem::path save_path() const;
void set_max_uploads(int max_uploads);
@ -525,10 +540,12 @@ was started.</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">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 hpw fast-resume works, see <a class="reference" href="#fast-resume">fast resume</a>.</p>
<div class="section" id="status">
<h3><a class="toc-backref" href="#id15" 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
torrent. If the <tt class="literal"><span class="pre">torrent_handle</span></tt> is invalid, it will throw <tt class="literal"><span class="pre">invalid_handle</span></tt> 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>
<pre class="literal-block">
struct torrent_status
@ -604,7 +621,7 @@ data), these counters ignore any protocol overhead.</p>
the pieces we don't have.</p>
<p><tt class="literal"><span class="pre">download_rate</span></tt> and <tt class="literal"><span class="pre">upload_rate</span></tt> are the total rates for all peers for this
torrent. These will usually have better precision than summing the rates from
all peers.</p>
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>
</div>
<div class="section" id="get-download-queue">
@ -643,7 +660,7 @@ may pass then.</p>
<h3><a class="toc-backref" href="#id17" 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
with one entry for each peer connected to this torrent, given the handle is valid. If the
<tt class="literal"><span class="pre">torrent_handle</span></tt> 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
the vector contains information about that particular peer. It contains the following
fields:</p>
<pre class="literal-block">
@ -717,8 +734,8 @@ the total number of bytes in this block.</p>
<div class="section" id="get-torrent-info">
<h3><a class="toc-backref" href="#id18" 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.
This reference is valid as long as the <tt class="literal"><span class="pre">torrent_handle</span></tt> is valid, no longer. If the
<tt class="literal"><span class="pre">torrent_handle</span></tt> is invalid, <tt class="literal"><span class="pre">invalid_handle</span></tt> exception will be thrown.</p>
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>
<div class="section" id="is-valid">
<h3><a class="toc-backref" href="#id19" name="is-valid">is_valid()</a></h3>
@ -922,7 +939,7 @@ public:
here's a complete list with description.</p>
<div class="section" id="invalid-handle">
<h3><a class="toc-backref" href="#id27" name="invalid-handle">invalid_handle</a></h3>
<p>This exception is thrown when querying information from a <tt class="literal"><span class="pre">torrent_handle</span></tt> 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>
<pre class="literal-block">
struct invalid_handle: std::exception
@ -1093,14 +1110,49 @@ int main(int argc, char* argv[])
</pre>
</div>
</div>
<div class="section" id="fast-resume">
<h2><a class="toc-backref" href="#id35" name="fast-resume">fast resume</a></h2>
<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
<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
to disk and use it when resuming the torrent. libtorrent will not check the piece hashes
then, and rely on the information given in the fast-resume data. The fast-resume data
also contains information about which bocks in the unfinished pieces were downloaded, so
it will not have to start from scratch on the partially downloaded pieces.</p>
<p>To use the fast-resume data you simply give it to <tt class="literal"><span class="pre">session::add_torrent()</span></tt>, and it
will skip the time consuming checks. It may have to do the checking anyway, if the
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>
<div class="section" id="file-format">
<h3><a class="toc-backref" href="#id36" name="file-format">file format</a></h3>
<p>The format of the fast-resume data is as follows, given that all
4-byte integers are stored as big-endian:</p>
<pre class="literal-block">
20 bytes, the info_hash for the torrent
4 bytes, the number of allocated slots in the storage
for each slot
4 bytes, piece index in this slot,
-1 means there's no storage for the slot
-2 means there's no piece at this slot, it's free
4 bytes, the number of blocks per piece.
this must be piece_size / 16k or 1 if piece_size is &lt; 16k
and can be 128 at max.
4 bytes, the number of unfinished pieces
for each unfinished piece
4 bytes, index of the unfinished piece
blocks_per_piece / 32 bytes, the bitmask describing which
blocks are finished in this piece.
</pre>
</div>
</div>
</div>
<div class="section" id="feedback">
<h1><a class="toc-backref" href="#id35" name="feedback">Feedback</a></h1>
<h1><a class="toc-backref" href="#id37" 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>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 class="section" id="aknowledgements">
<h1><a class="toc-backref" href="#id36" name="aknowledgements">Aknowledgements</a></h1>
<h1><a class="toc-backref" href="#id38" name="aknowledgements">Aknowledgements</a></h1>
<p>Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003</p>
<p>Contributions by Magnus Jonsson</p>
<p>Thanks to Reimond Retz for bugfixes, suggestions and testing</p>

View File

@ -43,6 +43,8 @@ The current state includes the following features:
* piece-wise file allocation
* tries to maintain a 1:1 share ratio between all peers but also shifts free
download to peers as free upload. To maintain a global 1:1 ratio.
* fast resume support, a way to get rid of the costly piece check at the start
of a resumed torrent. Saves the storage state in a separate fast-resume file.
__ http://home.elp.rr.com/tur/multitracker-spec.txt
.. _Azureus: http://azureus.sourceforge.net
@ -50,7 +52,6 @@ __ http://home.elp.rr.com/tur/multitracker-spec.txt
Functions that are yet to be implemented:
* choke/unchoke policy for seed-mode
* fast resume
* number of connections limit
* better handling of peers that send bad data
* ip-filters
@ -134,6 +135,11 @@ The ``session`` class has the following synopsis::
session(int listen_port);
torrent_handle add_torrent(const torrent_info& t, const std::string& save_path);
torrent_handle add_torrent(
const torrent_info& t
, const std::string& save_path
, const std::vector<char>& resume_data);
void remove_torrent(const torrent_handle& h);
void set_http_settings(const http_settings& settings);
@ -152,6 +158,10 @@ 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
if the torrent already exists in the session.
The optional last parameter, ``resume_data`` 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
``torrent_handle::write_resume_data()``. See `fast resume`_.
``remove_torrent()`` will close all peer connections associated with the torrent and tell
the tracker that we've stopped participating in the swarm.
@ -515,6 +525,8 @@ Its declaration looks like this::
const torrent_info& get_torrent_info();
bool is_valid();
void write_resume_data(std::vector<char>& data);
boost::filsystem::path save_path() const;
void set_max_uploads(int max_uploads);
@ -538,11 +550,14 @@ was started.
``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.
``write_resume_data()`` takes a non-const reference to a char-vector, that vector will be filled
with the fast-resume data. For more information about hpw fast-resume works, see `fast resume`_.
status()
~~~~~~~~
``status()`` will return a structure with information about the status of this
torrent. If the ``torrent_handle`` is invalid, it will throw ``invalid_handle`` exception.
torrent. If the torrent_handle_ is invalid, it will throw invalid_handle_ exception.
It contains the following fields::
struct torrent_status
@ -662,7 +677,7 @@ get_peer_info()
``get_peer_info()`` 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
``torrent_handle`` is invalid, it will throw ``invalid_handle`` exception. Each entry in
torrent_handle_ is invalid, it will throw ``invalid_handle`` exception. Each entry in
the vector contains information about that particular peer. It contains the following
fields::
@ -747,8 +762,8 @@ get_torrent_info()
~~~~~~~~~~~~~~~~~~
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.
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.
is_valid()
@ -976,7 +991,7 @@ here's a complete list with description.
invalid_handle
~~~~~~~~~~~~~~
This exception is thrown when querying information from a ``torrent_handle`` that hasn't
This exception is thrown when querying information from a torrent_handle_ that hasn't
been initialized or that has become invalid.
::
@ -1162,6 +1177,43 @@ This is a simple client. It doesn't have much output to keep it simple::
}
fast resume
-----------
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
``torrent_handle::write_resume_data()`` on torrent_handle_. You can then save this data
to disk and use it when resuming the torrent. libtorrent will not check the piece hashes
then, and rely on the information given in the fast-resume data. The fast-resume data
also contains information about which bocks in the unfinished pieces were downloaded, so
it will not have to start from scratch on the partially downloaded pieces.
To use the fast-resume data you simply give it to ``session::add_torrent()``, and it
will skip the time consuming checks. It may have to do the checking anyway, if the
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.
file format
~~~~~~~~~~~
The format of the fast-resume data is as follows, given that all
4-byte integers are stored as big-endian::
20 bytes, the info_hash for the torrent
4 bytes, the number of allocated slots in the storage
for each slot
4 bytes, piece index in this slot,
-1 means there's no storage for the slot
-2 means there's no piece at this slot, it's free
4 bytes, the number of blocks per piece.
this must be piece_size / 16k or 1 if piece_size is < 16k
and can be 128 at max.
4 bytes, the number of unfinished pieces
for each unfinished piece
4 bytes, index of the unfinished piece
blocks_per_piece / 32 bytes, the bitmask describing which
blocks are finished in this piece.
Feedback
========

View File

@ -79,7 +79,7 @@ namespace libtorrent
// reads an integer from a byte stream
// in big endian byte order and converts
// it to native endianess
template<class InIt>
template <class InIt>
unsigned int read_uint(InIt& start)
{
unsigned int val = 0;
@ -90,15 +90,23 @@ namespace libtorrent
return val;
}
template<class InIt>
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;
}
// reads an integer to a byte stream
// and converts it from native endianess
template<class OutIt>
template <class OutIt>
void write_uint(unsigned int val, OutIt& start)
{
*start = static_cast<unsigned char>((val >> 24) & 0xff); ++start;
@ -107,10 +115,17 @@ namespace libtorrent
*start = static_cast<unsigned char>((val) & 0xff); ++start;
}
template<class OutIt>
template <class OutIt>
inline void write_int(int val, OutIt& start)
{
write_uint(reinterpret_cast<unsigned int&>(val), start);
write_uint(static_cast<unsigned int>(val), start);
}
template <class OutIt>
inline void write_uchar(unsigned char val, OutIt& start)
{
*start = static_cast<char>(val);
++start;
}
}

View File

@ -173,7 +173,7 @@ namespace libtorrent
detail::session_impl* m_ses;
detail::checker_impl* m_chk;
sha1_hash m_info_hash; // should be replaced with a torrent*?
sha1_hash m_info_hash;
};

View File

@ -894,12 +894,16 @@ namespace libtorrent
const std::vector<char>& data = *rd;
if (data.size() < 3 * 4) return;
if (data.size() < 20 + 3 * 4) return;
std::vector<char>::const_iterator ptr = data.begin();
sha1_hash info_hash;
for (int i = 0; i < 20; ++i) info_hash[i] = read_uchar(ptr);
if (info.info_hash() != info_hash) return;
int num_slots = detail::read_int(ptr);
if (num_slots < 0) return;
if (data.size() < (3 + num_slots) * 4) return;
if (data.size() < 20 + (3 + num_slots) * 4) return;
tmp_pieces.reserve(num_slots);
for (int i = 0; i < num_slots; ++i)
@ -911,12 +915,12 @@ namespace libtorrent
}
int num_blocks_per_piece = read_int(ptr);
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 0)
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1)
return;
int num_unfinished = read_int(ptr);
if (num_unfinished < 0) return;
if (data.size() != (1 + num_slots + 2 + num_unfinished * (num_blocks_per_piece / 32 + 1)) * 4)
if (data.size() != 20 + (1 + num_slots + 2 + num_unfinished * (num_blocks_per_piece / 32 + 1)) * 4)
return;
tmp_unfinished.reserve(num_unfinished);

View File

@ -186,7 +186,13 @@ namespace libtorrent
// TODO: write file header
// TODO: write modification-dates for all files
// TODO: write info hash
for (sha1_hash::const_iterator i = m_info_hash.begin();
i != m_info_hash.end();
++i)
{
detail::write_uchar(*i, out);
}
// number of slots
int num_slots = piece_index.size();