From 97b387b196715ee7618172a20716c57edf8922f5 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 3 Jan 2004 03:22:53 +0000 Subject: [PATCH] *** empty log message *** --- docs/index.html | 74 ++++++++++++++++++++++---- docs/index.rst | 64 +++++++++++++++++++--- include/libtorrent/peer_connection.hpp | 25 +++++++-- include/libtorrent/torrent_handle.hpp | 2 +- src/session.cpp | 12 +++-- src/torrent_handle.cpp | 8 ++- 6 files changed, 157 insertions(+), 28 deletions(-) diff --git a/docs/index.html b/docs/index.html index 990829102..0dcd1d946 100755 --- a/docs/index.html +++ b/docs/index.html @@ -58,10 +58,14 @@
  • simple client
  • +
  • fast resume
  • -
  • Feedback
  • -
  • Aknowledgements
  • + + +
  • Feedback
  • +
  • Aknowledgements
  • @@ -94,13 +98,14 @@ thread-safe library interface. (i.e. There's no way for the user to cause a dead
  • 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.
  • 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
    • @@ -170,6 +175,11 @@ class session: public boost::noncopyable 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); @@ -187,6 +197,9 @@ object representing the information found in the torrent file and the path where 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.

      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& 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); @@ -525,10 +540,12 @@ was started.

      info_hash() returns the info hash for the torrent.

      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
      @@ -604,7 +621,7 @@ data), these counters ignore any protocol overhead.

      the pieces we don't have.

      download_rate and upload_rate are the total rates for all peers for this torrent. These will usually have better precision than summing the rates from -all peers.

      +all peers. The rates are given as the number of bytes per second.

      total_done is the total number of bytes of the file(s) that we have.

      @@ -643,7 +660,7 @@ may pass then.

      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:

      @@ -717,8 +734,8 @@ the total number of bytes in this block.

      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()

      @@ -922,7 +939,7 @@ public: 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.

       struct invalid_handle: std::exception
      @@ -1093,14 +1110,49 @@ int main(int argc, char* argv[])
       
      +
      +

      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

      +

      Feedback

      There's a mailing list.

      You can usually find me as hydri in #btports @ irc.freenode.net.

      -

      Aknowledgements

      +

      Aknowledgements

      Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003

      Contributions by Magnus Jonsson

      Thanks to Reimond Retz for bugfixes, suggestions and testing

      diff --git a/docs/index.rst b/docs/index.rst index a7ed60f2a..638c5065b 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -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& 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& 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 ======== diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 2d85e95b0..663d4ad6a 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -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 + template unsigned int read_uint(InIt& start) { unsigned int val = 0; @@ -90,15 +90,23 @@ namespace libtorrent return val; } - template + template inline int read_int(InIt& start) { return static_cast(read_uint(start)); } + template + inline unsigned char read_uchar(InIt& start) + { + unsigned char ret = static_cast(*start); + ++start; + return ret; + } + // reads an integer to a byte stream // and converts it from native endianess - template + template void write_uint(unsigned int val, OutIt& start) { *start = static_cast((val >> 24) & 0xff); ++start; @@ -107,10 +115,17 @@ namespace libtorrent *start = static_cast((val) & 0xff); ++start; } - template + template inline void write_int(int val, OutIt& start) { - write_uint(reinterpret_cast(val), start); + write_uint(static_cast(val), start); + } + + template + inline void write_uchar(unsigned char val, OutIt& start) + { + *start = static_cast(val); + ++start; } } diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 11c997325..6ca46e103 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -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; }; diff --git a/src/session.cpp b/src/session.cpp index 72a4f8c90..5836c6d17 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -894,12 +894,16 @@ namespace libtorrent const std::vector& data = *rd; - if (data.size() < 3 * 4) return; + if (data.size() < 20 + 3 * 4) return; std::vector::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); diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 4ca3f8daf..d77dad606 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -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();