diff --git a/docs/index.html b/docs/index.html index 5d73fd2aa..7e9cc3720 100755 --- a/docs/index.html +++ b/docs/index.html @@ -12,69 +12,19 @@

libtorrent

--++++ + +
sourceforge pagemanualscreenshot mailing list
-
-

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 @@ -87,1104 +37,13 @@ example client.

  • 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:

    -
    - -
    -

    Functions that are yet to be implemented:

    -
    - -
    -

    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 as well as zlib.

    -

    libtorrent has been successfully compiled and tested on:

    -
    - -
    -

    It does not compile on

    -
    - -
    -
    -
    -

    building

    -

    To build libtorrent you need boost and bjam installed. -Then you can use bjam to build libtorrent.

    -

    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', -'boost-1.30.2/libs/date_time/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 fingerprint& print);
    -        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);
    -        void set_upload_rate_limit(int bytes_per_second);
    -
    -        std::auto_ptr<alert> pop_alert();
    -        void set_severity_level(alert::severity_t s);
    -
    -};
    -
    -

    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. 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 -for checking, being checked or downloading) add_torrent() will throw -duplicate_torrent which derives from std::exception.

    -

    The difference between the two constructors is that one of them takes a fingerprint -as argument. If this is ommited, the client will get a default fingerprint stating -the version of libtorrent. The fingerprint is a short string that will be used in -the peer-id to identify the client and the client's version. For more details see the -fingerprint class.

    -

    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.

    -

    The pop_alert() function is the interface for retrieving alerts, warnings and -errors from libtorrent. If there hasn't occured any errors (matching your severity -level) pop_alert() will return a zero pointer. If there has been some error, it will -return a pointer to an alert object describing it. You can then use the query the -alert object for information about the error or message. To retrieve any alerts, you -have to select a severity level using set_severity_level(). It defaults to -alert::none, which means that you don't get any messages at all, ever. You have -the following levels to select among:

    - ---- - - - - - - - - - - - - - - - - - - - - -
    noneNo alert will ever have this severity level, which -effectively filters all messages.
    fatalFatal errors will have this severity level. Examples can -be disk full or something else that will make it -impossible to continue normal execution.
    criticalSignals errors that requires user interaction.
    warningMessages with the warning severity can be a tracker that -times out or responds with invalid data. It will be -retried automatically, and the possible next tracker in -a multitracker sequence will be tried. It does not -require any user interaction.
    infoEvents that can be considered normal, but still deserves -an event. This could be a piece hash that fails.
    debugThis will include alot of debug events that can be used -both for debugging libtorrent but also when debugging -other clients that are connected to libtorrent. It will -report strange behaviors among the connected peers.
    -

    When setting a severity level, you will receive messages of that severity and all -messages that are more sever. If you set alert::none (the default) you will not recieve -any events at all.

    -

    When you get an alert, you can use typeid() or dynamic_cast<> to get more detailed -information on exactly which type it is. i.e. what kind of error it is. You can also use a -dispatcher mechanism that's available in libtorrent.

    -

    TODO: describe the type dispatching mechanism

    -

    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

    -

    This alert is generated on tracker time outs, premature disconnects, invalid response or -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
    -{
    -        tracker_alert(const torrent_handle& h, const std::string& msg);
    -        virtual std::auto_ptr<alert> clone() const;
    -
    -        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
    -{
    -        hash_failed_alert(
    -                const torrent_handle& h
    -                , int index
    -                , const std::string& msg);
    -
    -        virtual std::auto_ptr<alert> clone() const;
    -
    -        torrent_handle handle;
    -        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

    -

    The torrent files are bencoded. There are two functions in libtorrent that can encode and decode -bencoded data. They are:

    -
    -template<class InIt> entry bdecode(InIt start, InIt end);
    -template<class OutIt> void bencode(OutIt out, const entry& e);
    -
    -

    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<char> buffer;
    -bencode(std::back_insert_iterator<std::vector<char> >(buf), e);
    -
    -

    If you want to decode a torrent file from a buffer in memory, you can do it like this:

    -
    -std::vector<char> 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.

    -

    If bdecode() encounters invalid encoded data in the range given to it -it will throw invalid_encoding.

    -
    -
    -

    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<std::string, entry> dictionary_type;
    -        typedef std::string string_type;
    -        typedef std::vector<entry> 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<file>::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<announce_entry>& 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.

    -

    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.

    -
    -
    -

    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();
    -        void get_download_queue(std::vector<partial_piece_info>& queue);
    -        void get_peer_info(std::vector<peer_info>& v);
    -        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);
    -
    -        sha1_hash info_hash() const;
    -
    -        bool operator==(const torrent_handle&) const;
    -        bool operator!=(const torrent_handle&) const;
    -        bool operator<(const torrent_handle&) const;
    -};
    -
    -

    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 on an uninitialized handle, it will throw invalid_handle.

    -

    save_path() returns the path that was given to add_torrent() when this torrent -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 how 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. -It contains the following fields:

    -
    -struct torrent_status
    -{
    -        enum state_t
    -        {
    -                invalid_handle,
    -                queued_for_checking,
    -                checking_files,
    -                connecting_to_tracker,
    -                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::size_t total_payload_download;
    -        std::size_t total_payload_upload;
    -
    -        float download_rate;
    -        float upload_rate;
    -
    -        std::vector<bool> 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:

    - ---- - - - - - - - - - - - - - - - - - -
    queued_for_checkingThe 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_filesThe torrent has not started its download yet, and is -currently checking existing files.
    connecting_to_trackerThe torrent has sent a request to the tracker and is -currently waiting for a response
    downloadingThe 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.
    seedingIn 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.

    -

    total_payload_download and total_payload_upload counts the amount of bytes -send and received this session, but only the actual oayload data (i.e the interesting -data), these counters ignore any protocol overhead.

    -

    pieces is the bitmask that representw which pieces we have (set to true) and -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. 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.

    -
    -
    -

    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<max_blocks_per_piece> requested_blocks;
    -        std::bitset<max_blocks_per_piece> 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, given the handle is valid. If the -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:

    -
    -struct peer_info
    -{
    -        enum
    -        {
    -                interesting = 0x1,
    -                choked = 0x2,
    -                remote_interested = 0x4,
    -                remote_choked = 0x8,
    -                supports_extensions = 0x10
    -        };
    -        unsigned int flags;
    -        address ip;
    -        float up_speed;
    -        float down_speed;
    -        unsigned int total_download;
    -        unsigned int total_upload;
    -        peer_id id;
    -        std::vector<bool> pieces;
    -        int upload_limit;
    -        int upload_ceiling;
    -
    -        int load_balancing;
    -
    -        int downloading_piece_index;
    -        int downloading_block_index;
    -        int downloading_progress;
    -        int downloading_total;
    -};
    -
    -

    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. support_extensions means that this peer supports the extension protocol -as described by nolar.

    -

    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. The upload limits of all peers -should sum up to the upload limit set by session::set_upload_limit.

    -

    upload_ceiling is the current maximum allowed upload rate given the cownload -rate and share ratio. If the global upload rate is inlimited, the upload_limit -for every peer will be the same as their upload_ceiling.

    -

    load_balancing is a measurment of the balancing of free download (that we get) -and free upload that we give. Every peer gets a certain amount of free upload, but -this member says how much extra free upload this peer has got. If it is a negative -number it means that this was a peer from which we have got this amount of free -download.

    -

    You can know which piece, and which part of that piece, that is currently being -downloaded from a specific peer by looking at the next four members. -downloading_piece_index is the index of the piece that is currently being downloaded. -This may be set to -1 if there's currently no piece downloading from this peer. If it is ->= 0, the other three members are valid. downloading_block_index is the index of the -block (or sub-piece) that is being downloaded. downloading_progress is the number -of bytes of this block we have received from the peer, and downloading_total is -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.

    -
    -
    -

    is_valid()

    -

    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.

    -
    -
    -
    -

    address

    -

    The address 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 sockaddr_in would contain. -Its declaration looks like this:

    -
    -class address
    -{
    -public:
    -        address();
    -        address(unsigned char a
    -                , unsigned char b
    -                , unsigned char c
    -                , unsigned char d
    -                , unsigned short  port);
    -        address(unsigned int addr, unsigned short port);
    -        address(const std::string& addr, unsigned short port);
    -        address(const address& a);
    -        ~address();
    -
    -        std::string as_string() const;
    -        unsigned int ip() const;
    -        unsigned short port() const;
    -
    -        bool operator<(const address& a) const;
    -        bool operator!=(const address& a) const;
    -        bool operator==(const address& a) const;
    -};
    -
    -

    It is less-than comparable to make it possible to use it as a key in a map. as_string() may block -while it does the DNS lookup, it returns a string that points to the address represented by the object.

    -

    ip() will return the 32-bit ip-address as an integer. port() returns the port number.

    -
    -
    -

    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;
    -};
    -
    -

    proxy_ip may be a hostname or ip to a http proxy to use. If this is -an empty string, no http proxy will be used.

    -

    proxy_port is the port on which the http proxy listens. If proxy_ip -is empty, this will be ignored.

    -

    proxy_login should be the login username for the http proxy, if this -empty, the http proxy will be trid to be used without authentication.

    -

    proxy_password the password string for the http proxy.

    -

    user_agent this is the client identification to the tracker. It will -be followed by the string "(libtorrent)" to identify that this library -is being used. This should be set to your client's name and version number.

    -

    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.

    -
    -
    -

    fingerprint

    -

    The fingerprint class represents information about a client and its version. It is used -to encode this information into the client's peer id.

    -

    This is the class declaration:

    -
    -struct fingerprint
    -{
    -        fingerprint(const char* id_string, int major, int minor, int revision, int tag);
    -
    -        std::string to_string() const;
    -
    -        char id[2];
    -        char major_version;
    -        char minor_version;
    -        char revision_version;
    -        char tag_version;
    -
    -};
    -
    -

    The constructor takes a const char* that should point to a string constant containing -exactly two characters. These are the characters that should be unique for your client. Make -sure not to clash with anybody else. Here are some taken id's:

    - ---- - - - - - - - - - - - - - - - - - - - -
    id charsclient
    'AZ'Azureus
    'LT'libtorrent (default)
    'BX'BittorrentX
    'MT'Moonlight Torrent
    -

    The major, minor, revision and tag parameters are used to identify the -version of your client. All these numbers must be within the range [0, 9].

    -

    to_string() will generate the actual string put in the peer-id, and return it.

    -
    -
    -

    alert

    -

    The alert 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 -is its synopsis:

    -
    -class alert
    -{
    -public:
    -
    -        enum severity_t { debug, info, warning, critital, fatal, none };
    -
    -        alert(severity_t severity, const std::string& msg);
    -
    -        virtual ~alert() {}
    -
    -        const std::string& msg() const;
    -        severity_t severity() const;
    -
    -        virtual std::auto_ptr<alert> clone() const = 0;
    -};
    -
    -
    -
    -

    exceptions

    -

    There are a number of exceptions that can be thrown from different places in libtorrent, -here's a complete list with description.

    -
    -

    invalid_handle

    -

    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
    -{
    -        const char* what() const throw();
    -};
    -
    -
    -
    -

    duplicate_torrent

    -

    This is thrown by session::add_torrent() if the torrent already has been added to -the session.

    -
    -struct duplicate_torrent: std::exception
    -{
    -        const char* what() const throw();
    -};
    -
    -
    -
    -

    invalid_encoding

    -

    This is thrown by bdecode() if the input data is not a valid bencoding.

    -
    -struct invalid_encoding: std::exception
    -{
    -        const char* what() const throw();
    -};
    -
    -
    -
    -

    type_error

    -

    This is thrown from the accessors of entry if the data type of the entry doesn't -match the type you want to extract from it.

    -
    -struct type_error: std::runtime_error
    -{
    -        type_error(const char* error);
    -};
    -
    -
    -
    -

    invalid_torrent_file

    -

    This exception is thrown from the constructor of torrent_info if the given bencoded information -doesn't meet the requirements on what information has to be present in a torrent file.

    -
    -struct invalid_torrent_file: std::exception
    -{
    -        const char* what() const throw();
    -};
    -
    -
    -
    -
    -

    example usage

    -
    -

    dump_torrent

    -

    This is an example of a program that will take a torrent-file as a parameter and -print information about it to std out:

    -
    -#include <iostream>
    -#include <fstream>
    -#include <iterator>
    -#include <exception>
    -#include <iomanip>
    -
    -#include "libtorrent/entry.hpp"
    -#include "libtorrent/bencode.hpp"
    -#include "libtorrent/torrent_info.hpp"
    -
    -
    -int main(int argc, char* argv[])
    -{
    -        using namespace libtorrent;
    -
    -        if (argc != 2)
    -        {
    -                std::cerr << "usage: dump_torrent torrent-file\n";
    -                return 1;
    -        }
    -
    -        try
    -        {
    -                std::ifstream in(argv[1], std::ios_base::binary);
    -                in.unsetf(std::ios_base::skipws);
    -                entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
    -                torrent_info t(e);
    -
    -                // print info about torrent
    -                std::cout << "\n\n----- torrent file info -----\n\n";
    -                std::cout << "trackers:\n";
    -                for (std::vector<announce_entry>::const_iterator i = t.trackers().begin();
    -                        i != t.trackers().end();
    -                        ++i)
    -                {
    -                        std::cout << i->tier << ": " << i->url << "\n";
    -                }
    -
    -                std::cout << "number of pieces: " << t.num_pieces() << "\n";
    -                std::cout << "piece length: " << t.piece_length() << "\n";
    -                std::cout << "files:\n";
    -                for (torrent_info::file_iterator i = t.begin_files();
    -                        i != t.end_files();
    -                        ++i)
    -                {
    -                        std::cout << "  " << std::setw(11) << i->size
    -                        << "  " << i->path << " " << i->filename << "\n";
    -                }
    -                
    -        }
    -        catch (std::exception& e)
    -        {
    -                std::cout << e.what() << "\n";
    -        }
    -
    -        return 0;
    -}
    -
    -
    -
    -

    simple client

    -

    This is a simple client. It doesn't have much output to keep it simple:

    -
    -#include <iostream>
    -#include <fstream>
    -#include <iterator>
    -#include <exception>
    -
    -#include <boost/format.hpp>
    -#include <boost/date_time/posix_time/posix_time.hpp>
    -
    -#include "libtorrent/entry.hpp"
    -#include "libtorrent/bencode.hpp"
    -#include "libtorrent/session.hpp"
    -#include "libtorrent/http_settings.hpp"
    -
    -int main(int argc, char* argv[])
    -{
    -        using namespace libtorrent;
    -
    -        if (argc != 2)
    -        {
    -                std::cerr << "usage: ./simple_cient torrent-file\n"
    -                        "to stop the client, press return.\n";
    -                return 1;
    -        }
    -
    -        try
    -        {
    -                session s(6881);
    -
    -                std::ifstream in(argv[1], std::ios_base::binary);
    -                in.unsetf(std::ios_base::skipws);
    -                entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
    -                torrent_info t(e);
    -                s.add_torrent(t, "");
    -                        
    -                // wait for the user to end
    -                char a;
    -                std::cin.unsetf(std::ios_base::skipws);
    -                std::cin >> a;
    -        }
    -        catch (std::exception& e)
    -        {
    -                std::cout << e.what() << "\n";
    -        }
    -        return 0;
    -}
    -
    -
    -
    -
    -

    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 / 8 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 4b8de3458..58ea4d88d 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,18 +3,15 @@ libtorrent ========== -=================== =============== -`sourceforge page`_ `mailing list`_ -=================== =============== +=================== ======= =========== =============== +`sourceforge page`_ manual_ screenshot_ `mailing list`_ +=================== ======= =========== =============== .. _sourceforge page: http://www.sourceforge.net/projects/libtorrent +.. _manual: manual.html +.. _screenshot: libtorrent_screen.png .. _mailing list: http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss -.. 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 @@ -28,1228 +25,6 @@ The main goals of libtorrent are: * 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 and the maximum number of unchoked peers - * 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 - -Functions that are yet to be implemented: - - * number of connections limit - * better handling of peers that send bad data - * ip-filters - * file-level piece priority - -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 as well as zlib. - -libtorrent has been successfully compiled and tested on: - - * Cygwin GCC 3.3.1 - * Windows 2000 vc7.1 - * Linux x86 (debian) GCC 3.0 - -It does not compile on - - * GCC 2.95 - -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', -'boost-1.30.2/libs/date_time/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 fingerprint& print); - 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); - void set_upload_rate_limit(int bytes_per_second); - - std::auto_ptr pop_alert(); - void set_severity_level(alert::severity_t s); - - }; - -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. ``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 -for checking, being checked or downloading) ``add_torrent()`` will throw -``duplicate_torrent`` which derives from ``std::exception``. - -The difference between the two constructors is that one of them takes a fingerprint -as argument. If this is ommited, the client will get a default fingerprint stating -the version of libtorrent. The fingerprint is a short string that will be used in -the peer-id to identify the client and the client's version. For more details see the -fingerprint class. - -``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.* - -The ``pop_alert()`` function is the interface for retrieving alerts, warnings and -errors from libtorrent. If there hasn't occured any errors (matching your severity -level) ``pop_alert()`` will return a zero pointer. If there has been some error, it will -return a pointer to an alert object describing it. You can then use the query the -alert_ object for information about the error or message. To retrieve any alerts, you -have to select a severity level using ``set_severity_level()``. It defaults to -``alert::none``, which means that you don't get any messages at all, ever. You have -the following levels to select among: - -+--------------+----------------------------------------------------------+ -| ``none`` | No alert will ever have this severity level, which | -| | effectively filters all messages. | -| | | -+--------------+----------------------------------------------------------+ -| ``fatal`` | Fatal errors will have this severity level. Examples can | -| | be disk full or something else that will make it | -| | impossible to continue normal execution. | -| | | -+--------------+----------------------------------------------------------+ -| ``critical`` | Signals errors that requires user interaction. | -| | | -+--------------+----------------------------------------------------------+ -| ``warning`` | Messages with the warning severity can be a tracker that | -| | times out or responds with invalid data. It will be | -| | retried automatically, and the possible next tracker in | -| | a multitracker sequence will be tried. It does not | -| | require any user interaction. | -| | | -+--------------+----------------------------------------------------------+ -| ``info`` | Events that can be considered normal, but still deserves | -| | an event. This could be a piece hash that fails. | -| | | -+--------------+----------------------------------------------------------+ -| ``debug`` | This will include alot of debug events that can be used | -| | both for debugging libtorrent but also when debugging | -| | other clients that are connected to libtorrent. It will | -| | report strange behaviors among the connected peers. | -| | | -+--------------+----------------------------------------------------------+ - -When setting a severity level, you will receive messages of that severity and all -messages that are more sever. If you set ``alert::none`` (the default) you will not recieve -any events at all. - -When you get an alert, you can use ``typeid()`` or ``dynamic_cast<>`` to get more detailed -information on exactly which type it is. i.e. what kind of error it is. You can also use a -dispatcher mechanism that's available in libtorrent. - -TODO: describe the type dispatching mechanism - -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 -~~~~~~~~~~~~~ - -This alert is generated on tracker time outs, premature disconnects, invalid response or -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 - { - tracker_alert(const torrent_handle& h, const std::string& msg); - virtual std::auto_ptr clone() const; - - 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 - { - hash_failed_alert( - const torrent_handle& h - , int index - , const std::string& msg); - - virtual std::auto_ptr clone() const; - - torrent_handle handle; - 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 clone() const; - - peer_id id; - }; - - -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``. - -If ``bdecode()`` encounters invalid encoded data in the range given to it -it will throw invalid_encoding_. - - - -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. - -__ 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(); - void get_download_queue(std::vector& queue); - void get_peer_info(std::vector& v); - 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); - - sha1_hash info_hash() const; - - bool operator==(const torrent_handle&) const; - bool operator!=(const torrent_handle&) const; - bool operator<(const torrent_handle&) const; - }; - -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 on an uninitialized handle, it will throw ``invalid_handle``. - -``save_path()`` returns the path that was given to ``add_torrent()`` when this torrent -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 how 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. -It contains the following fields:: - - struct torrent_status - { - enum state_t - { - invalid_handle, - queued_for_checking, - checking_files, - connecting_to_tracker, - 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::size_t total_payload_download; - std::size_t total_payload_upload; - - float download_rate; - float upload_rate; - - 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: - -+--------------------------+----------------------------------------------------------+ -|``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. | -| | | -+--------------------------+----------------------------------------------------------+ -|``connecting_to_tracker`` |The torrent has sent a request to the tracker and is | -| |currently waiting for a response | -| | | -+--------------------------+----------------------------------------------------------+ -|``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. - -``total_payload_download`` and ``total_payload_upload`` counts the amount of bytes -send and received this session, but only the actual oayload data (i.e the interesting -data), these counters ignore any protocol overhead. - -``pieces`` is the bitmask that representw which pieces we have (set to true) and -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. 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. - -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, given the handle is valid. If the -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:: - - struct peer_info - { - enum - { - interesting = 0x1, - choked = 0x2, - remote_interested = 0x4, - remote_choked = 0x8, - supports_extensions = 0x10 - }; - 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; - int upload_ceiling; - - int load_balancing; - - int downloading_piece_index; - int downloading_block_index; - int downloading_progress; - int downloading_total; - }; - -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**. ``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 -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. The upload limits of all peers -should sum up to the upload limit set by ``session::set_upload_limit``. - -``upload_ceiling`` is the current maximum allowed upload rate given the cownload -rate and share ratio. If the global upload rate is inlimited, the ``upload_limit`` -for every peer will be the same as their ``upload_ceiling``. - -``load_balancing`` is a measurment of the balancing of free download (that we get) -and free upload that we give. Every peer gets a certain amount of free upload, but -this member says how much *extra* free upload this peer has got. If it is a negative -number it means that this was a peer from which we have got this amount of free -download. - -You can know which piece, and which part of that piece, that is currently being -downloaded from a specific peer by looking at the next four members. -``downloading_piece_index`` is the index of the piece that is currently being downloaded. -This may be set to -1 if there's currently no piece downloading from this peer. If it is ->= 0, the other three members are valid. ``downloading_block_index`` is the index of the -block (or sub-piece) that is being downloaded. ``downloading_progress`` is the number -of bytes of this block we have received from the peer, and ``downloading_total`` is -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. - - -is_valid() -~~~~~~~~~~ - -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. - - -address -------- - -The ``address`` 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 ``sockaddr_in`` would contain. -Its declaration looks like this:: - - class address - { - public: - address(); - address(unsigned char a - , unsigned char b - , unsigned char c - , unsigned char d - , unsigned short port); - address(unsigned int addr, unsigned short port); - address(const std::string& addr, unsigned short port); - address(const address& a); - ~address(); - - std::string as_string() const; - unsigned int ip() const; - unsigned short port() const; - - bool operator<(const address& a) const; - bool operator!=(const address& a) const; - bool operator==(const address& a) const; - }; - -It is less-than comparable to make it possible to use it as a key in a map. ``as_string()`` may block -while it does the DNS lookup, it returns a string that points to the address represented by the object. - -``ip()`` will return the 32-bit ip-address as an integer. ``port()`` returns the port number. - - - - -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; - }; - -``proxy_ip`` may be a hostname or ip to a http proxy to use. If this is -an empty string, no http proxy will be used. - -``proxy_port`` is the port on which the http proxy listens. If ``proxy_ip`` -is empty, this will be ignored. - -``proxy_login`` should be the login username for the http proxy, if this -empty, the http proxy will be trid to be used without authentication. - -``proxy_password`` the password string for the http proxy. - -``user_agent`` this is the client identification to the tracker. It will -be followed by the string "(libtorrent)" to identify that this library -is being used. This should be set to your client's name and version number. - -``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``. - - -fingerprint ------------ - -The fingerprint class represents information about a client and its version. It is used -to encode this information into the client's peer id. - -This is the class declaration:: - - struct fingerprint - { - fingerprint(const char* id_string, int major, int minor, int revision, int tag); - - std::string to_string() const; - - char id[2]; - char major_version; - char minor_version; - char revision_version; - char tag_version; - - }; - -The constructor takes a ``const char*`` that should point to a string constant containing -exactly two characters. These are the characters that should be unique for your client. Make -sure not to clash with anybody else. Here are some taken id's: - -+----------+-----------------------+ -| id chars | client | -+==========+=======================+ -| 'AZ' | Azureus | -+----------+-----------------------+ -| 'LT' | libtorrent (default) | -+----------+-----------------------+ -| 'BX' | BittorrentX | -+----------+-----------------------+ -| 'MT' | Moonlight Torrent | -+----------+-----------------------+ - - -The ``major``, ``minor``, ``revision`` and ``tag`` parameters are used to identify the -version of your client. All these numbers must be within the range [0, 9]. - -``to_string()`` will generate the actual string put in the peer-id, and return it. - -alert ------ - -The ``alert`` 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 -is its synopsis:: - - class alert - { - public: - - enum severity_t { debug, info, warning, critital, fatal, none }; - - alert(severity_t severity, const std::string& msg); - - virtual ~alert() {} - - const std::string& msg() const; - severity_t severity() const; - - virtual std::auto_ptr clone() const = 0; - }; - - - - -exceptions ----------- - -There are a number of exceptions that can be thrown from different places in libtorrent, -here's a complete list with description. - - -invalid_handle -~~~~~~~~~~~~~~ - -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 - { - const char* what() const throw(); - }; - - -duplicate_torrent -~~~~~~~~~~~~~~~~~ - -This is thrown by ``session::add_torrent()`` if the torrent already has been added to -the session. - -:: - - struct duplicate_torrent: std::exception - { - const char* what() const throw(); - }; - - -invalid_encoding -~~~~~~~~~~~~~~~~ - -This is thrown by ``bdecode()`` if the input data is not a valid bencoding. - -:: - - struct invalid_encoding: std::exception - { - const char* what() const throw(); - }; - - -type_error -~~~~~~~~~~ - -This is thrown from the accessors of ``entry`` if the data type of the ``entry`` doesn't -match the type you want to extract from it. - -:: - - struct type_error: std::runtime_error - { - type_error(const char* error); - }; - - -invalid_torrent_file -~~~~~~~~~~~~~~~~~~~~ - -This exception is thrown from the constructor of ``torrent_info`` if the given bencoded information -doesn't meet the requirements on what information has to be present in a torrent file. - -:: - - struct invalid_torrent_file: std::exception - { - const char* what() const throw(); - }; - - -example usage -------------- - -dump_torrent -~~~~~~~~~~~~ - -This is an example of a program that will take a torrent-file as a parameter and -print information about it to std out:: - - #include - #include - #include - #include - #include - - #include "libtorrent/entry.hpp" - #include "libtorrent/bencode.hpp" - #include "libtorrent/torrent_info.hpp" - - - int main(int argc, char* argv[]) - { - using namespace libtorrent; - - if (argc != 2) - { - std::cerr << "usage: dump_torrent torrent-file\n"; - return 1; - } - - try - { - std::ifstream in(argv[1], std::ios_base::binary); - in.unsetf(std::ios_base::skipws); - entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); - torrent_info t(e); - - // print info about torrent - std::cout << "\n\n----- torrent file info -----\n\n"; - std::cout << "trackers:\n"; - for (std::vector::const_iterator i = t.trackers().begin(); - i != t.trackers().end(); - ++i) - { - std::cout << i->tier << ": " << i->url << "\n"; - } - - std::cout << "number of pieces: " << t.num_pieces() << "\n"; - std::cout << "piece length: " << t.piece_length() << "\n"; - std::cout << "files:\n"; - for (torrent_info::file_iterator i = t.begin_files(); - i != t.end_files(); - ++i) - { - std::cout << " " << std::setw(11) << i->size - << " " << i->path << " " << i->filename << "\n"; - } - - } - catch (std::exception& e) - { - std::cout << e.what() << "\n"; - } - - return 0; - } - - -simple client -~~~~~~~~~~~~~ - -This is a simple client. It doesn't have much output to keep it simple:: - - #include - #include - #include - #include - - #include - #include - - #include "libtorrent/entry.hpp" - #include "libtorrent/bencode.hpp" - #include "libtorrent/session.hpp" - #include "libtorrent/http_settings.hpp" - - int main(int argc, char* argv[]) - { - using namespace libtorrent; - - if (argc != 2) - { - std::cerr << "usage: ./simple_cient torrent-file\n" - "to stop the client, press return.\n"; - return 1; - } - - try - { - session s(6881); - - std::ifstream in(argv[1], std::ios_base::binary); - in.unsetf(std::ios_base::skipws); - entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); - torrent_info t(e); - s.add_torrent(t, ""); - - // wait for the user to end - char a; - std::cin.unsetf(std::ios_base::skipws); - std::cin >> a; - } - catch (std::exception& e) - { - std::cout << e.what() << "\n"; - } - return 0; - } - - -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 / 8 bytes, the bitmask describing which - blocks are finished in this piece. Feedback ======== diff --git a/docs/libtorrent_screen.png b/docs/libtorrent_screen.png new file mode 100755 index 000000000..19d985261 Binary files /dev/null and b/docs/libtorrent_screen.png differ diff --git a/docs/manual.html b/docs/manual.html new file mode 100755 index 000000000..683998724 --- /dev/null +++ b/docs/manual.html @@ -0,0 +1,1264 @@ + + + + + + +libtorrent manual + + + +
    +

    libtorrent manual

    + +
    +

    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.

    +

    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 and the maximum number of unchoked peers
    • +
    • 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.
    • +
    • The extension protocol described by Nolar. See extensions.
    • +
    +
    +

    Functions that are yet to be implemented:

    +
    +
      +
    • number of connections limit
    • +
    • better handling of peers that send bad data
    • +
    • ip-filters
    • +
    • file-level piece priority
    • +
    +
    +

    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 as well as zlib.

    +

    libtorrent has been successfully compiled and tested on:

    +
    +
      +
    • Cygwin GCC 3.3.1
    • +
    • Windows 2000 vc7.1
    • +
    • Linux x86 (debian) GCC 3.0
    • +
    +
    +

    It does not compile on

    +
    +
      +
    • GCC 2.95
    • +
    +
    +
    +
    +

    building

    +

    To build libtorrent you need boost and bjam installed. +Then you can use bjam to build libtorrent.

    +

    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', +'boost-1.30.2/libs/date_time/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.

    +

    The basic usage is as follows:

    +
      +
    • conststruct a session

      +
    • +
    • parse .torrent-files and add them to the session

      +
    • +
    • +
      main loop
      +
        +
      • query the torrent_handles for progress
      • +
      • query the session for information
      • +
      • add and remove torrents from the session at run-time
      • +
      +
      +
      +
    • +
    • destruct all torrent_handles

      +
    • +
    • destruct session object

      +
    • +
    +

    Each class and function is described in this manual.

    +
    +
    +

    session

    +

    The session class has the following synopsis:

    +
    +class session: public boost::noncopyable
    +{
    +        session(int listen_port, const fingerprint& print);
    +        session(int listen_port);
    +
    +        torrent_handle add_torrent(
    +                const torrent_info& t
    +                , const std::string& save_path
    +                , const entry& resume_data = entry());
    +
    +        void remove_torrent(const torrent_handle& h);
    +
    +        void set_http_settings(const http_settings& settings);
    +        void set_upload_rate_limit(int bytes_per_second);
    +
    +        std::auto_ptr<alert> pop_alert();
    +        void set_severity_level(alert::severity_t s);
    +
    +};
    +
    +

    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. 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 +for checking, being checked or downloading) add_torrent() will throw +duplicate_torrent which derives from std::exception.

    +

    The difference between the two constructors is that one of them takes a fingerprint +as argument. If this is ommited, the client will get a default fingerprint stating +the version of libtorrent. The fingerprint is a short string that will be used in +the peer-id to identify the client and the client's version. For more details see the +fingerprint class.

    +

    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.

    +

    For information about the pop_alert() function, see alerts.

    +
    +
    +

    parsing torrent files

    +

    The torrent files are bencoded. There are two functions in libtorrent that can encode and decode +bencoded data. They are:

    +
    +template<class InIt> entry bdecode(InIt start, InIt end);
    +template<class OutIt> void bencode(OutIt out, const entry& e);
    +
    +

    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<char> buffer;
    +bencode(std::back_insert_iterator<std::vector<char> >(buf), e);
    +
    +

    If you want to decode a torrent file from a buffer in memory, you can do it like this:

    +
    +std::vector<char> 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.

    +

    If bdecode() encounters invalid encoded data in the range given to it +it will throw invalid_encoding.

    +
    +
    +

    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<std::string, entry> dictionary_type;
    +        typedef std::string string_type;
    +        typedef std::vector<entry> 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(const dictionary_type&);
    +        entry(const string_type&);
    +        entry(const list_type&);
    +        entry(const integer_type&);
    +
    +        entry();
    +        entry(data_type t);
    +        entry(const entry& e);
    +
    +        ~entry();
    +
    +        void operator=(const entry& e);
    +        void operator=(const dictionary_type&);
    +        void operator=(const string_type&);
    +        void operator=(const list_type&);
    +        void operator=(const integer_type&);
    +
    +        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<file>::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<announce_entry>& 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.

    +

    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.

    +
    +
    +

    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();
    +        void get_download_queue(std::vector<partial_piece_info>& queue);
    +        void get_peer_info(std::vector<peer_info>& v);
    +        const torrent_info& get_torrent_info();
    +        bool is_valid();
    +
    +        entry write_resume_data();
    +
    +        boost::filsystem::path save_path() const;
    +
    +        void set_max_uploads(int max_uploads);
    +
    +        sha1_hash info_hash() const;
    +
    +        bool operator==(const torrent_handle&) const;
    +        bool operator!=(const torrent_handle&) const;
    +        bool operator<(const torrent_handle&) const;
    +};
    +
    +

    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 on an uninitialized handle, it will throw invalid_handle.

    +

    save_path() returns the path that was given to add_torrent() when this torrent +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() generates fast-resume data and returns it as an entry. This entry +is suitable for being bencoded. For more information about how fast-resume works, see fast resume. +It may throw invalid_handle if the torrent handle is invalid.

    +
    +

    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. +It contains the following fields:

    +
    +struct torrent_status
    +{
    +        enum state_t
    +        {
    +                invalid_handle,
    +                queued_for_checking,
    +                checking_files,
    +                connecting_to_tracker,
    +                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::size_t total_payload_download;
    +        std::size_t total_payload_upload;
    +
    +        float download_rate;
    +        float upload_rate;
    +
    +        std::vector<bool> 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:

    + ++++ + + + + + + + + + + + + + + + + + +
    queued_for_checkingThe 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_filesThe torrent has not started its download yet, and is +currently checking existing files.
    connecting_to_trackerThe torrent has sent a request to the tracker and is +currently waiting for a response
    downloadingThe 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.
    seedingIn 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.

    +

    total_payload_download and total_payload_upload counts the amount of bytes +send and received this session, but only the actual oayload data (i.e the interesting +data), these counters ignore any protocol overhead.

    +

    pieces is the bitmask that representw which pieces we have (set to true) and +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. 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.

    +
    +
    +

    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<max_blocks_per_piece> requested_blocks;
    +        std::bitset<max_blocks_per_piece> 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, given the handle is valid. If the +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:

    +
    +struct peer_info
    +{
    +        enum
    +        {
    +                interesting = 0x1,
    +                choked = 0x2,
    +                remote_interested = 0x4,
    +                remote_choked = 0x8,
    +                supports_extensions = 0x10
    +        };
    +        unsigned int flags;
    +        address ip;
    +        float up_speed;
    +        float down_speed;
    +        unsigned int total_download;
    +        unsigned int total_upload;
    +        peer_id id;
    +        std::vector<bool> pieces;
    +        int upload_limit;
    +        int upload_ceiling;
    +
    +        int load_balancing;
    +
    +        int downloading_piece_index;
    +        int downloading_block_index;
    +        int downloading_progress;
    +        int downloading_total;
    +};
    +
    +

    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. support_extensions means that this peer supports the extension protocol +as described by nolar.

    +

    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. The upload limits of all peers +should sum up to the upload limit set by session::set_upload_limit.

    +

    upload_ceiling is the current maximum allowed upload rate given the cownload +rate and share ratio. If the global upload rate is inlimited, the upload_limit +for every peer will be the same as their upload_ceiling.

    +

    load_balancing is a measurment of the balancing of free download (that we get) +and free upload that we give. Every peer gets a certain amount of free upload, but +this member says how much extra free upload this peer has got. If it is a negative +number it means that this was a peer from which we have got this amount of free +download.

    +

    You can know which piece, and which part of that piece, that is currently being +downloaded from a specific peer by looking at the next four members. +downloading_piece_index is the index of the piece that is currently being downloaded. +This may be set to -1 if there's currently no piece downloading from this peer. If it is +>= 0, the other three members are valid. downloading_block_index is the index of the +block (or sub-piece) that is being downloaded. downloading_progress is the number +of bytes of this block we have received from the peer, and downloading_total is +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.

    +
    +
    +

    is_valid()

    +

    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.

    +
    +
    +
    +

    address

    +

    The address 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 sockaddr_in would contain. +Its declaration looks like this:

    +
    +class address
    +{
    +public:
    +        address();
    +        address(unsigned char a
    +                , unsigned char b
    +                , unsigned char c
    +                , unsigned char d
    +                , unsigned short  port);
    +        address(unsigned int addr, unsigned short port);
    +        address(const std::string& addr, unsigned short port);
    +        address(const address& a);
    +        ~address();
    +
    +        std::string as_string() const;
    +        unsigned int ip() const;
    +        unsigned short port() const;
    +
    +        bool operator<(const address& a) const;
    +        bool operator!=(const address& a) const;
    +        bool operator==(const address& a) const;
    +};
    +
    +

    It is less-than comparable to make it possible to use it as a key in a map. as_string() may block +while it does the DNS lookup, it returns a string that points to the address represented by the object.

    +

    ip() will return the 32-bit ip-address as an integer. port() returns the port number.

    +
    +
    +

    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;
    +};
    +
    +

    proxy_ip may be a hostname or ip to a http proxy to use. If this is +an empty string, no http proxy will be used.

    +

    proxy_port is the port on which the http proxy listens. If proxy_ip +is empty, this will be ignored.

    +

    proxy_login should be the login username for the http proxy, if this +empty, the http proxy will be trid to be used without authentication.

    +

    proxy_password the password string for the http proxy.

    +

    user_agent this is the client identification to the tracker. It will +be followed by the string "(libtorrent)" to identify that this library +is being used. This should be set to your client's name and version number.

    +

    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.

    +
    +
    +

    fingerprint

    +

    The fingerprint class represents information about a client and its version. It is used +to encode this information into the client's peer id.

    +

    This is the class declaration:

    +
    +struct fingerprint
    +{
    +        fingerprint(const char* id_string, int major, int minor, int revision, int tag);
    +
    +        std::string to_string() const;
    +
    +        char id[2];
    +        char major_version;
    +        char minor_version;
    +        char revision_version;
    +        char tag_version;
    +
    +};
    +
    +

    The constructor takes a const char* that should point to a string constant containing +exactly two characters. These are the characters that should be unique for your client. Make +sure not to clash with anybody else. Here are some taken id's:

    + ++++ + + + + + + + + + + + + + + + + + + + +
    id charsclient
    'AZ'Azureus
    'LT'libtorrent (default)
    'BX'BittorrentX
    'MT'Moonlight Torrent
    +

    The major, minor, revision and tag parameters are used to identify the +version of your client. All these numbers must be within the range [0, 9].

    +

    to_string() will generate the actual string put in the peer-id, and return it.

    +
    +
    +

    alerts

    +

    The pop_alert() function on session is the interface for retrieving +alerts, warnings, messages and errors from libtorrent. If there hasn't +occured any errors (matching your severity level) pop_alert() will +return a zero pointer. If there has been some error, it will return a pointer +to an alert object describing it. You can then use the alert object and query +it for information about the error or message. To retrieve any alerts, you have +to select a severity level using session::set_severity_level(). It defaults to +alert::none, which means that you don't get any messages at all, ever. +You have the following levels to select among:

    + ++++ + + + + + + + + + + + + + + + + + + + + +
    noneNo alert will ever have this severity level, which +effectively filters all messages.
    fatalFatal errors will have this severity level. Examples can +be disk full or something else that will make it +impossible to continue normal execution.
    criticalSignals errors that requires user interaction or +messages that almost never should be ignored. For +example, a chat message received from another peer is +announced as severity critical.
    warningMessages with the warning severity can be a tracker that +times out or responds with invalid data. It will be +retried automatically, and the possible next tracker in +a multitracker sequence will be tried. It does not +require any user interaction.
    infoEvents that can be considered normal, but still deserves +an event. This could be a piece hash that fails.
    debugThis will include alot of debug events that can be used +both for debugging libtorrent but also when debugging +other clients that are connected to libtorrent. It will +report strange behaviors among the connected peers.
    +

    When setting a severity level, you will receive messages of that severity and all +messages that are more sever. If you set alert::none (the default) you will not recieve +any events at all.

    +

    When you set a severuty level other than none, you have the responsibility to call +pop_alert() from time to time. If you don't do that, the alert queue will just grow.

    +

    When you get an alert, you can use typeid() or dynamic_cast<> to get more detailed +information on exactly which type it is. i.e. what kind of error it is. You can also use a +dispatcher mechanism that's available in libtorrent.

    +

    The alert class is the base class that specific messages are derived from. This +is its synopsis:

    +
    +class alert
    +{
    +public:
    +
    +        enum severity_t { debug, info, warning, critital, fatal, none };
    +
    +        alert(severity_t severity, const std::string& msg);
    +        virtual ~alert();
    +
    +        const std::string& msg() const;
    +        severity_t severity() const;
    +
    +        virtual std::auto_ptr<alert> clone() const = 0;
    +};
    +
    +

    This means that all alerts have at least a string describing it. They also +have a severity leve that can be used to sort them or present them to the +user in different ways.

    +

    The specific alerts, that all derives from alert, are:

    +
    +

    tracker_alert

    +

    This alert is generated on tracker time outs, premature disconnects, invalid response or +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
    +{
    +        tracker_alert(const torrent_handle& h, const std::string& msg);
    +        virtual std::auto_ptr<alert> clone() const;
    +
    +        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
    +{
    +        hash_failed_alert(
    +                const torrent_handle& h
    +                , int index
    +                , const std::string& msg);
    +
    +        virtual std::auto_ptr<alert> clone() const;
    +
    +        torrent_handle handle;
    +        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;
    +};
    +
    +
    +
    +

    chat_message_alert

    +

    This alert is generated when you receive a chat message from another peer. Chat messages +are supported as an extension ("chat"). It is generated as severity level critical, +even though it doesn't necessarily require any user intervention, it's high priority +since you would almost never want to ignore such a message. The alert class contain +a torrent_handle to the torrent in which the sender-peer is a member and the peer_id +of the sending peer.

    +
    +struct chat_message_alert: alert
    +{
    +        chat_message_alert(const torrent_handle& h
    +                , const peer_id& sender
    +                , const std::string& msg);
    +
    +        virtual std::auto_ptr<alert> clone() const;
    +
    +        torrent_handle handle;
    +        peer_id sender;
    +};
    +
    +
    +
    +

    dispatcher

    +

    TODO: describe the dispatcher mechanism

    +
    +
    +
    +

    exceptions

    +

    There are a number of exceptions that can be thrown from different places in libtorrent, +here's a complete list with description.

    +
    +

    invalid_handle

    +

    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
    +{
    +        const char* what() const throw();
    +};
    +
    +
    +
    +

    duplicate_torrent

    +

    This is thrown by session::add_torrent() if the torrent already has been added to +the session.

    +
    +struct duplicate_torrent: std::exception
    +{
    +        const char* what() const throw();
    +};
    +
    +
    +
    +

    invalid_encoding

    +

    This is thrown by bdecode() if the input data is not a valid bencoding.

    +
    +struct invalid_encoding: std::exception
    +{
    +        const char* what() const throw();
    +};
    +
    +
    +
    +

    type_error

    +

    This is thrown from the accessors of entry if the data type of the entry doesn't +match the type you want to extract from it.

    +
    +struct type_error: std::runtime_error
    +{
    +        type_error(const char* error);
    +};
    +
    +
    +
    +

    invalid_torrent_file

    +

    This exception is thrown from the constructor of torrent_info if the given bencoded information +doesn't meet the requirements on what information has to be present in a torrent file.

    +
    +struct invalid_torrent_file: std::exception
    +{
    +        const char* what() const throw();
    +};
    +
    +
    +
    +
    +

    examples

    +
    +

    dump_torrent

    +

    This is an example of a program that will take a torrent-file as a parameter and +print information about it to std out:

    +
    +#include <iostream>
    +#include <fstream>
    +#include <iterator>
    +#include <exception>
    +#include <iomanip>
    +
    +#include "libtorrent/entry.hpp"
    +#include "libtorrent/bencode.hpp"
    +#include "libtorrent/torrent_info.hpp"
    +
    +
    +int main(int argc, char* argv[])
    +{
    +        using namespace libtorrent;
    +
    +        if (argc != 2)
    +        {
    +                std::cerr << "usage: dump_torrent torrent-file\n";
    +                return 1;
    +        }
    +
    +        try
    +        {
    +                std::ifstream in(argv[1], std::ios_base::binary);
    +                in.unsetf(std::ios_base::skipws);
    +                entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
    +                torrent_info t(e);
    +
    +                // print info about torrent
    +                std::cout << "\n\n----- torrent file info -----\n\n";
    +                std::cout << "trackers:\n";
    +                for (std::vector<announce_entry>::const_iterator i = t.trackers().begin();
    +                        i != t.trackers().end();
    +                        ++i)
    +                {
    +                        std::cout << i->tier << ": " << i->url << "\n";
    +                }
    +
    +                std::cout << "number of pieces: " << t.num_pieces() << "\n";
    +                std::cout << "piece length: " << t.piece_length() << "\n";
    +                std::cout << "files:\n";
    +                for (torrent_info::file_iterator i = t.begin_files();
    +                        i != t.end_files();
    +                        ++i)
    +                {
    +                        std::cout << "  " << std::setw(11) << i->size
    +                        << "  " << i->path << " " << i->filename << "\n";
    +                }
    +                
    +        }
    +        catch (std::exception& e)
    +        {
    +                std::cout << e.what() << "\n";
    +        }
    +
    +        return 0;
    +}
    +
    +
    +
    +

    simple client

    +

    This is a simple client. It doesn't have much output to keep it simple:

    +
    +#include <iostream>
    +#include <fstream>
    +#include <iterator>
    +#include <exception>
    +
    +#include <boost/format.hpp>
    +#include <boost/date_time/posix_time/posix_time.hpp>
    +
    +#include "libtorrent/entry.hpp"
    +#include "libtorrent/bencode.hpp"
    +#include "libtorrent/session.hpp"
    +#include "libtorrent/http_settings.hpp"
    +
    +int main(int argc, char* argv[])
    +{
    +        using namespace libtorrent;
    +
    +        if (argc != 2)
    +        {
    +                std::cerr << "usage: ./simple_cient torrent-file\n"
    +                        "to stop the client, press return.\n";
    +                return 1;
    +        }
    +
    +        try
    +        {
    +                session s(6881);
    +
    +                std::ifstream in(argv[1], std::ios_base::binary);
    +                in.unsetf(std::ios_base::skipws);
    +                entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
    +                torrent_info t(e);
    +                s.add_torrent(t, "");
    +                        
    +                // wait for the user to end
    +                char a;
    +                std::cin.unsetf(std::ios_base::skipws);
    +                std::cin >> a;
    +        }
    +        catch (std::exception& e)
    +        {
    +                std::cout << e.what() << "\n";
    +        }
    +        return 0;
    +}
    +
    +
    +
    +
    +

    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 blocks, 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

    +

    TODO: describe the file format

    +
    +
    +

    extensions

    +

    These extensions all operates within the extension protocol. The +name of the extension is the name used in the extension-list packets, +and the payload is the data in the extended message (not counting the +length-prefix, message-id nor extension-id).

    +

    These are the extensions that are currently implemented.

    +
    +

    chat messages

    +

    Extension name: "chat"

    +

    The payload in the packet is a bencoded dictionary with any +combination of the following entries:

    + ++++ + + + + + + + + +
    "msg"This is a string that contains a message that +should be displayed to the user.
    "ctrl"This is a control string that can tell a client that +it is ignored (to make the user aware of that) and +it can also tell a client that it is no longer ignored. +These notifications are encoded as the strings: +"ignored" and "not ignored". +Any unrecognized strings should be ignored.
    +
    +
    +
    +

    Aknowledgements

    +

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

    +

    Contributions by Magnus Jonsson

    +

    Thanks to Reimond Retz for bugfixes, suggestions and testing

    +

    Project is hosted by sourceforge.

    +

    sf_logo

    +
    +
    + + diff --git a/docs/manual.rst b/docs/manual.rst new file mode 100755 index 000000000..7265e3334 --- /dev/null +++ b/docs/manual.rst @@ -0,0 +1,1353 @@ +================= +libtorrent manual +================= + +.. 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 and the maximum number of unchoked peers + * 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. + * The extension protocol `described by Nolar`__. See extensions_. + +__ http://home.elp.rr.com/tur/multitracker-spec.txt +.. _Azureus: http://azureus.sourceforge.net +__ http://nolar.com/azureus/extended.htm + +Functions that are yet to be implemented: + + * number of connections limit + * better handling of peers that send bad data + * ip-filters + * file-level piece priority + +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 as well as zlib. + +libtorrent has been successfully compiled and tested on: + + * Cygwin GCC 3.3.1 + * Windows 2000 vc7.1 + * Linux x86 (debian) GCC 3.0 + +It does not compile on + + * GCC 2.95 + +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', +'boost-1.30.2/libs/date_time/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. + +The basic usage is as follows: + +* conststruct a session +* parse .torrent-files and add them to the session +* main loop + * query the torrent_handles for progress + * query the session for information + * add and remove torrents from the session at run-time +* destruct all torrent_handles +* destruct session object + +Each class and function is described in this manual. + + + +session +======= + +The ``session`` class has the following synopsis:: + + class session: public boost::noncopyable + { + session(int listen_port, const fingerprint& print); + session(int listen_port); + + torrent_handle add_torrent( + const torrent_info& t + , const std::string& save_path + , const entry& resume_data = entry()); + + void remove_torrent(const torrent_handle& h); + + void set_http_settings(const http_settings& settings); + void set_upload_rate_limit(int bytes_per_second); + + std::auto_ptr pop_alert(); + void set_severity_level(alert::severity_t s); + + }; + +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. ``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 +for checking, being checked or downloading) ``add_torrent()`` will throw +``duplicate_torrent`` which derives from ``std::exception``. + +The difference between the two constructors is that one of them takes a fingerprint +as argument. If this is ommited, the client will get a default fingerprint stating +the version of libtorrent. The fingerprint is a short string that will be used in +the peer-id to identify the client and the client's version. For more details see the +fingerprint class. + +``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.* + +For information about the ``pop_alert()`` function, see alerts_. + + + +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_. + +If ``bdecode()`` encounters invalid encoded data in the range given to it +it will throw invalid_encoding_. + + + +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(const dictionary_type&); + entry(const string_type&); + entry(const list_type&); + entry(const integer_type&); + + entry(); + entry(data_type t); + entry(const entry& e); + + ~entry(); + + void operator=(const entry& e); + void operator=(const dictionary_type&); + void operator=(const string_type&); + void operator=(const list_type&); + void operator=(const integer_type&); + + 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. + +__ 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(); + void get_download_queue(std::vector& queue); + void get_peer_info(std::vector& v); + const torrent_info& get_torrent_info(); + bool is_valid(); + + entry write_resume_data(); + + boost::filsystem::path save_path() const; + + void set_max_uploads(int max_uploads); + + sha1_hash info_hash() const; + + bool operator==(const torrent_handle&) const; + bool operator!=(const torrent_handle&) const; + bool operator<(const torrent_handle&) const; + }; + +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 on an uninitialized handle, it will throw ``invalid_handle``. + +``save_path()`` returns the path that was given to ``add_torrent()`` when this torrent +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()`` generates fast-resume data and returns it as an entry. This entry +is suitable for being bencoded. For more information about how fast-resume works, see `fast resume`_. +It may throw invalid_handle_ if the torrent handle is invalid. + +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. +It contains the following fields:: + + struct torrent_status + { + enum state_t + { + invalid_handle, + queued_for_checking, + checking_files, + connecting_to_tracker, + 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::size_t total_payload_download; + std::size_t total_payload_upload; + + float download_rate; + float upload_rate; + + 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: + ++--------------------------+----------------------------------------------------------+ +|``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. | +| | | ++--------------------------+----------------------------------------------------------+ +|``connecting_to_tracker`` |The torrent has sent a request to the tracker and is | +| |currently waiting for a response | +| | | ++--------------------------+----------------------------------------------------------+ +|``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. + +``total_payload_download`` and ``total_payload_upload`` counts the amount of bytes +send and received this session, but only the actual oayload data (i.e the interesting +data), these counters ignore any protocol overhead. + +``pieces`` is the bitmask that representw which pieces we have (set to true) and +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. 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. + +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, given the handle is valid. If the +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:: + + struct peer_info + { + enum + { + interesting = 0x1, + choked = 0x2, + remote_interested = 0x4, + remote_choked = 0x8, + supports_extensions = 0x10 + }; + 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; + int upload_ceiling; + + int load_balancing; + + int downloading_piece_index; + int downloading_block_index; + int downloading_progress; + int downloading_total; + }; + +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**. ``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 +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. The upload limits of all peers +should sum up to the upload limit set by ``session::set_upload_limit``. + +``upload_ceiling`` is the current maximum allowed upload rate given the cownload +rate and share ratio. If the global upload rate is inlimited, the ``upload_limit`` +for every peer will be the same as their ``upload_ceiling``. + +``load_balancing`` is a measurment of the balancing of free download (that we get) +and free upload that we give. Every peer gets a certain amount of free upload, but +this member says how much *extra* free upload this peer has got. If it is a negative +number it means that this was a peer from which we have got this amount of free +download. + +You can know which piece, and which part of that piece, that is currently being +downloaded from a specific peer by looking at the next four members. +``downloading_piece_index`` is the index of the piece that is currently being downloaded. +This may be set to -1 if there's currently no piece downloading from this peer. If it is +>= 0, the other three members are valid. ``downloading_block_index`` is the index of the +block (or sub-piece) that is being downloaded. ``downloading_progress`` is the number +of bytes of this block we have received from the peer, and ``downloading_total`` is +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. + + +is_valid() +---------- + +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. + + + +address +======= + +The ``address`` 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 ``sockaddr_in`` would contain. +Its declaration looks like this:: + + class address + { + public: + address(); + address(unsigned char a + , unsigned char b + , unsigned char c + , unsigned char d + , unsigned short port); + address(unsigned int addr, unsigned short port); + address(const std::string& addr, unsigned short port); + address(const address& a); + ~address(); + + std::string as_string() const; + unsigned int ip() const; + unsigned short port() const; + + bool operator<(const address& a) const; + bool operator!=(const address& a) const; + bool operator==(const address& a) const; + }; + +It is less-than comparable to make it possible to use it as a key in a map. ``as_string()`` may block +while it does the DNS lookup, it returns a string that points to the address represented by the object. + +``ip()`` will return the 32-bit ip-address as an integer. ``port()`` returns the port number. + + + + +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; + }; + +``proxy_ip`` may be a hostname or ip to a http proxy to use. If this is +an empty string, no http proxy will be used. + +``proxy_port`` is the port on which the http proxy listens. If ``proxy_ip`` +is empty, this will be ignored. + +``proxy_login`` should be the login username for the http proxy, if this +empty, the http proxy will be trid to be used without authentication. + +``proxy_password`` the password string for the http proxy. + +``user_agent`` this is the client identification to the tracker. It will +be followed by the string "(libtorrent)" to identify that this library +is being used. This should be set to your client's name and version number. + +``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``. + + +fingerprint +=========== + +The fingerprint class represents information about a client and its version. It is used +to encode this information into the client's peer id. + +This is the class declaration:: + + struct fingerprint + { + fingerprint(const char* id_string, int major, int minor, int revision, int tag); + + std::string to_string() const; + + char id[2]; + char major_version; + char minor_version; + char revision_version; + char tag_version; + + }; + +The constructor takes a ``const char*`` that should point to a string constant containing +exactly two characters. These are the characters that should be unique for your client. Make +sure not to clash with anybody else. Here are some taken id's: + ++----------+-----------------------+ +| id chars | client | ++==========+=======================+ +| 'AZ' | Azureus | ++----------+-----------------------+ +| 'LT' | libtorrent (default) | ++----------+-----------------------+ +| 'BX' | BittorrentX | ++----------+-----------------------+ +| 'MT' | Moonlight Torrent | ++----------+-----------------------+ + + +The ``major``, ``minor``, ``revision`` and ``tag`` parameters are used to identify the +version of your client. All these numbers must be within the range [0, 9]. + +``to_string()`` will generate the actual string put in the peer-id, and return it. + +alerts +====== + +The ``pop_alert()`` function on session is the interface for retrieving +alerts, warnings, messages and errors from libtorrent. If there hasn't +occured any errors (matching your severity level) ``pop_alert()`` will +return a zero pointer. If there has been some error, it will return a pointer +to an alert object describing it. You can then use the alert object and query +it for information about the error or message. To retrieve any alerts, you have +to select a severity level using ``session::set_severity_level()``. It defaults to +``alert::none``, which means that you don't get any messages at all, ever. +You have the following levels to select among: + ++--------------+----------------------------------------------------------+ +| ``none`` | No alert will ever have this severity level, which | +| | effectively filters all messages. | +| | | ++--------------+----------------------------------------------------------+ +| ``fatal`` | Fatal errors will have this severity level. Examples can | +| | be disk full or something else that will make it | +| | impossible to continue normal execution. | +| | | ++--------------+----------------------------------------------------------+ +| ``critical`` | Signals errors that requires user interaction or | +| | messages that almost never should be ignored. For | +| | example, a chat message received from another peer is | +| | announced as severity ``critical``. | +| | | ++--------------+----------------------------------------------------------+ +| ``warning`` | Messages with the warning severity can be a tracker that | +| | times out or responds with invalid data. It will be | +| | retried automatically, and the possible next tracker in | +| | a multitracker sequence will be tried. It does not | +| | require any user interaction. | +| | | ++--------------+----------------------------------------------------------+ +| ``info`` | Events that can be considered normal, but still deserves | +| | an event. This could be a piece hash that fails. | +| | | ++--------------+----------------------------------------------------------+ +| ``debug`` | This will include alot of debug events that can be used | +| | both for debugging libtorrent but also when debugging | +| | other clients that are connected to libtorrent. It will | +| | report strange behaviors among the connected peers. | +| | | ++--------------+----------------------------------------------------------+ + +When setting a severity level, you will receive messages of that severity and all +messages that are more sever. If you set ``alert::none`` (the default) you will not recieve +any events at all. + +When you set a severuty level other than ``none``, you have the responsibility to call +``pop_alert()`` from time to time. If you don't do that, the alert queue will just grow. + +When you get an alert, you can use ``typeid()`` or ``dynamic_cast<>`` to get more detailed +information on exactly which type it is. i.e. what kind of error it is. You can also use a +dispatcher_ mechanism that's available in libtorrent. + +The ``alert`` class is the base class that specific messages are derived from. This +is its synopsis:: + + class alert + { + public: + + enum severity_t { debug, info, warning, critital, fatal, none }; + + alert(severity_t severity, const std::string& msg); + virtual ~alert(); + + const std::string& msg() const; + severity_t severity() const; + + virtual std::auto_ptr clone() const = 0; + }; + +This means that all alerts have at least a string describing it. They also +have a severity leve that can be used to sort them or present them to the +user in different ways. + +The specific alerts, that all derives from ``alert``, are: + + +tracker_alert +------------- + +This alert is generated on tracker time outs, premature disconnects, invalid response or +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 + { + tracker_alert(const torrent_handle& h, const std::string& msg); + virtual std::auto_ptr clone() const; + + 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 + { + hash_failed_alert( + const torrent_handle& h + , int index + , const std::string& msg); + + virtual std::auto_ptr clone() const; + + torrent_handle handle; + 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 clone() const; + + peer_id id; + }; + + + +chat_message_alert +------------------ + +This alert is generated when you receive a chat message from another peer. Chat messages +are supported as an extension ("chat"). It is generated as severity level ``critical``, +even though it doesn't necessarily require any user intervention, it's high priority +since you would almost never want to ignore such a message. The alert class contain +a torrent_handle_ to the torrent in which the sender-peer is a member and the peer_id +of the sending peer. + +:: + + struct chat_message_alert: alert + { + chat_message_alert(const torrent_handle& h + , const peer_id& sender + , const std::string& msg); + + virtual std::auto_ptr clone() const; + + torrent_handle handle; + peer_id sender; + }; + + +dispatcher +---------- + +TODO: describe the dispatcher mechanism + + + +exceptions +========== + +There are a number of exceptions that can be thrown from different places in libtorrent, +here's a complete list with description. + + +invalid_handle +-------------- + +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 + { + const char* what() const throw(); + }; + + +duplicate_torrent +----------------- + +This is thrown by ``session::add_torrent()`` if the torrent already has been added to +the session. + +:: + + struct duplicate_torrent: std::exception + { + const char* what() const throw(); + }; + + +invalid_encoding +---------------- + +This is thrown by ``bdecode()`` if the input data is not a valid bencoding. + +:: + + struct invalid_encoding: std::exception + { + const char* what() const throw(); + }; + + +type_error +---------- + +This is thrown from the accessors of ``entry`` if the data type of the ``entry`` doesn't +match the type you want to extract from it. + +:: + + struct type_error: std::runtime_error + { + type_error(const char* error); + }; + + +invalid_torrent_file +-------------------- + +This exception is thrown from the constructor of ``torrent_info`` if the given bencoded information +doesn't meet the requirements on what information has to be present in a torrent file. + +:: + + struct invalid_torrent_file: std::exception + { + const char* what() const throw(); + }; + + +examples +======== + +dump_torrent +------------ + +This is an example of a program that will take a torrent-file as a parameter and +print information about it to std out:: + + #include + #include + #include + #include + #include + + #include "libtorrent/entry.hpp" + #include "libtorrent/bencode.hpp" + #include "libtorrent/torrent_info.hpp" + + + int main(int argc, char* argv[]) + { + using namespace libtorrent; + + if (argc != 2) + { + std::cerr << "usage: dump_torrent torrent-file\n"; + return 1; + } + + try + { + std::ifstream in(argv[1], std::ios_base::binary); + in.unsetf(std::ios_base::skipws); + entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); + torrent_info t(e); + + // print info about torrent + std::cout << "\n\n----- torrent file info -----\n\n"; + std::cout << "trackers:\n"; + for (std::vector::const_iterator i = t.trackers().begin(); + i != t.trackers().end(); + ++i) + { + std::cout << i->tier << ": " << i->url << "\n"; + } + + std::cout << "number of pieces: " << t.num_pieces() << "\n"; + std::cout << "piece length: " << t.piece_length() << "\n"; + std::cout << "files:\n"; + for (torrent_info::file_iterator i = t.begin_files(); + i != t.end_files(); + ++i) + { + std::cout << " " << std::setw(11) << i->size + << " " << i->path << " " << i->filename << "\n"; + } + + } + catch (std::exception& e) + { + std::cout << e.what() << "\n"; + } + + return 0; + } + + +simple client +------------- + +This is a simple client. It doesn't have much output to keep it simple:: + + #include + #include + #include + #include + + #include + #include + + #include "libtorrent/entry.hpp" + #include "libtorrent/bencode.hpp" + #include "libtorrent/session.hpp" + #include "libtorrent/http_settings.hpp" + + int main(int argc, char* argv[]) + { + using namespace libtorrent; + + if (argc != 2) + { + std::cerr << "usage: ./simple_cient torrent-file\n" + "to stop the client, press return.\n"; + return 1; + } + + try + { + session s(6881); + + std::ifstream in(argv[1], std::ios_base::binary); + in.unsetf(std::ios_base::skipws); + entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); + torrent_info t(e); + s.add_torrent(t, ""); + + // wait for the user to end + char a; + std::cin.unsetf(std::ios_base::skipws); + std::cin >> a; + } + catch (std::exception& e) + { + std::cout << e.what() << "\n"; + } + return 0; + } + + +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 blocks, 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 +=========== + +TODO: describe the file format + +extensions +========== + +These extensions all operates within the `extension protocol`__. The +name of the extension is the name used in the extension-list packets, +and the payload is the data in the extended message (not counting the +length-prefix, message-id nor extension-id). + +__ http://nolar.com/azureus/extended.html + +These are the extensions that are currently implemented. + +chat messages +------------- + +Extension name: "chat" + +The payload in the packet is a bencoded dictionary with any +combination of the following entries: + ++----------+--------------------------------------------------------+ +| "msg" | This is a string that contains a message that | +| | should be displayed to the user. | ++----------+--------------------------------------------------------+ +| "ctrl" | This is a control string that can tell a client that | +| | it is ignored (to make the user aware of that) and | +| | it can also tell a client that it is no longer ignored.| +| | These notifications are encoded as the strings: | +| | "ignored" and "not ignored". | +| | Any unrecognized strings should be ignored. | ++----------+--------------------------------------------------------+ + + + +Aknowledgements +=============== + +Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003 + +Contributions by Magnus Jonsson + +Thanks to Reimond Retz for bugfixes, suggestions and testing + +Project is hosted by sourceforge. + +|sf_logo|__ + +.. |sf_logo| image:: http://sourceforge.net/sflogo.php?group_id=7994 +__ http://sourceforge.net + + diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 6352e2858..366d22db1 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -206,10 +206,8 @@ int main(int argc, char* argv[]) std::ifstream resume_file("test.fastresume", std::ios_base::binary); resume_file.unsetf(std::ios_base::skipws); - std::vector resume_data; - std::copy(std::istream_iterator(resume_file) - , std::istream_iterator() - , std::back_inserter(resume_data)); + entry resume_data = bdecode(std::istream_iterator(resume_file) + , std::istream_iterator()); handles.push_back(ses.add_torrent(t, "", resume_data)); handles.back().set_max_uploads(40); @@ -230,12 +228,11 @@ int main(int argc, char* argv[]) { if (c == 'q') { - std::vector data; - handles.front().write_resume_data(data); + entry data = handles.front().write_resume_data(); std::ofstream out("test.fastresume", std::ios_base::binary); out.unsetf(std::ios_base::skipws); - std::copy(data.begin(), data.end(), std::ostream_iterator(out)); + bencode(std::ostream_iterator(out), data); break; } } @@ -313,8 +310,7 @@ int main(int argc, char* argv[]) << "(" << add_suffix(i->total_download) << ") " << "u: " << add_suffix(i->up_speed) << "/s " << "(" << add_suffix(i->total_upload) << ") " -// << "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " " - << "q: " << i->download_queue_length << " " + << "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " " << "f: " << static_cast((i->flags & peer_info::interesting)?"I":"_") << static_cast((i->flags & peer_info::choked)?"C":"_") @@ -336,13 +332,8 @@ int main(int argc, char* argv[]) if (progress > j) out << "#"; else out << "-"; } - out << " "; + out << "\n"; } - else - { - for (int i = 0; i < 19; ++i) out << " "; - } - out << identify_client(i->id) << "\n"; } out << "___________________________________\n"; diff --git a/examples/dump_torrent.cpp b/examples/dump_torrent.cpp index 5d2b4d9ca..a3a5a0445 100755 --- a/examples/dump_torrent.cpp +++ b/examples/dump_torrent.cpp @@ -55,7 +55,6 @@ int main(int argc, char* argv[]) std::ifstream in(argv[1], std::ios_base::binary); in.unsetf(std::ios_base::skipws); entry e = bdecode(std::istream_iterator(in), std::istream_iterator()); - torrent_info t(e); @@ -63,6 +62,8 @@ int main(int argc, char* argv[]) e.print(std::cout); + torrent_info t(e); + // print info about torrent std::cout << "\n\n----- torrent file info -----\n\n"; std::cout << "trackers:\n"; diff --git a/include/libtorrent/alert.hpp b/include/libtorrent/alert.hpp index e9cecf7d3..00665a44d 100755 --- a/include/libtorrent/alert.hpp +++ b/include/libtorrent/alert.hpp @@ -51,7 +51,7 @@ namespace libtorrent { class alert { public: - enum severity_t { debug, info, warning, critital, fatal, none }; + enum severity_t { debug, info, warning, critical, fatal, none }; alert(severity_t severity, const std::string& msg) : m_msg(msg) diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index 24e7cdd75..6991f61c6 100755 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -129,6 +129,11 @@ namespace libtorrent data_type type() const { return m_type; } + entry(const dictionary_type&); + entry(const string_type&); + entry(const list_type&); + entry(const integer_type&); + entry(): m_type(undefined_t) {} entry(data_type t): m_type(t) { construct(t); } entry(const entry& e) { copy(e); } @@ -140,6 +145,11 @@ namespace libtorrent copy(e); } + void operator=(const dictionary_type&); + void operator=(const string_type&); + void operator=(const list_type&); + void operator=(const integer_type&); + integer_type& integer() { if (m_type != int_t) throw type_error("invalid typ requested from entry"); diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 69553f356..5164066af 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include @@ -50,6 +51,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/piece_picker.hpp" #include "libtorrent/stat.hpp" #include "libtorrent/debug.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/torrent_handle.hpp" // TODO: each time a block is 'taken over' // from another peer. That peer must be given @@ -135,6 +138,23 @@ namespace libtorrent protocol_error(const std::string& msg): std::runtime_error(msg) {}; }; + struct chat_message_alert: alert + { + chat_message_alert(const torrent_handle& h + , const peer_id& send + , const std::string& msg) + : alert(alert::critical, msg) + , handle(h) + , sender(send) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new chat_message_alert(*this)); } + + torrent_handle handle; + peer_id sender; + }; + struct peer_request { int piece; @@ -336,6 +356,7 @@ namespace libtorrent void send_have(int index); void send_handshake(); void send_extensions(); + void send_chat_message(const std::string& msg); // is used during handshake enum state @@ -519,7 +540,7 @@ namespace libtorrent enum extension_index { - gzip_piece, + extended_chat_message, num_supported_extensions }; static const char* extension_names[num_supported_extensions]; diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp index 10ab4aab1..3e257f489 100755 --- a/include/libtorrent/session.hpp +++ b/include/libtorrent/session.hpp @@ -116,7 +116,7 @@ namespace libtorrent sha1_hash info_hash; void parse_resume_data( - const std::vector* rd + const entry& rd , const torrent_info& info); std::vector piece_map; std::vector unfinished_pieces; @@ -225,20 +225,10 @@ namespace libtorrent ~session(); // all torrent_handles must be destructed before the session is destructed! - torrent_handle add_torrent( - const torrent_info& ti - , const boost::filesystem::path& save_path) - { - return add_torrent_impl(ti, save_path, 0); - } - torrent_handle add_torrent( const torrent_info& ti , const boost::filesystem::path& save_path - , const std::vector& resume_data) - { - return add_torrent_impl(ti, save_path, &resume_data); - } + , const entry& resume_data = entry()); void remove_torrent(const torrent_handle& h); @@ -252,11 +242,6 @@ namespace libtorrent private: - torrent_handle add_torrent_impl( - const torrent_info& ti - , const boost::filesystem::path& save_path - , const std::vector* resume_data); - // data shared between the main thread // and the working thread detail::session_impl m_impl; diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 6543f834e..614c24dc0 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -247,6 +247,9 @@ namespace libtorrent boost::filesystem::path save_path() const { return m_storage.save_path(); } + alert_manager& alerts() const; + torrent_handle get_handle() const; + // DEBUG #ifndef NDEBUG logger* spawn_logger(const char* title); diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 6ca46e103..5f2459cdb 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -133,7 +133,7 @@ namespace libtorrent const torrent_info& get_torrent_info() const; bool is_valid() const; - void write_resume_data(std::vector& buf); + entry write_resume_data(); // TODO: add force reannounce diff --git a/src/entry.cpp b/src/entry.cpp index da37e6c77..631f0d54a 100755 --- a/src/entry.cpp +++ b/src/entry.cpp @@ -49,127 +49,183 @@ namespace } } -void libtorrent::entry::construct(data_type t) +namespace libtorrent { - m_type = t; - switch(m_type) - { - case int_t: - new(data) integer_type; - break; - case string_t: - new(data) string_type; - break; - case list_t: - new(data) list_type; - break; - case dictionary_t: - new (data) dictionary_type; - break; - default: - m_type = undefined_t; - } -} -void libtorrent::entry::copy(const entry& e) -{ - m_type = e.m_type; - switch(m_type) + entry::entry(const dictionary_type& v) { - case int_t: - new(data) integer_type(e.integer()); - break; - case string_t: - new(data) string_type(e.string()); - break; - case list_t: - new(data) list_type(e.list()); - break; - case dictionary_t: - new (data) dictionary_type(e.dict()); - break; - default: - m_type = undefined_t; + new(data) dictionary_type(v); + m_type = dictionary_t; } -} -void libtorrent::entry::destruct() -{ - switch(m_type) + entry::entry(const string_type& v) { - case int_t: - call_destructor(reinterpret_cast(data)); - break; - case string_t: - call_destructor(reinterpret_cast(data)); - break; - case list_t: - call_destructor(reinterpret_cast(data)); - break; - case dictionary_t: - call_destructor(reinterpret_cast(data)); - break; - default: - break; + new(data) string_type(v); + m_type = string_t; } -} -void libtorrent::entry::print(std::ostream& os, int indent) const -{ - for (int i = 0; i < indent; ++i) os << " "; - switch (m_type) + entry::entry(const list_type& v) { - case int_t: - os << integer() << "\n"; - break; - case string_t: + new(data) list_type(v); + m_type = list_t; + } + + entry::entry(const integer_type& v) + { + new(data) integer_type(v); + m_type = int_t; + } + + void entry::operator=(const dictionary_type& v) + { + destruct(); + new(data) dictionary_type(v); + m_type = dictionary_t; + } + + void entry::operator=(const string_type& v) + { + destruct(); + new(data) string_type(v); + m_type = string_t; + } + + void entry::operator=(const list_type& v) + { + destruct(); + new(data) list_type(v); + m_type = list_t; + } + + void entry::operator=(const integer_type& v) + { + destruct(); + new(data) integer_type(v); + m_type = int_t; + } + + + void entry::construct(data_type t) + { + m_type = t; + switch(m_type) { - bool binary_string = false; - for (std::string::const_iterator i = string().begin(); i != string().end(); ++i) + case int_t: + new(data) integer_type; + break; + case string_t: + new(data) string_type; + break; + case list_t: + new(data) list_type; + break; + case dictionary_t: + new (data) dictionary_type; + break; + default: + m_type = undefined_t; + } + } + + void entry::copy(const entry& e) + { + m_type = e.m_type; + switch(m_type) + { + case int_t: + new(data) integer_type(e.integer()); + break; + case string_t: + new(data) string_type(e.string()); + break; + case list_t: + new(data) list_type(e.list()); + break; + case dictionary_t: + new (data) dictionary_type(e.dict()); + break; + default: + m_type = undefined_t; + } + } + + void entry::destruct() + { + switch(m_type) + { + case int_t: + call_destructor(reinterpret_cast(data)); + break; + case string_t: + call_destructor(reinterpret_cast(data)); + break; + case list_t: + call_destructor(reinterpret_cast(data)); + break; + case dictionary_t: + call_destructor(reinterpret_cast(data)); + break; + default: + break; + } + } + + void entry::print(std::ostream& os, int indent) const + { + for (int i = 0; i < indent; ++i) os << " "; + switch (m_type) + { + case int_t: + os << integer() << "\n"; + break; + case string_t: { - if (!std::isprint(static_cast(*i))) - { - binary_string = true; - break; - } - } - if (binary_string) - { - os.unsetf(std::ios_base::dec); - os.setf(std::ios_base::hex); + bool binary_string = false; for (std::string::const_iterator i = string().begin(); i != string().end(); ++i) - os << static_cast((unsigned char)*i); - os.unsetf(std::ios_base::hex); - os.setf(std::ios_base::dec); - os << "\n"; - } - else + { + if (!std::isprint(static_cast(*i))) + { + binary_string = true; + break; + } + } + if (binary_string) + { + os.unsetf(std::ios_base::dec); + os.setf(std::ios_base::hex); + for (std::string::const_iterator i = string().begin(); i != string().end(); ++i) + os << static_cast((unsigned char)*i); + os.unsetf(std::ios_base::hex); + os.setf(std::ios_base::dec); + os << "\n"; + } + else + { + os << string() << "\n"; + } + } break; + case list_t: { - os << string() << "\n"; - } - } break; - case list_t: - { - os << "list\n"; - for (list_type::const_iterator i = list().begin(); i != list().end(); ++i) + os << "list\n"; + for (list_type::const_iterator i = list().begin(); i != list().end(); ++i) + { + i->print(os, indent+1); + } + } break; + case dictionary_t: { - i->print(os, indent+1); - } - } break; - case dictionary_t: - { - os << "dictionary\n"; - for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i) - { - for (int j = 0; j < indent+1; ++j) os << " "; - os << "[" << i->first << "]"; - if (i->second.type() != entry::string_t && i->second.type() != entry::int_t) os << "\n"; - else os << " "; - i->second.print(os, indent+2); - } - } break; - default: - os << "\n"; + os << "dictionary\n"; + for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i) + { + for (int j = 0; j < indent+1; ++j) os << " "; + os << "[" << i->first << "]"; + if (i->second.type() != entry::string_t && i->second.type() != entry::int_t) os << "\n"; + else os << " "; + i->second.print(os, indent+2); + } + } break; + default: + os << "\n"; + } } } - diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 3e6d6cab8..862f95316 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -52,7 +52,7 @@ namespace libtorrent // the names of the extensions to look for in // the extensions-message const char* peer_connection::extension_names[] = - { "gzip" }; + { "chat" }; const peer_connection::message_handler peer_connection::m_message_handler[] = { @@ -728,7 +728,57 @@ namespace libtorrent void peer_connection::on_extended(int received) { - + m_statistics.received_bytes(0, received); + if (m_packet_size < 5) + throw protocol_error("'extended' message smaller than 5 bytes"); + + if (m_torrent == 0) + throw protocol_error("'extended' message sent before proper handshake"); + + + if (m_recv_pos < 5) return; + + const char* ptr = &m_recv_buffer[1]; + + int extended_id = detail::read_int(ptr); + + switch (extended_id) + { + case extended_chat_message: + { + if (m_packet_size > 2 * 1024) + if (m_recv_pos < m_packet_size) return; + throw protocol_error("CHAT message larger than 2 kB"); + try + { + entry d = bdecode(m_recv_buffer.begin()+5, m_recv_buffer.end()); + entry::dictionary_type::const_iterator i = d.dict().find("msg"); + if (i == d.dict().end()) + throw protocol_error("CHAT message did not contain any 'msg'"); + + const std::string& str = i->second.string(); + + if (m_torrent->alerts().should_post(alert::critical)) + { + m_torrent->alerts() + .post_alert(chat_message_alert(m_torrent->get_handle(), m_peer_id, str)); + } + + } + catch (invalid_encoding& e) + { + throw protocol_error("invalid bencoding in CHAT message"); + } + catch (type_error& e) + { + throw protocol_error("invalid types in bencoded CHAT message"); + } + return; + } + default: + throw protocol_error("unknown extended message id"); + + }; } @@ -746,6 +796,7 @@ namespace libtorrent { assert(m_recv_pos >= received); assert(m_recv_pos > 0); + assert(m_torrent); int packet_type = m_recv_buffer[0]; if (packet_type < 0 @@ -853,6 +904,25 @@ namespace libtorrent send_buffer_updated(); } + void peer_connection::send_chat_message(const std::string& msg) + { + assert(msg.length() <= 1 * 1024); + if (m_extension_messages[extended_chat_message] == 0) return; + + entry e(entry::dictionary_t); + e.dict()["msg"] = msg; + + std::vector message; + bencode(std::back_inserter(message), e); + std::back_insert_iterator > ptr(m_send_buffer); + + detail::write_uint(1 + 4 + message.size(), ptr); + detail::write_uchar(msg_extended, ptr); + detail::write_int(m_extension_messages[extended_chat_message], ptr); + std::copy(message.begin(), message.end(), ptr); + send_buffer_updated(); + } + void peer_connection::send_bitfield() { #ifndef NDEBUG @@ -884,9 +954,7 @@ namespace libtorrent for (int i = 0; i < num_supported_extensions; ++i) { - entry msg_index(entry::int_t); - msg_index.integer() = i; - extension_list.dict()[extension_names[i]] = msg_index; + extension_list.dict()[extension_names[i]] = i; } // make room for message size diff --git a/src/session.cpp b/src/session.cpp index b45287147..d44639ab5 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/session.hpp" #include "libtorrent/fingerprint.hpp" +#include "libtorrent/entry.hpp" #if defined(_MSC_VER) && _MSC_VER < 1300 namespace std @@ -751,10 +752,10 @@ namespace libtorrent // TODO: add a check to see if filenames are accepted on the // current platform. // if the torrent already exists, this will throw duplicate_torrent - torrent_handle session::add_torrent_impl( + torrent_handle session::add_torrent( const torrent_info& ti , const boost::filesystem::path& save_path - , const std::vector* resume_data) + , const entry& resume_data) { { @@ -886,6 +887,97 @@ namespace libtorrent } // TODO: store resume data as an entry instead + void detail::piece_checker_data::parse_resume_data( + const entry& resume_data + , const torrent_info& info) + { + // if we don't have any resume data, return + if (resume_data.type() == entry::undefined_t) return; + + std::vector tmp_pieces; + std::vector tmp_unfinished; + + entry rd = resume_data; + + try + { + if (rd.dict()["file-format"].string() != "libtorrent resume file") + return; + + if (rd.dict()["file-version"].integer() != 1) + return; + + // verify info_hash + const std::string &hash = rd.dict()["info-hash"].string(); + std::string real_hash(info.info_hash().begin(), info.info_hash().end()); + if (hash != real_hash) + return; + + // read piece map + const entry::list_type& slots = rd.dict()["slots"].list(); + if (slots.size() > info.num_pieces()) + return; + + tmp_pieces.reserve(slots.size()); + for (entry::list_type::const_iterator i = slots.begin(); + i != slots.end(); + ++i) + { + int index = i->integer(); + if (index >= info.num_pieces() || index < -2) + return; + tmp_pieces.push_back(index); + } + + + int num_blocks_per_piece = rd.dict()["blocks per piece"].integer(); + if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1) + return; + + const entry::list_type& unfinished = rd.dict()["unfinished"].list(); + + tmp_unfinished.reserve(unfinished.size()); + for (entry::list_type::const_iterator i = unfinished.begin(); + i != unfinished.end(); + ++i) + { + piece_picker::downloading_piece p; + if (i->list().size() < 2) return; + + p.index = i->list()[0].integer(); + if (p.index < 0 || p.index >= info.num_pieces()) + return; + + const std::string& bitmask = i->list()[1].string(); + + const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1); + if (bitmask.size() != num_bitmask_bytes) return; + for (int j = 0; j < num_bitmask_bytes; ++j) + { + unsigned char bits = bitmask[j]; + for (int k = 0; k < 8; ++k) + { + const int bit = j * 8 + k; + if (bits & (1 << k)) + p.finished_blocks[bit] = true; + } + } + tmp_unfinished.push_back(p); + } + + piece_map.swap(tmp_pieces); + unfinished_pieces.swap(tmp_unfinished); + } + catch (invalid_encoding) + { + return; + } + catch (type_error) + { + return; + } + } +/* void detail::piece_checker_data::parse_resume_data( const std::vector* rd , const torrent_info& info) @@ -958,4 +1050,5 @@ namespace libtorrent piece_map.swap(tmp_pieces); unfinished_pieces.swap(tmp_unfinished); } +*/ } diff --git a/src/torrent.cpp b/src/torrent.cpp index d0db58dc0..4e105648f 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -303,8 +303,7 @@ namespace libtorrent { std::stringstream s; s << "hash for piece " << index << " failed"; - torrent_handle self(&m_ses, 0, m_torrent_file.info_hash()); - m_ses.m_alerts.post_alert(hash_failed_alert(self, index, s.str())); + m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index, s.str())); } std::vector downloaders; m_picker.get_downloaders(downloaders, index); @@ -577,6 +576,18 @@ namespace libtorrent #endif } + alert_manager& torrent::alerts() const + { + return m_ses.m_alerts; + } + + torrent_handle torrent::get_handle() const + { + return torrent_handle(&m_ses, 0, m_torrent_file.info_hash()); + } + + + #ifndef NDEBUG void torrent::check_invariant() { @@ -699,8 +710,7 @@ namespace libtorrent s << "tracker: \"" << m_torrent_file.trackers()[m_currently_trying_tracker].url << "\" timed out"; - 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(get_handle(), s.str())); } // TODO: increase the retry_delay for // each failed attempt on the same tracker! @@ -726,8 +736,7 @@ namespace libtorrent s << "tracker: \"" << m_torrent_file.trackers()[m_currently_trying_tracker].url << "\" " << str; - 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(get_handle(), s.str())); } diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index f74090c07..0a21a4966 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -170,43 +170,30 @@ namespace libtorrent return false; } - void torrent_handle::write_resume_data(std::vector& buf) + entry torrent_handle::write_resume_data() { - buf.clear(); std::vector piece_index; - if (m_ses == 0) return; + if (m_ses == 0) + throw invalid_handle(); boost::mutex::scoped_lock l(m_ses->m_mutex); torrent* t = m_ses->find_torrent(m_info_hash); - if (t == 0) return; + if (t == 0) + throw invalid_handle(); t->filesystem().export_piece_map(piece_index); - std::back_insert_iterator > out(buf); + entry ret(entry::dictionary_t); - // TODO: write file header - // TODO: write modification-dates for all files + ret.dict()["file-format"] = "libtorrent resume file"; + ret.dict()["file-version"] = 1; - for (sha1_hash::const_iterator i = m_info_hash.begin(); - i != m_info_hash.end(); - ++i) - { - detail::write_uchar(*i, out); - } + const sha1_hash& info_hash = t->torrent_file().info_hash(); + ret.dict()["info-hash"] = std::string(info_hash.begin(), info_hash.end()); - // number of slots - int num_slots = piece_index.size(); - detail::write_int(num_slots, out); - - // the piece indices for each slot (-1 means no index assigned) - for (std::vector::iterator i = piece_index.begin(); - i != piece_index.end(); - ++i) - { - detail::write_int(*i, out); - assert(*i >= -2); - assert(*i < t->torrent_file().num_pieces()); - } + ret.dict()["slots"] = entry(entry::list_t); + entry::list_type& slots = ret.dict()["slots"].list(); + std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots)); const piece_picker& p = t->picker(); @@ -216,11 +203,12 @@ namespace libtorrent // blocks per piece int num_blocks_per_piece = t->torrent_file().piece_length() / t->block_size(); - detail::write_int(num_blocks_per_piece, out); + ret.dict()["blocks per piece"] = num_blocks_per_piece; // num unfinished pieces int num_unfinished = q.size(); - detail::write_int(num_unfinished, out); + ret.dict()["unfinished"] = entry(entry::list_t); + entry::list_type& up = ret.dict()["unfinished"].list(); // info for each unfinished piece for (std::vector::const_iterator i @@ -228,20 +216,28 @@ namespace libtorrent i != q.end(); ++i) { - // the unsinished piece's index - detail::write_int(i->index, out); + entry piece_struct(entry::list_t); - // TODO: write the bitmask in correct byteorder - // TODO: make sure to read it in the correct order too + // the unfinished piece's index + piece_struct.list().push_back(i->index); + + std::string bitmask; const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1); for (int j = 0; j < num_bitmask_bytes; ++j) { unsigned char v = 0; for (int k = 0; k < 8; ++k) v |= i->finished_blocks[j*8+k]?(1 << k):0; - detail::write_uchar(v, out); + bitmask.push_back(v); } + piece_struct.list().push_back(bitmask); + + // TODO: add a hash to piece_struct + + // push the struct onto the unfinished-piece list + up.push_back(piece_struct); } + return ret; }