From 086dbd40fe1030c231113f4295467c55826f7172 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 20 Nov 2003 19:58:29 +0000 Subject: [PATCH] added support for comments and creation date in torrent files. fixed bug in url_handler. --- docs/index.html | 11 + docs/index.rst | 700 +++++++++++++++++++++++++ include/libtorrent/peer_connection.hpp | 2 +- include/libtorrent/torrent.hpp | 5 +- include/libtorrent/torrent_handle.hpp | 8 +- include/libtorrent/torrent_info.hpp | 22 +- src/torrent.cpp | 12 + src/torrent_handle.cpp | 7 + src/torrent_info.cpp | 19 + 9 files changed, 782 insertions(+), 4 deletions(-) create mode 100755 docs/index.rst diff --git a/docs/index.html b/docs/index.html index fb5c2bbbd..e392fd75f 100755 --- a/docs/index.html +++ b/docs/index.html @@ -410,6 +410,9 @@ public: std::size_t num_pieces() const; const sha1_hash& info_hash() const; const std::stirng& name() const; + const std::string& comment() const; + boost::posiz_time::ptime creation_date() const; + void print(std::ostream& os) const; @@ -486,6 +489,14 @@ piece and info_hash() returns the 20-bytes sha1-hash for the info-secti torrent file. For more information on the sha1_hash, see the big_number class.

+

+comment() returns the comment associated with the torrent. If there's no comment, +it will return an empty string. creation_date() returns a +boost::posix_time::ptime +object, representing the time when this torrent file was created. If there's no timestamp +in the torrent file, this will return a date of january 1:st 1970. +

+

torrent_handle

