From 557b3f3955d0055895f931ea2a44e09cbf49544d Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Tue, 9 Dec 2003 18:09:34 +0000 Subject: [PATCH] *** empty log message *** --- docs/index.html | 163 ++++++++++++++++--------- docs/index.rst | 23 +++- examples/client_test.cpp | 2 +- include/libtorrent/peer_connection.hpp | 30 ++++- include/libtorrent/peer_info.hpp | 8 ++ include/libtorrent/torrent.hpp | 3 + src/peer_connection.cpp | 44 ++++++- src/piece_picker.cpp | 5 + src/torrent_handle.cpp | 17 +++ 9 files changed, 227 insertions(+), 68 deletions(-) diff --git a/docs/index.html b/docs/index.html index bd9e70ff1..9ab1124c9 100755 --- a/docs/index.html +++ b/docs/index.html @@ -17,53 +17,53 @@ sourceforge page -mailing list +mailing list

Contents

-

introduction

+

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 @@ -115,7 +115,7 @@ boost.filesystem boost.date_time and various other boost libraries and zlib.

-

building

+

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 @@ -146,11 +146,11 @@ loop scope" and "treat wchar_t as built-in type" to Yes.

TODO: more detailed build instructions.

-

using

+

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

+

session

The session class has the following synopsis:

 class session: public boost::noncopyable
@@ -196,7 +196,7 @@ increasing the port number until it succeeds or has failed 9 ports. This wil
 change in the future to give more control of the listen-port.

-

parsing torrent files

+

parsing torrent files

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

@@ -233,7 +233,7 @@ entry e = bdecode(buf, buf + data_size);
 

Now we just need to know how to retrieve information from the entry.

-

entry

+

entry

The entry class represents one node in a bencoded hierarchy. It works as a variant type, it can be either a list, a dictionary (std::map), an integer or a string. This is its synopsis:

@@ -303,7 +303,7 @@ if (i != dict.end()) exists.

-

torrent_info

+

torrent_info

The torrent_info has the following synopsis:

 class torrent_info
@@ -385,12 +385,12 @@ be smaller.

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_ +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

+

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:

@@ -404,13 +404,24 @@ struct torrent_handle void get_peer_info(std::vector<peer_info>& v); const torrent_info& get_torrent_info(); bool is_valid(); + + boost::filsystem::path save_path() const; + + 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 they will simply return.

+

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.

-

status()

+

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:

@@ -431,6 +442,8 @@ struct torrent_status boost::posix_time::time_duration next_announce; std::size_t total_download; std::size_t total_upload; + float download_rate; + float upload_rate; std::vector<bool> pieces; std::size_t total_done; }; @@ -470,10 +483,13 @@ is a pure seeder. uploaded to all peers, accumulated, this session only.

pieces is the bitmask that representw which pieces we have (set to true) and the pieces we don't have.

+

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.

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

-

get_download_queue()

+

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:

@@ -505,7 +521,7 @@ When a piece fails a hash verification, single blocks may be redownloaded to see may pass then.

-

get_peer_info()

+

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 @@ -530,6 +546,12 @@ struct peer_info peer_id id; std::vector<bool> pieces; int upload_limit; + int upload_ceiling; + + 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 @@ -552,22 +574,34 @@ is using.

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.

+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.

+

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

+

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

+

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

+

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:

@@ -600,7 +634,7 @@ while it does the DNS lookup, it returns a string that points to the address rep

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

-

http_settings

+

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 @@ -618,6 +652,16 @@ struct http_settings 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.

@@ -628,10 +672,9 @@ 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.

-

TODO: finish document http_settings

-

big_number

+

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:

@@ -652,7 +695,7 @@ public:
 

The iterators gives you access to individual bytes.

-

hasher

+

hasher

This class creates sha1-hashes. Its declaration looks like this:

 class hasher
@@ -676,11 +719,11 @@ call reset() to reinitialize i
 For more info, see src/sha1.c.

-

exceptions

+

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

+

invalid_handle

This exception is thrown when querying information from a torrent_handle that hasn't been initialized or that has become invalid.

@@ -691,7 +734,7 @@ struct invalid_handle: std::exception
 
-

duplicate_torrent

+

duplicate_torrent

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

@@ -702,7 +745,7 @@ struct duplicate_torrent: std::exception
 