diff --git a/docs/index.rst b/docs/index.rst new file mode 100755 index 000000000..df9a31463 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,700 @@ +========== +libtorrent +========== + + +=================== =============== +`sourceforge page`_ `mailing list`_ +=================== =============== + +.. _sourceforge page: http://www.sourceforge.net/projects/libtorrent +.. _mailing list: http://lists.sourceforge.net/lists/listinfo/libtorrent-discus + +.. contents:: + +introduction +============ + +libtorrent is a C++ library that aims to be a good alternative to all the +`other bittorrent implementations`__ around. It is a +library and not a full featured client, although it comes with a working +example client. + +__ links.html + +The main goals of libtorrent are: + + * to be cpu efficient + * to be memory efficient + * to be very easy to use + +libtorrent is not finished. It is an ongoing project (including this documentation). +The current state includes the following features: + + * multitracker extension support (as `described by TheShadow`_) + * serves multiple torrents on a single port and a single thread + * supports http proxies and proxy authentication + * gzipped tracker-responses + * piece picking on block-level (as opposed to piece-level) like in Azureus_ + * queues torrents for file check, instead of checking all of them in parallel. + * uses separate threads for checking files and for main downloader, with a fool-proof + thread-safe library interface. (i.e. There's no way for the user to cause a deadlock). + * can limit the upload bandwidth usage + +.. _`described by TheShadow`: http://home.elp.rr.com/tur/multitracker-spec.txt +.. _Azureus: http://azureus.sourceforge.net + +Functions that are yet to be implemented: + + * optimistic unchoke + * Snubbing + * end game mode + * new allocation model + * fast resume + * file-level piece priority + * a good upload speed cap + +libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread, +boost.filesystem and various other boost libraries and zlib. + +libtorrent has been successfully compiled and tested on: + + * Cygwin GCC 3.3.1 + * Windows 2000 vc7.1 + * Linux x86 (debian) GCC 3.0 + + +building +======== + +To build libtorrent you need boost_ and bjam installed. +Then you can use ``bjam`` to build libtorrent. + +.. _boost: http://www.boost.org + +To make bjam work, you need to set the environment variable ``BOOST_ROOT`` to the +path where boost is installed (e.g. c:\boost_1_30_2 on windows). Then you can just run +``bjam`` in the libtorrent directory. + +The Jamfile doesn't work yet. On unix-systems you can use the makefile however. You +first have to build boost.thread and boost.filesystem. You do this by, in the directory +'boost-1.30.2/tools/build/jam_src' run the build script ``./build.sh``. This should +produce at least one folder with the 'bin' prefix (and the rest of the name describes +your platform). Put the files in that folder somewhere in your path. + +You can then invoke ``bjam`` in the directories 'boost-1.30.2/libs/thread/build' and +'boost-1.30.2/libs/filesystem/build'. That will produce the needed libraries. Put these +libraries in the libtorrent root directory. You then have to modify the makefile to use +you prefered compiler and to have the correct path to your boost istallation. + +Then the makefile should be able to do the rest. + +When building (with boost 1.30.2) on linux and solaris however, I found that I had to make the following +modifications to the boost.date-time library. In the file: +'boost-1.30.2/boost/date_time/gregorian_calendar.hpp' line 59. Prepend 'boost/date_time/' +to the include path. + +And the second modification was in the file: +'boost-1.30.2/boost/date_time/microsec_time_clock.hpp' add the following include at the top +of the file:: + + #include "boost/cstdint.hpp" + +In developer studio, you may have to set the compiler options "force conformance in for +loop scope" and "treat wchar_t as built-in type" to Yes. + +TODO: more detailed build instructions. + + + + + +using +===== + +The interface of libtorrent consists of a few classes. The main class is +the ``session``, it contains the main loop that serves all torrents. + + + +session +------- + +The ``session`` class has the following synopsis:: + + class session: public boost::noncopyable + { + session(int listen_port, const std::string& fingerprint = std::string()); + + torrent_handle add_torrent(const torrent_info& t, const std::string& save_path); + void remove_torrent(const torrent_handle& h); + + void set_http_settings(const http_settings& settings); + void set_upload_rate_limit(int bytes_per_second); + }; + +Once it's created, it will spawn the main thread that will do all the work. +The main thread will be idle as long it doesn't have any torrents to participate in. +You add torrents through the ``add_torrent()``-function where you give an +object representing the information found in the torrent file and the path where you +want to save the files. The ``save_path`` will be prepended to the directory- +structure in the torrent-file. + +``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 +for checking, being checked or downloading) ``add_torrent()`` will throw +``duplicate_torrent`` which derives from ``std::exception``. + +``fingerprint`` is a short string that will be used in the peer_id to +identify the client. If the string is longer than 7 characters it will +be trimmed down to 7 characters. The default is an empty string. + +``set_upload_rate_limit()`` set the maximum number of bytes allowed to be +sent to peers per second. This bandwidth is distributed among all the peers. If +you don't want to limit upload rate, you can set this to -1 (the default). + +The destructor of session will notify all trackers that our torrents has been shut down. +If some trackers are down, they will timout. All this before the destructor of session +returns. So, it's adviced that any kind of interface (such as windows) are closed before +destructing the sessoin object. Because it can take a few second for it to finish. The +timeout can be set with ``set_http_settings()``. + +How to parse a torrent file and create a ``torrent_info`` object is described below. + +The torrent_handle_ returned by ``add_torrent`` can be used to retrieve information +about the torrent's progress, its peers etc. It is also used to abort a torrent. + +The constructor takes a listen port as argument, if the given port is busy it will +increase the port number by one and try again. If it still fails it will continue +increasing the port number until it succeeds or has failed 9 ports. *This will +change in the future to give more control of the listen-port.* + + + + +parsing torrent files +--------------------- + +The torrent files are bencoded__. There are two functions in libtorrent that can encode and decode +bencoded data. They are:: + + template entry bdecode(InIt start, InIt end); + template void bencode(OutIt out, const entry& e); + +__ http://bitconjurer.org/BitTorrent/protocol.html + + +The ``entry`` class is the internal representation of the bencoded data +and it can be used to retreive information, an entry can also be build by +the program and given to ``bencode()`` to encode it into the ``OutIt`` +iterator. + +The ``OutIt`` and ``InIt`` are iterators +(``InputIterator_`` and ``OutputIterator_`` respectively). They +are templates and are usually instantiated as ``ostream_iterator_``, +``back_insert_iterator_`` or ``istream_iterator_``. These +functions will assume that the iterator refers to a character +(``char``). So, if you want to encode entry ``e`` into a buffer +in memory, you can do it like this:: + + std::vector buffer; + bencode(std::back_insert_iterator >(buf), e); + +.. _InputIterator: http://www.sgi.com/tech/stl/InputIterator.html +.. _OutputIterator: http://www.sgi.com/tech/stl/OutputIterator.html +.. _ostream_iterator: http://www.sgi.com/tech/stl/ostream_iterator.html +.. _back_insert_iterator: http://www.sgi.com/tech/stl/back_insert_iterator.html +.. _istream_iterator: http://www.sgi.com/tech/stl/istream_iterator.html + + +If you want to decode a torrent file from a buffer in memory, you can do it like this:: + + std::vector buffer; + // ... + entry e = bdecode(buf.begin(), buf.end()); + +Or, if you have a raw char buffer:: + + const char* buf; + // ... + entry e = bdecode(buf, buf + data_size); + +Now we just need to know how to retrieve information from the ``entry``. + + + + +entry +----- + +The ``entry`` class represents one node in a bencoded hierarchy. It works as a +variant type, it can be either a list, a dictionary (``std::map``), an integer +or a string. This is its synopsis:: + + class entry + { + public: + + typedef std::map dictionary_type; + typedef std::string string_type; + typedef std::vector list_type; + typedef implementation-defined integer_type; + + enum data_type + { + int_t, + string_t, + list_t, + dictionary_t, + undefined_t + }; + + data_type type() const; + + entry(); + entry(data_type t); + entry(const entry& e); + + void operator=(const entry& e); + + integer_type& integer() + const integer_type& integer() const; + string_type& string(); + const string_type& string() const; + list_type& list(); + const list_type& list() const; + dictionary_type& dict(); + const dictionary_type& dict() const; + + void print(std::ostream& os, int indent = 0) const; + }; + +The ``integer()``, ``string()``, ``list()`` and ``dict()`` functions +are accessorts that return the respecive type. If the ``entry`` object isn't of the +type you request, the accessor will throw ``type_error`` (which derives from +``std::runtime_error``). You can ask an ``entry`` for its type through the +``type()`` function. + +The ``print()`` function is there for debug purposes only. + +If you want to create an ``entry`` you give it the type you want it to have in its +constructor, and then use one of the non-const accessors to get a reference which you then +can assign the value you want it to have. + +The typical code to get info from a torrent file will then look like this:: + + entry torrent_file; + // ... + + const entry::dictionary_type& dict = torrent_file.dict(); + entry::dictionary_type::const_iterator i; + i = dict.find("announce"); + if (i != dict.end()) + { + std::string tracker_url= i->second.string(); + std::cout << tracker_url << "\n"; + } + +To make it easier to extract information from a torren file, the class ``torrent_info`` +exists. + +torrent_info +------------ + +The ``torrent_info`` has the following synopsis:: + + class torrent_info + { + public: + + torrent_info(const entry& torrent_file) + + typedef std::vector>file>::const_iterator file_iterator; + typedef std::vector::const_reverse_iterator reverse_file_iterator; + + file_iterator begin_files() const; + file_iterator end_files() const; + reverse_file_iterator rbegin_files() const; + reverse_file_iterator rend_files() const; + + std::size_t num_files() const; + const file& file_at(int index) const; + + const std::vector& trackers() const; + + int prioritize_tracker(int index); + + entry::integer_type total_size() const; + entry::integer_type piece_length() const; + std::size_t num_pieces() const; + const sha1_hash& info_hash() const; + const std::stirng& name() const; + const std::string& comment() const; + boost::posiz_time::ptime creation_date() const; + + + void print(std::ostream& os) const; + + entry::integer_type piece_size(unsigned int index) const; + const sha1_hash& hash_for_piece(unsigned int index) const; + }; + +This class will need some explanation. First of all, to get a list of all files +in the torrent, you can use ``begin_files()``, ``end_files()``, +``rbegin_files()`` and ``rend_files()``. These will give you standard vector +iterators with the type ``file``. + +:: + + struct file + { + std::string path; + std::string filename; + entry::integer_type size; + }; + +If you need index-access to files you can use the ``num_files()`` and ``file_at()`` +to access files using indices. + +The ``print()`` function is there for debug purposes only. It will print the info from +the torrent file to the given outstream. + +``name()`` returns the name of the torrent. + +The ``trackers()`` function will return a sorted vector of ``announce_entry``. +Each announce entry contains a string, which is the tracker url, and a tier index. The +tier index is the high-level priority. No matter which trackers that works or not, the +ones with lower tier will always be tried before the one with higher tier number. + +:: + + struct announce_entry + { + std::string url; + int tier; + }; + +The ``prioritize_tracker()`` is used internally to move a tracker to the front +of its tier group. i.e. It will never be moved pass a tracker with a different tier +number. For more information about how multiple trackers are dealt with, see the +specification_. + +.. _specification: http://home.elp.rr.com/tur/multitracker-spec.txt + + +``total_size()``, ``piece_length()`` and ``num_pieces()`` returns the total +number of bytes the torrent-file represents (all the files in it), the number of byte for +each piece and the total number of pieces, respectively. The difference between +``piece_size()`` and ``piece_length()`` is that ``piece_size()`` takes +the piece index as argument and gives you the exact size of that piece. It will always +be the same as ``piece_length()`` except in the case of the last piece, which may +be smaller. + +``hash_for_piece()`` takes a piece-index and returns the 20-bytes sha1-hash for that +piece and ``info_hash()`` returns the 20-bytes sha1-hash for the info-section of the +torrent file. For more information on the ``sha1_hash``, see the big_number_ class. + +``comment()`` returns the comment associated with the torrent. If there's no comment, +it will return an empty string. ``creation_date()`` returns a ``boost::posix_time::ptime_`` +object, representing the time when this torrent file was created. If there's no timestamp +in the torrent file, this will return a date of january 1:st 1970. + +.. _boost::posix_time::ptime: http://www.boost.org/libs/date_time/doc/class_ptime.html + + + + +torrent_handle +-------------- + +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. +Its declaration looks like this:: + + struct torrent_handle + { + torrent_handle(); + + torrent_status status() const; + void get_download_queue(std::vector& queue); + void get_peer_info(std::vector& v); + }; + +The default constructor will initialize the handle to an invalid state. Which means you cannot +perform any operation on it, unless you first assign it a valid handle. If you try to perform +any operation they will simply return. + + + + +status() +~~~~~~~~ + +``status()`` will return a structure with information about the status of this +torrent. It contains the following fields:: + + struct torrent_status + { + enum state_t + { + invalid_handle, + queued_for_checking, + checking_files, + downloading, + seeding + }; + + state_t state; + float progress; + boost::posix_time::time_duration next_announce; + std::size_t total_download; + std::size_t total_upload; + std::vector pieces; + std::size_t total_done; + }; + +``progress`` is a value in the range [0, 1], that represents the progress of the +torrent's current task. It may be checking files or downloading. The torrent's +current task is in the ``state`` member, it will be one of the following: + ++-----------------------+----------------------------------------------------------+ +|``invalid_handle`` |This will be the state if you called status on an | +| |uninitialized handle (a handle that was constructed | +| |with the default constructor). | ++-----------------------+----------------------------------------------------------+ +|``queued_for_checking``|The torrent is in the queue for being checked. But there | +| |currently is another torrent that are being checked. | +| |This torrent will wait for its turn. | ++-----------------------+----------------------------------------------------------+ +|``checking_files`` |The torrent has not started its download yet, and is | +| |currently checking existing files. | ++-----------------------+----------------------------------------------------------+ +|``downloading`` |The torrent is being downloaded. This is the state | +| |most torrents will be in most of the time. The progress | +| |meter will tell how much of the files that has been | +| |downloaded. | ++-----------------------+----------------------------------------------------------+ +|``seeding`` |In this state the torrent has finished downloading and | +| |is a pure seeder. | ++-----------------------+----------------------------------------------------------+ + +``next_announce`` is the time until the torrent will announce itself to the tracker. + +``total_download`` and ``total_upload`` is the number of bytes downloaded and +uploaded to all peers, accumulated, *this session* only. + +``pieces`` is the bitmask that representw which pieces we have (set to true) and +the pieces we don't have. + +``total_done`` is the total number of bytes of the file(s) that we have. + +get_download_queue() +~~~~~~~~~~~~~~~~~~~~ + +``get_download_queue()`` 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 +requested. The entry in the vector (``partial_piece_info``) looks like this:: + + struct partial_piece_info + { + enum { max_blocks_per_piece }; + int piece_index; + int blocks_in_piece; + std::bitset requested_blocks; + std::bitset finished_blocks; + peer_id peer[max_blocks_per_piece]; + int num_downloads[max_blocks_per_piece]; + }; + +``piece_index`` is the index of the piece in question. ``blocks_in_piece`` is the +number of blocks in this particular piece. This number will be the same for most pieces, but +the last piece may have fewer blocks than the standard pieces. + +``requested_blocks`` is a bitset with one bit per block in the piece. If a bit is set, it +means that that block has been requested, but not necessarily fully downloaded yet. To know +from whom the block has been requested, have a look in the ``peer`` array. The bit-index +in the ``requested_blocks`` and ``finished_blocks`` correspons to the array-index into +``peers`` and ``num_downloads``. The array of peers is contains the id of the +peer the piece was requested from. If a piece hasn't been requested (the bit in +``requested_blocks`` is not set) the peer array entry will be undefined. + +The ``finished_blocks`` is a bitset where each bit says if the block is fully downloaded +or not. And the ``num_downloads`` array says how many times that block has been downloaded. +When a piece fails a hash verification, single blocks may be redownloaded to see if the hash teast +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. Each entry contains information about +that particular peer. It contains the following information:: + + struct peer_info + { + enum + { + interesting = 0x1, + choked = 0x2, + remote_interested = 0x4, + remote_choked = 0x8 + }; + unsigned int flags; + address ip; + float up_speed; + float down_speed; + unsigned int total_download; + unsigned int total_upload; + peer_id id; + std::vector pieces; + int upload_limit; + }; + +The ``flags`` attribute tells you in which state the peer is. It is set to +any combination of the four enums above. Where ``interesting`` means that we +are interested in pieces from this peer. ``choked`` means that **we** have +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 +**us**. + +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. + +``up_speed`` and ``down_speed`` is the current upload and download speed +we have to and from this peer. These figures are updated aproximately once every second. + +``total_download`` and ``total_upload`` are the total number of bytes downloaded +from and uploaded to this peer. These numbers do not include the protocol chatter, but only +the payload data. + +``id`` is the peer's id as used in the bit torrent protocol. This id can be used to +extract 'fingerprints' from the peer. Sometimes it can tell you which client the peer +is using. + +``pieces`` is a vector of booleans that has as many entries as there are pieces +in the torrent. Each boolean tells you if the peer has that piece (if it's set to true) +or if the peer miss that piece (set to false). + +``upload_limit`` is the number of bytes per second we are allowed to send to this +peer every second. It may be -1 if there's no limit. + + + +address +------- + +TODO + + + +http_settings +------------- + +You have some control over tracker requests through the ``http_settings`` object. You +create it and fill it with your settings and the use ``session::set_http_settings()`` +to apply them. You have control over proxy and authorization settings and also the user-agent +that will be sent to the tracker. The user-agent is a good way to identify your client. + +:: + + struct http_settings + { + http_settings(); + std::string proxy_ip; + int proxy_port; + std::string proxy_login; + std::string proxy_password; + std::string user_agent; + int tracker_timeout; + int tracker_maximum_response_length; + }; + +``tracker_timeout`` is the number of seconds the tracker connection will +wait until it considers the tracker to have timed-out. Default value is 10 +seconds. + +``tracker_maximum_response_length`` is the maximum number of bytes in a +tracker response. If a response size passes this number it will be rejected +and the connection will be closed. On gzipped responses this size is measured +on the uncompressed data. So, if you get 20 bytes of gzip response that'll +expand to 2 megs, it will be interrupted before the entire response has been +uncompressed (given your limit is lower than 2 megs). Default limit is +1 megabyte. + + + +big_number +---------- + +Both the ``peer_id`` and ``sha1_hash`` types are typedefs of the class +``big_number``. It represents 20 bytes of data. Its synopsis follows:: + + class big_number + { + public: + bool operator==(const big_number& n) const; + bool operator!=(const big_number& n) const; + bool operator<(const big_number& n) const; + + const unsigned char* begin() const; + const unsigned char* end() const; + + unsigned char* begin(); + unsigned char* end(); + }; + +The iterators gives you access to individual bytes. + + + +hasher +------ + +This class creates sha1-hashes. Its declaration looks like this:: + + class hasher + { + public: + hasher(); + + void update(const char* data, unsigned int len); + sha1_hash final(); + void reset(); + }; + + +You use it by first instantiating it, then call ``update()`` to feed it +with data. i.e. you don't have to keep the entire buffer of which you want to +create the hash in memory. You can feed the hasher parts of it at a time. When +You have fed the hasher with all the data, you call ``final()`` and it +will return the sha1-hash of the data. + +If you want to reuse the hasher object once you have created a hash, you have to +call ``reset()`` to reinitialize it. + +The sha1-algorithm used was implemented by Steve Reid and released as public domain. +For more info, see ``src/sha1.c``. + + + +Feedback +======== + +There's a `mailing list`__. + +__ http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss + +You can usually find me as hydri in ``#btports @ irc.freenode.net``. + + + +Credits +======= + +Copyright (c) 2003 Arvid Norberg + diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index f2db0074c..8d91d8313 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include +#include #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index b1e9b1c0a..571da405c 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -41,7 +41,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include +#include #include "libtorrent/torrent_handle.hpp" #include "libtorrent/entry.hpp" @@ -218,6 +218,9 @@ namespace libtorrent #endif private: +#ifndef NDEBUG + virtual void debug_log(const std::string& line); +#endif void try_next_tracker(); diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index e72d2f9f2..7515d73c8 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_TORRENT_HANDLE_HPP_INCLUDED #include -#include +#include #include "libtorrent/peer_id.hpp" #include "libtorrent/peer_info.hpp" @@ -69,8 +69,14 @@ namespace libtorrent state_t state; float progress; boost::posix_time::time_duration next_announce; + + // transferred this session! std::size_t total_download; std::size_t total_upload; + std::vector pieces; + + // the number of bytes of the file we have + std::size_t total_done; }; struct partial_piece_info diff --git a/include/libtorrent/torrent_info.hpp b/include/libtorrent/torrent_info.hpp index 7e91b6643..aeae0037e 100755 --- a/include/libtorrent/torrent_info.hpp +++ b/include/libtorrent/torrent_info.hpp @@ -41,6 +41,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" +#include "boost/date_time/posix_time/posix_time.hpp" + /* * This file declares the following functions: * @@ -49,7 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. * */ -// TODO: add std::string comment() and creation_date() +// TODO: add std::string comment() namespace libtorrent { @@ -77,6 +79,9 @@ namespace libtorrent public: torrent_info(const entry& torrent_file) + : m_creation_date(boost::gregorian::date(1970 + , boost::gregorian::Jan + , 1)) { try { @@ -131,6 +136,12 @@ namespace libtorrent return m_piece_hash[index]; } + boost::posix_time::ptime creation_date() const + { return m_creation_date; } + + const std::string& comment() const + { return m_comment; } + private: void read_torrent_info(const entry& libtorrent); @@ -154,6 +165,15 @@ namespace libtorrent sha1_hash m_info_hash; std::string m_name; + + // if a creation date is found in the torrent file + // this will be set to that, otherwise it'll be + // 1970, Jan 1 + boost::posix_time::ptime m_creation_date; + + // if a comment is found in the torrent file + // this will be set to that comment + std::string m_comment; }; } diff --git a/src/torrent.cpp b/src/torrent.cpp index 677d99342..c2abdb712 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -442,6 +442,11 @@ namespace libtorrent st.next_announce = next_announce() - boost::posix_time::second_clock::local_time(); + // TODO: this is not accurate because it assumes the last + // block is m_block_size bytes + st.total_done = (blocks_we_have + unverified_blocks) * m_block_size; + st.pieces = m_storage.pieces(); + if (num_pieces == p.size()) st.state = torrent_status::seeding; else @@ -450,5 +455,12 @@ namespace libtorrent return st; } +#ifndef NDEBUG + void torrent::debug_log(const std::string& line) + { + (*m_ses->m_logger) << line << "\n"; + } +#endif + } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 6280b393e..09ffbe497 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -73,6 +73,8 @@ namespace libtorrent st.progress = 0.f; st.state = torrent_status::invalid_handle; st.next_announce = boost::posix_time::time_duration(); + st.pieces.clear(); + st.total_done = 0; return st; } @@ -98,6 +100,9 @@ namespace libtorrent st.state = torrent_status::queued_for_checking; st.progress = d->progress; st.next_announce = boost::posix_time::time_duration(); + st.pieces.clear(); + st.pieces.resize(d->torrent_ptr->torrent_file().num_pieces(), false); + st.total_done = 0; return st; } } @@ -107,7 +112,9 @@ namespace libtorrent st.total_upload = 0; st.progress = 0.f; st.state = torrent_status::invalid_handle; + st.pieces.clear(); st.next_announce = boost::posix_time::time_duration(); + st.total_done = 0; return st; } diff --git a/src/torrent_info.cpp b/src/torrent_info.cpp index 44fa97780..8dce311db 100755 --- a/src/torrent_info.cpp +++ b/src/torrent_info.cpp @@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include "libtorrent/torrent_info.hpp" #include "libtorrent/bencode.hpp" @@ -169,6 +170,20 @@ namespace libtorrent extract_files(i->second.list(), m_files, m_name); } + // extract creation date + i = info.dict().find("creation date"); + if (i != info.dict().end() && i->second.type() == entry::int_t) + { + m_creation_date = m_creation_date + boost::posix_time::seconds(i->second.integer()); + } + + // extract comment + i = info.dict().find("comment"); + if (i != info.dict().end() && i->second.type() == entry::string_t) + { + m_comment = i->second.string(); + } + // calculate total size of all pieces m_total_size = 0; for (std::vector::iterator i = m_files.begin(); i != m_files.end(); ++i) @@ -210,6 +225,10 @@ namespace libtorrent { os << i->tier << ": " << i->url << "\n"; } + if (!m_comment.empty()) + os << "comment: " << m_comment << "\n"; + if (m_creation_date != boost::posix_time::ptime(boost::gregorian::date(1970, boost::gregorian::Jan, 1))) + os << "creation date: " << to_simple_string(m_creation_date) << "\n"; os << "number of pieces: " << num_pieces() << "\n"; os << "piece length: " << piece_length() << "\n"; os << "files:\n";