-

invalid_encoding

+

invalid_encoding

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

 struct invalid_encoding: std::exception
@@ -712,7 +755,7 @@ struct invalid_encoding: std::exception
 
-

type_error

+

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.

@@ -723,7 +766,7 @@ struct type_error: std::runtime_error
 
-

invalid_torrent_file

+

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.

@@ -735,9 +778,9 @@ struct invalid_torrent_file: std::exception
 
-

example usage

+

example usage

-

dump_torrent

+

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:

@@ -801,7 +844,7 @@ int main(int argc, char* argv[])
 
-

simple client

+

simple client

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

 #include <iostream>
@@ -854,12 +897,12 @@ int main(int argc, char* argv[])
 
-

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

Project is hosted by sourceforge.

sf_logo

diff --git a/docs/index.rst b/docs/index.rst index af02fbde5..4344cc47b 100755 --- a/docs/index.rst +++ b/docs/index.rst @@ -8,7 +8,7 @@ libtorrent =================== =============== .. _sourceforge page: http://www.sourceforge.net/projects/libtorrent -.. _mailing list: http://lists.sourceforge.net/lists/listinfo/libtorrent-discus +.. _mailing list: http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss .. contents:: @@ -398,11 +398,11 @@ piece and ``info_hash()`` returns the 20-bytes sha1-hash for the info-section of 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_`` +it will return an empty string. ``creation_date()`` returns a `boost::posix_time::ptime`__ object, representing the time when this torrent file was created. If there's no timestamp in the torrent file, this will return a date of january 1:st 1970. -.. _boost::posix_time::ptime: http://www.boost.org/libs/date_time/doc/class_ptime.html +__ http://www.boost.org/libs/date_time/doc/class_ptime.html @@ -437,7 +437,7 @@ The default constructor will initialize the handle to an invalid state. Which me perform any operation on it, unless you first assign it a valid handle. If you try to perform any operation they will simply return. -``save_path()`` returns the path that were given to ``add_torrent()`` when this torrent +``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. @@ -570,6 +570,11 @@ fields:: std::vector pieces; int upload_limit; int upload_ceiling; + + 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 @@ -605,6 +610,16 @@ should sum up to the upload limit set by ``session::set_upload_limit``. 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``. +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() ~~~~~~~~~~~~~~~~~~ diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 0dd539123..f23d33fe5 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -163,7 +163,7 @@ int main(int argc, char* argv[]) using namespace libtorrent; // TEMPORARY - boost::filesystem::path::default_name_check(boost::filesystem::no_check); +// boost::filesystem::path::default_name_check(boost::filesystem::no_check); if (argc < 2) { diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index d36e9a266..b7aa43870 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" @@ -55,6 +56,11 @@ POSSIBILITY OF SUCH DAMAGE. // a chance to request another block instead. // Where it also could become not-interested. +// TODO: maybe there should be some kind of +// per-torrent free-upload counter. All free +// download we get is put in there and increases +// the amount of free upload we give. + namespace libtorrent { class torrent; @@ -78,6 +84,21 @@ namespace libtorrent { return piece == r.piece && start == r.start && length == r.length; } }; + struct piece_block_progress + { + // the piece and block index + // determines exactly which + // part of the torrent that + // is currently being downloaded + int piece_index; + int block_index; + // the number of bytes we have received + // of this block + int bytes_downloaded; + // the number of bytes in the block + int full_block_bytes; + }; + class peer_connection: public boost::noncopyable { public: @@ -139,6 +160,13 @@ namespace libtorrent void request_block(piece_block block); void cancel_block(piece_block block); + // returns the block currently being + // downloaded. And the progress of that + // block. If the peer isn't downloading + // a piece for the moment, the boost::optional + // will be invalid. + boost::optional downloading_piece() const; + bool is_interesting() const throw() { return m_interesting; } bool is_choked() const throw() { return m_choked; } @@ -188,7 +216,7 @@ namespace libtorrent void received_invalid_data() { m_trust_points--; - if (m_trust_points < 5) m_trust_points = 5; + if (m_trust_points < -5) m_trust_points = -5; } int trust_points() const diff --git a/include/libtorrent/peer_info.hpp b/include/libtorrent/peer_info.hpp index 8d1ff1ad8..3d01259d1 100755 --- a/include/libtorrent/peer_info.hpp +++ b/include/libtorrent/peer_info.hpp @@ -58,6 +58,14 @@ namespace libtorrent std::vector pieces; int upload_limit; int upload_ceiling; + + // the currently downloading piece + // if piece index is -1 all associated + // members are just set to 0 + int downloading_piece_index; + int downloading_block_index; + int downloading_progress; + int downloading_total; }; } diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 6bf07f834..e059844ab 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -235,6 +235,9 @@ namespace libtorrent m_priority = p; } + bool is_seed() const + { return m_num_pieces == m_torrent_file.num_pieces(); } + boost::filesystem::path save_path() const { return m_storage.save_path(); } diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 75c064199..1b7206e26 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -231,6 +231,38 @@ void libtorrent::peer_connection::send_handshake() send_buffer_updated(); } +boost::optional libtorrent::peer_connection::downloading_piece() const +{ + // are we currently receiving a 'piece' message? + if (m_state != read_packet + || m_recv_pos < 9 + || m_recv_buffer[0] != msg_piece) + return boost::optional(); + + int piece_index = read_int(&m_recv_buffer[1]); + int offset = read_int(&m_recv_buffer[5]); + int len = m_packet_size - 9; + + // is any of the piece message header data invalid? + // TODO: make sure that len is == block_size or less only + // if its's the last block. + if (piece_index < 0 + || piece_index >= m_torrent->torrent_file().num_pieces() + || offset < 0 + || offset + len > m_torrent->torrent_file().piece_size(piece_index) + || offset % m_torrent->block_size() != 0) + return boost::optional(); + + piece_block_progress p; + + p.piece_index = piece_index; + p.block_index = offset / m_torrent->block_size(); + p.bytes_downloaded = m_recv_pos - 9; + p.full_block_bytes = len; + + return boost::optional(p); +} + bool libtorrent::peer_connection::dispatch_message(int received) { assert(m_recv_pos >= received); @@ -470,6 +502,8 @@ bool libtorrent::peer_connection::dispatch_message(int received) #endif throw protocol_error("piece message contains more data than the piece size"); } + // TODO: make sure that len is == block_size or less only + // if its's the last block. if (offset % m_torrent->block_size() != 0) { @@ -790,9 +824,15 @@ void libtorrent::peer_connection::second_tick() // upload rate of 10 kB/s more than we dowlload // if we have uploaded too much, send with a rate of // 10 kB/s less than we receive - int bias = (diff > -32*1024 ? 10 : -10) * 1024; + if (diff > -32*1024) + { + m_send_quota_limit = m_statistics.download_rate() * 1.5; + } + else + { + m_send_quota_limit = m_statistics.download_rate() * .5; + } // the maximum send_quota given our download rate from this peer - m_send_quota_limit = m_statistics.download_rate() + bias; if (m_send_quota_limit < 500) m_send_quota_limit = 500; } assert(m_send_quota_limit >= 500 || m_send_quota_limit == -1); diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index aa7a8fbaa..aa98a1bbb 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -316,6 +316,11 @@ namespace libtorrent // to insert the element at a random // index when moving it to another // vector. + // one solution might be to create a + // vector of all piece indices that + // are to have their ref_count increased + // and then random_shuffle that vector + // before processing them. bool piece_picker::inc_refcount(int i) { assert(i >= 0); diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 4559d689f..19a82e0b2 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include "libtorrent/peer_id.hpp" #include "libtorrent/torrent_info.hpp" @@ -211,6 +212,22 @@ namespace libtorrent p.upload_limit = peer->send_quota(); p.upload_ceiling = peer->send_quota_limit(); + boost::optional ret = peer->downloading_piece(); + if (ret) + { + p.downloading_piece_index = ret->piece_index; + p.downloading_block_index = ret->block_index; + p.downloading_progress = ret->bytes_downloaded; + p.downloading_total = ret->full_block_bytes; + } + else + { + p.downloading_piece_index = -1; + p.downloading_block_index = -1; + p.downloading_progress = 0; + p.downloading_total = 0; + } + p.flags = 0; if (peer->is_interesting()) p.flags |= peer_info::interesting; if (peer->is_choked()) p.flags |= peer_info::choked;