diff --git a/docs/manual.html b/docs/manual.html index e69a8e881..4a680b465 100755 --- a/docs/manual.html +++ b/docs/manual.html @@ -193,7 +193,7 @@ Boost.Filesystem, Boost.Date_time and various other boost libraries as well as z @@ -887,6 +887,10 @@ struct torrent_handle bool is_paused() const; bool is_seed() const; + void filter_piece(int index, bool filter); + bool is_piece_filtered(int index) const; + std::vector<bool> filtered_pieces() const; + int num_complete() const; int num_incomplete() const; @@ -905,8 +909,9 @@ struct torrent_handle

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.

-

TODO: document trackers() and replace_trackers() -TODO: document how to create a .torrent

+

TODO: document trackers() and replace_trackers()

+

TODO: document how to create a .torrent

+

TODO: document filter_piece(), is_piece_filtered() and filtered_pieces()

save_path()

@@ -1340,6 +1345,8 @@ struct peer_info address ip; float up_speed; float down_speed; + float payload_up_speed; + float payload_down_speed; size_type total_download; size_type total_upload; peer_id id; @@ -1393,8 +1400,10 @@ us.

The ip field is the IP-address to this peer. Its type is a wrapper around the actual address and the port number. See address class.

-

up_speed and down_speed is the current upload and download speed -we have to and from this peer. These figures are updated aproximately once every second.

+

up_speed and down_speed contains the current upload and download speed +we have to and from this peer (including any protocol messages). The transfer rates +of payload data only are found in payload_up_speed and payload_down_speed. +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.

diff --git a/docs/manual.rst b/docs/manual.rst index fd0dc6fe6..153c5bf7b 100755 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -70,7 +70,7 @@ libtorrent has been successfully compiled and tested on: * Windows 2000 vc7.1 * Linux x86 GCC 3.0.4, GCC 3.2.3, GCC 3.4.2 - * MacOS X, GCC 3.3 + * MacOS X, (Apple's) GCC 3.3, (Apple's) GCC 4.0 * SunOS 5.8 GCC 3.1 * Cygwin GCC 3.3.3 @@ -816,6 +816,10 @@ Its declaration looks like this:: bool is_paused() const; bool is_seed() const; + void filter_piece(int index, bool filter); + bool is_piece_filtered(int index) const; + std::vector filtered_pieces() const; + int num_complete() const; int num_incomplete() const; @@ -836,8 +840,11 @@ perform any operation on it, unless you first assign it a valid handle. If you t any operation on an uninitialized handle, it will throw ``invalid_handle``. **TODO: document trackers() and replace_trackers()** + **TODO: document how to create a .torrent** +**TODO: document filter_piece(), is_piece_filtered() and filtered_pieces()** + save_path() ----------- @@ -1301,6 +1308,8 @@ It contains the following fields:: address ip; float up_speed; float down_speed; + float payload_up_speed; + float payload_down_speed; size_type total_download; size_type total_upload; peer_id id; @@ -1346,8 +1355,10 @@ __ 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. +``up_speed`` and ``down_speed`` contains the current upload and download speed +we have to and from this peer (including any protocol messages). The transfer rates +of payload data only are found in ``payload_up_speed`` and ``payload_down_speed``. +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 diff --git a/examples/client_test.cpp b/examples/client_test.cpp index d8e5dd44c..271ac4b0e 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -147,10 +147,10 @@ void clear() #endif -std::string to_string(float v, int width) +std::string to_string(float v, int width, int precision = 4) { std::stringstream s; - s.precision(width-2); + s.precision(precision); s.flags(std::ios_base::right); s.width(width); s.fill(' '); @@ -158,10 +158,10 @@ std::string to_string(float v, int width) return s.str(); } -std::string pos_to_string(float v, int width) +std::string pos_to_string(float v, int width, int precision = 4) { std::stringstream s; - s.precision(width-1); + s.precision(precision); s.flags(std::ios_base::right); s.width(width); s.fill(' '); @@ -194,12 +194,11 @@ std::string add_suffix(float val) { const char* prefix[] = {"B", "kB", "MB", "GB", "TB"}; const int num_prefix = sizeof(prefix) / sizeof(const char*); - int i; - for (i = 0; i < num_prefix; ++i) + for (int i = 0; i < num_prefix; ++i) { if (fabs(val) < 1000.f) return to_string(val, i==0?7:6) + prefix[i]; - val /= 1024.f; + val /= 1000.f; } return to_string(val, 6) + "PB"; } @@ -221,8 +220,7 @@ void print_peer_info(std::ostream& out, std::vector const out << " down up q r flags client block\n"; for (std::vector::const_iterator i = peers.begin(); - i != peers.end(); - ++i) + i != peers.end(); ++i) { out.fill(' '); out.width(2); @@ -233,8 +231,8 @@ void print_peer_info(std::ostream& out, std::vector const // << "ul:" << add_suffix(i->upload_limit) << "/s " // << "uc:" << add_suffix(i->upload_ceiling) << "/s " // << "df:" << ratio(i->total_download, i->total_upload) << " " - << to_string(i->download_queue_length, 2) << " " - << to_string(i->upload_queue_length, 2) << " " + << to_string(i->download_queue_length, 2, 2) << " " + << to_string(i->upload_queue_length, 2, 2) << " " << static_cast((i->flags & peer_info::interesting)?"I":"_") << static_cast((i->flags & peer_info::choked)?"C":"_") << static_cast((i->flags & peer_info::remote_interested)?"i":"_") @@ -354,8 +352,7 @@ int main(int argc, char* argv[]) if (c == 'q') { for (std::vector::iterator i = handles.begin(); - i != handles.end(); - ++i) + i != handles.end(); ++i) { torrent_handle h = *i; if (!h.get_torrent_info().is_valid()) continue; @@ -441,8 +438,7 @@ int main(int argc, char* argv[]) std::stringstream out; for (std::vector::iterator i = handles.begin(); - i != handles.end(); - ++i) + i != handles.end(); ++i) { if (!i->is_valid()) { @@ -515,14 +511,14 @@ int main(int argc, char* argv[]) { out.width(4); out.fill(' '); - out << i->piece_index << ": |"; + out << i->piece_index << ": ["; for (int j = 0; j < i->blocks_in_piece; ++j) { if (i->finished_blocks[j]) out << "#"; else if (i->requested_blocks[j]) out << "+"; - else out << "."; + else out << "-"; } - out << "|\n"; + out << "]\n"; } out << "___________________________________\n"; diff --git a/include/libtorrent/bencode.hpp b/include/libtorrent/bencode.hpp index a4cf74afb..00cae30bb 100755 --- a/include/libtorrent/bencode.hpp +++ b/include/libtorrent/bencode.hpp @@ -101,12 +101,8 @@ namespace libtorrent template void write_string(OutIt& out, const std::string& val) { - std::string::const_iterator end = val.begin()+val.length(); - for (std::string::const_iterator i = val.begin(); i != end; ++i) - { - *out = *i; - ++out; - } + std::string::const_iterator end = val.begin() + val.length(); + std::copy(val.begin(), end, out); } template @@ -115,6 +111,13 @@ namespace libtorrent write_string(out, boost::lexical_cast(val)); } + template + void write_char(OutIt& out, char c) + { + *out = c; + ++out; + } + template std::string read_until(InIt& in, InIt end, char end_token) { @@ -130,7 +133,7 @@ namespace libtorrent } template - std::string read_string(InIt& in, InIt end, int len) + std::string read_string(InIt& in, InIt end, int len) { assert(len >= 0); std::string ret; @@ -149,35 +152,34 @@ namespace libtorrent switch(e.type()) { case entry::int_t: - *out = 'i'; ++out; + write_char(out, 'i'); write_integer(out, e.integer()); - *out = 'e'; ++out; + write_char(out, 'e'); break; case entry::string_t: write_integer(out, e.string().length()); - *out = ':'; ++out; + write_char(out, ':'); write_string(out, e.string()); break; case entry::list_t: - *out = 'l'; ++out; + write_char(out, 'l'); for (entry::list_type::const_iterator i = e.list().begin(); i != e.list().end(); ++i) bencode_recursive(out, *i); - *out = 'e'; ++out; + write_char(out, 'e'); break; case entry::dictionary_t: - *out = 'd'; ++out; + write_char(out, 'd'); for (entry::dictionary_type::const_iterator i = e.dict().begin(); - i != e.dict().end(); - ++i) + i != e.dict().end(); ++i) { // write key write_integer(out, i->first.length()); - *out = ':'; ++out; + write_char(out, ':'); write_string(out, i->first); // write value bencode_recursive(out, i->second); } - *out = 'e'; ++out; + write_char(out, 'e'); break; default: throw invalid_encoding(); diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index 437ca0650..5b49f754d 100755 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -57,7 +57,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/storage.hpp" -#include "libtorrent/piece_picker.hpp" #include "libtorrent/stat.hpp" #include "libtorrent/debug.hpp" #include "libtorrent/alert.hpp" diff --git a/include/libtorrent/peer_info.hpp b/include/libtorrent/peer_info.hpp index cb2496509..c10638020 100755 --- a/include/libtorrent/peer_info.hpp +++ b/include/libtorrent/peer_info.hpp @@ -56,6 +56,8 @@ namespace libtorrent address ip; float up_speed; float down_speed; + float payload_up_speed; + float payload_down_speed; size_type total_download; size_type total_upload; peer_id id; diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index f6950aeed..47784cc36 100755 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -134,6 +134,23 @@ namespace libtorrent // (i.e. we don't have to maintain a refcount) void we_have(int index); + // This will mark a piece as unfiltered, and if it was + // previously marked as filtered, it will be considered + // interesting again and be placed in the piece list available + // for downloading. + void mark_as_unfiltered(int index); + + // This will mark a piece as filtered. The piece will be + // removed from the list of pieces avalable for downloading + // and hence, will not be downloaded. + void mark_as_filtered(int index); + + // returns true if the pieces at 'index' is marked as filtered + bool is_filtered(int index) const; + + // fills the bitmask with 1's for pieces that are filtered + void filtered_pieces(std::vector& mask) const; + // pieces should be the vector that represents the pieces a // client has. It returns a list of all pieces that this client // has and that are interesting to download. It returns them in @@ -209,6 +226,7 @@ namespace libtorrent piece_pos(int peer_count_, int index_) : peer_count(peer_count_) , downloading(0) + , filtered(0) , index(index_) { assert(peer_count_ >= 0); @@ -219,9 +237,13 @@ namespace libtorrent unsigned peer_count : 11; // is 1 if the piece is marked as being downloaded unsigned downloading : 1; + // is 1 if the piece is filtered (not to be downloaded) + unsigned filtered : 1; // index in to the piece_info vector - unsigned index : 20; + unsigned index : 19; + enum { we_have_index = 0x3ffff }; + bool operator!=(piece_pos p) { return index != p.index || peer_count != p.peer_count; } @@ -231,8 +253,13 @@ namespace libtorrent }; - void move(bool downloading, int vec_index, int elem_index); - void remove(bool downloading, int vec_index, int elem_index); + void move(bool downloading, bool filtered, int vec_index, int elem_index); + void remove(bool downloading, bool filtered, int vec_index, int elem_index); + std::vector >& pick_piece_info_vector(bool downloading + , bool filtered); + + std::vector > const& pick_piece_info_vector( + bool downloading, bool filtered) const; int add_interesting_blocks(const std::vector& piece_list, const std::vector& pieces, @@ -252,10 +279,14 @@ namespace libtorrent // during piece picking std::vector > m_downloading_piece_info; + // this vector has the same structure as m_piece_info + // but only contains pieces we aren't interested in (filtered) + std::vector > m_filtered_piece_info; + // this maps indices to number of peers that has this piece and // index into the m_piece_info vectors. - // 0xfffff means that we have the piece, so it doesn't - // exist in the piece_info buckets + // piece_pos::we_have_index means that we have the piece, so it + // doesn't exist in the piece_info buckets std::vector m_piece_map; // each piece that's currently being downloaded diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index f106c3914..dbc2a8bcf 100755 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -141,6 +141,10 @@ namespace libtorrent void resume(); bool is_paused() const { return m_paused; } + void filter_piece(int index, bool download); + bool is_piece_filtered(int index) const; + void filtered_pieces(std::vector& bitmask) const; + torrent_status status() const; void use_interface(const char* net_interface); diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp index 4d4efd43b..2d1278fce 100755 --- a/include/libtorrent/torrent_handle.hpp +++ b/include/libtorrent/torrent_handle.hpp @@ -208,6 +208,13 @@ namespace libtorrent void pause(); void resume(); + + // marks the piece with the given index as filtered + // it will not be downloaded + void filter_piece(int index, bool filter); + bool is_piece_filtered(int index) const; + std::vector filtered_pieces() const; + // set the interface to bind outgoing connections // to. void use_interface(const char* net_interface); diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index eed446bb9..972aff873 100755 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -273,7 +273,8 @@ namespace libtorrent { int index = *i; m_torrent->peer_has(index); - if (!m_torrent->have_piece(index)) + if (!m_torrent->have_piece(index) + && m_torrent->picker().is_filtered(index)) interesting = true; } @@ -654,7 +655,9 @@ namespace libtorrent ++m_num_pieces; m_torrent->peer_has(index); - if (!m_torrent->have_piece(index) && !is_interesting()) + if (!m_torrent->have_piece(index) + && !is_interesting() + && !m_torrent->picker().is_filtered(index)) m_torrent->get_policy().peer_is_interesting(*this); } @@ -729,12 +732,12 @@ namespace libtorrent // peer has, in a shuffled order bool interesting = false; for (std::vector::iterator i = piece_list.begin(); - i != piece_list.end(); - ++i) + i != piece_list.end(); ++i) { int index = *i; m_torrent->peer_has(index); - if (!m_torrent->have_piece(index)) + if (!m_torrent->have_piece(index) + && !m_torrent->picker().is_filtered(index)) interesting = true; } @@ -1571,7 +1574,14 @@ namespace libtorrent #ifdef TORRENT_VERBOSE_LOGGING using namespace boost::posix_time; (*m_logger) << to_simple_string(second_clock::universal_time()) - << " ==> BITFIELD\n"; + << " ==> BITFIELD "; + + for (int i = 0; i < (int)m_have_piece.size(); ++i) + { + if (m_torrent->have_piece(i)) (*m_logger) << "1"; + else (*m_logger) << "0"; + } + (*m_logger) << "\n"; #endif const int packet_size = ((int)m_have_piece.size() + 7) / 8 + 5; const int old_size = (int)m_send_buffer.size(); diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index 07c171f5f..07e0873ce 100755 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -57,6 +57,7 @@ namespace libtorrent piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks) : m_piece_info(2) , m_downloading_piece_info(2) + , m_filtered_piece_info(2) , m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece) { assert(blocks_per_piece > 0); @@ -64,7 +65,7 @@ namespace libtorrent // the piece index is stored in 20 bits, which limits the allowed // number of pieces somewhat - if (m_piece_map.size() >= 0xfffff) throw std::runtime_error("too many pieces in torrent"); + if (m_piece_map.size() >= piece_pos::we_have_index) throw std::runtime_error("too many pieces in torrent"); m_blocks_per_piece = blocks_per_piece; m_blocks_in_last_piece = total_num_blocks % blocks_per_piece; @@ -76,7 +77,7 @@ namespace libtorrent // allocate the piece_map to cover all pieces // and make them invalid (as if though we already had every piece) - std::fill(m_piece_map.begin(), m_piece_map.end(), piece_pos(0, 0xfffff)); + std::fill(m_piece_map.begin(), m_piece_map.end(), piece_pos(0, piece_pos::we_have_index)); } void piece_picker::files_checked( @@ -107,14 +108,18 @@ namespace libtorrent int index = *i; assert(index >= 0); assert(index < (int)m_piece_map.size()); - assert(m_piece_map[index].index == 0xfffff); + assert(m_piece_map[index].index == piece_pos::we_have_index); int peer_count = m_piece_map[index].peer_count; assert(peer_count == 0); assert(m_piece_info.size() == 2); - m_piece_map[index].index = (int)m_piece_info[peer_count].size(); - m_piece_info[peer_count].push_back(index); + piece_pos& p = m_piece_map[index]; + std::vector >& dst_vec = pick_piece_info_vector(p.downloading + , p.filtered); + assert((int)dst_vec.size() > peer_count); + p.index = (int)dst_vec[peer_count].size(); + dst_vec[peer_count].push_back(index); } // if we have fast resume info @@ -184,14 +189,14 @@ namespace libtorrent */ } - if (i->index == 0xfffff) + if (i->index == piece_pos::we_have_index) { assert(t == 0 || t->have_piece(index)); assert(i->downloading == 0); // make sure there's no entry // with this index. (there shouldn't - // be since the piece_map is 0xfffff) + // be since the piece_map is piece_pos::we_have_index) for (std::vector >::const_iterator i = m_piece_info.begin(); i != m_piece_info.end(); ++i) { @@ -203,8 +208,7 @@ namespace libtorrent } for (std::vector >::const_iterator i = m_downloading_piece_info.begin(); - i != m_downloading_piece_info.end(); - ++i) + i != m_downloading_piece_info.end(); ++i) { for (std::vector::const_iterator j = i->begin(); j != i->end(); ++j) @@ -219,7 +223,7 @@ namespace libtorrent if (t != 0) assert(!t->have_piece(index)); - const std::vector >& c_vec = (i->downloading)?m_downloading_piece_info:m_piece_info; + const std::vector >& c_vec = pick_piece_info_vector(i->downloading, i->filtered); assert(i->peer_count < c_vec.size()); const std::vector& vec = c_vec[i->peer_count]; assert(i->index < vec.size()); @@ -261,11 +265,30 @@ namespace libtorrent return 1.f; } - void piece_picker::move(bool downloading, int peer_count, int elem_index) + std::vector >& piece_picker::pick_piece_info_vector( + bool downloading, bool filtered) + { + return filtered + ?m_filtered_piece_info + :(downloading?m_downloading_piece_info:m_piece_info); + } + + std::vector > const& piece_picker::pick_piece_info_vector( + bool downloading, bool filtered) const + { + return filtered + ?m_filtered_piece_info + :(downloading?m_downloading_piece_info:m_piece_info); + } + + + // will update the piece with the given properties (downloading, filtered, peer_count, elem_index) + // to place it at the correct position in the vectors. + void piece_picker::move(bool downloading, bool filtered, int peer_count, int elem_index) { assert(peer_count >= 0); assert(elem_index >= 0); - std::vector >& src_vec = (downloading)?m_downloading_piece_info:m_piece_info; + std::vector >& src_vec(pick_piece_info_vector(downloading, filtered)); assert((int)src_vec.size() > peer_count); assert((int)src_vec[peer_count].size() > elem_index); @@ -276,7 +299,7 @@ namespace libtorrent assert(p.downloading != downloading || (int)p.peer_count != peer_count); - std::vector >& dst_vec = (p.downloading)?m_downloading_piece_info:m_piece_info; + std::vector >& dst_vec(pick_piece_info_vector(p.downloading, p.filtered)); if (dst_vec.size() <= p.peer_count) { @@ -308,21 +331,20 @@ namespace libtorrent } src_vec[peer_count].pop_back(); - } - void piece_picker::remove(bool downloading, int peer_count, int elem_index) + void piece_picker::remove(bool downloading, bool filtered, int peer_count, int elem_index) { assert(peer_count >= 0); assert(elem_index >= 0); - std::vector >& src_vec = (downloading)?m_downloading_piece_info:m_piece_info; + std::vector >& src_vec(pick_piece_info_vector(downloading, filtered)); assert((int)src_vec.size() > peer_count); assert((int)src_vec[peer_count].size() > elem_index); int index = src_vec[peer_count][elem_index]; - m_piece_map[index].index = 0xfffff; + m_piece_map[index].index = piece_pos::we_have_index; if (downloading) { @@ -360,7 +382,8 @@ namespace libtorrent m_downloads.erase(i); m_piece_map[index].downloading = 0; - move(true, m_piece_map[index].peer_count, m_piece_map[index].index); + piece_pos& p = m_piece_map[index]; + move(true, p.filtered, p.peer_count, p.index); #ifndef NDEBUG // integrity_check(); @@ -381,9 +404,10 @@ namespace libtorrent // if we have the piece, we don't have to move // any entries in the piece_info vector - if (index == 0xfffff) return; + if (index == piece_pos::we_have_index) return; - move(m_piece_map[i].downloading, peer_count, index); + piece_pos& p = m_piece_map[i]; + move(p.downloading, p.filtered, peer_count, index); #ifndef NDEBUG // integrity_check(); @@ -407,10 +431,15 @@ namespace libtorrent if (m_piece_map[i].peer_count > 0) m_piece_map[i].peer_count--; - if (index == 0xfffff) return; - move(m_piece_map[i].downloading, peer_count, index); + if (index == piece_pos::we_have_index) return; + piece_pos& p = m_piece_map[i]; + move(p.downloading, p.filtered, peer_count, index); } + // this is used to indicate that we succesfully have + // downloaded a piece, and that no further attempts + // to pick that piece should be made. The piece will + // be removed from the available piece list. void piece_picker::we_have(int index) { assert(index >= 0); @@ -421,16 +450,74 @@ namespace libtorrent assert(m_piece_map[index].downloading == 1); - assert(info_index != 0xfffff); - remove(m_piece_map[index].downloading, peer_count, info_index); + assert(info_index != piece_pos::we_have_index); + piece_pos& p = m_piece_map[index]; + remove(p.downloading, p.filtered, peer_count, info_index); #ifndef NDEBUG // integrity_check(); #endif } - void piece_picker::pick_pieces(const std::vector& pieces, - std::vector& interesting_pieces, - int num_blocks) const + + void piece_picker::mark_as_filtered(int index) + { + assert(index >= 0); + assert(index < (int)m_piece_map.size()); + + piece_pos& p = m_piece_map[index]; + if (p.filtered == 1) return; + p.filtered = 1; + if (p.index != piece_pos::we_have_index) + move(p.downloading, false, p.peer_count, p.index); + +#ifndef NDEBUG + integrity_check(); +#endif + } + + // this function can be used for pieces that we don't + // have, but have marked as filtered (so we didn't + // want to download them) but later want to enable for + // downloading, then we call this function and it will + // be inserted in the available piece list again + void piece_picker::mark_as_unfiltered(int index) + { + assert(index >= 0); + assert(index < (int)m_piece_map.size()); + + piece_pos& p = m_piece_map[index]; + if (p.filtered == 0) return; + p.filtered = 0; + if (p.index != piece_pos::we_have_index) + move(p.downloading, true, p.peer_count, p.index); + +#ifndef NDEBUG + integrity_check(); +#endif + } + + bool piece_picker::is_filtered(int index) const + { + assert(index >= 0); + assert(index < (int)m_piece_map.size()); + + return m_piece_map[index].filtered == 1; + } + + void piece_picker::filtered_pieces(std::vector& mask) const + { + mask.resize(m_piece_map.size()); + std::vector::iterator j = mask.begin(); + for (std::vector::const_iterator i = m_piece_map.begin(), + end(m_piece_map.end()); i != end; ++i, ++j) + { + *j = i->filtered == 1; + } + } + + void piece_picker::pick_pieces(const std::vector& pieces + , std::vector& interesting_pieces + , int num_blocks) const { assert(num_blocks > 0); assert(pieces.size() == m_piece_map.size()); @@ -445,8 +532,10 @@ namespace libtorrent // parts of them may be free for download as well, the // partially donloaded pieces will be prioritized assert(m_piece_info.begin() != m_piece_info.end()); + // +1 is to ignore pieces that no peer has. The bucket with index 0 contains + // pieces that 0 other peers has. std::vector >::const_iterator free = m_piece_info.begin()+1; - assert(m_downloading_piece_info.begin()!=m_downloading_piece_info.end()); + assert(m_downloading_piece_info.begin() != m_downloading_piece_info.end()); std::vector >::const_iterator partial = m_downloading_piece_info.begin()+1; while((free != m_piece_info.end()) || (partial != m_downloading_piece_info.end())) @@ -472,10 +561,10 @@ namespace libtorrent } } - int piece_picker::add_interesting_blocks(const std::vector& piece_list, - const std::vector& pieces, - std::vector& interesting_blocks, - int num_blocks) const + int piece_picker::add_interesting_blocks(const std::vector& piece_list + , const std::vector& pieces + , std::vector& interesting_blocks + , int num_blocks) const { assert(num_blocks > 0); @@ -571,7 +660,7 @@ namespace libtorrent assert(block.piece_index < (int)m_piece_map.size()); assert(block.block_index < (int)max_blocks_per_piece); - if (m_piece_map[block.piece_index].index == 0xfffff) return true; + if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true; if (m_piece_map[block.piece_index].downloading == 0) return false; std::vector::const_iterator i = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); @@ -594,7 +683,7 @@ namespace libtorrent if (p.downloading == 0) { p.downloading = 1; - move(false, p.peer_count, p.index); + move(false, p.filtered, p.peer_count, p.index); downloading_piece dp; dp.index = block.piece_index; @@ -627,10 +716,12 @@ namespace libtorrent assert(block.block_index < blocks_in_piece(block.piece_index)); piece_pos& p = m_piece_map[block.piece_index]; + if (p.index == piece_pos::we_have_index) return; + if (p.downloading == 0) { p.downloading = 1; - move(false, p.peer_count, p.index); + move(false, p.filtered, p.peer_count, p.index); downloading_piece dp; dp.index = block.piece_index; @@ -750,7 +841,8 @@ namespace libtorrent { m_downloads.erase(i); m_piece_map[block.piece_index].downloading = 0; - move(true, m_piece_map[block.piece_index].peer_count, m_piece_map[block.piece_index].index); + piece_pos& p = m_piece_map[block.piece_index]; + move(true, p.filtered, p.peer_count, p.index); } #ifndef NDEBUG // integrity_check(); diff --git a/src/policy.cpp b/src/policy.cpp index 2c1d72518..6b19bcd83 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -124,8 +124,7 @@ namespace busy_pieces.reserve(10); for (std::vector::iterator i = interesting_pieces.begin(); - i != interesting_pieces.end(); - ++i) + i != interesting_pieces.end(); ++i) { if (p.is_downloading(*i)) { diff --git a/src/session.cpp b/src/session.cpp index 751e498b2..92eb52a49 100755 --- a/src/session.cpp +++ b/src/session.cpp @@ -136,26 +136,28 @@ namespace libtorrent { namespace detail // lock the session to add the new torrent boost::mutex::scoped_lock l(m_mutex); - if (!t->abort) + if (t->abort) { - boost::mutex::scoped_lock l(m_ses.m_mutex); - m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr)); m_torrents.pop_front(); - if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info)) - { - m_ses.m_alerts.post_alert(torrent_finished_alert( - t->torrent_ptr->get_handle() - , "torrent is complete")); - } - - peer_id id; - std::fill(id.begin(), id.end(), 0); - for (std::vector
::const_iterator i = t->peers.begin(); - i != t->peers.end(); ++i) - { - t->torrent_ptr->get_policy().peer_from_tracker(*i, id); - } + continue; } + boost::mutex::scoped_lock l2(m_ses.m_mutex); + m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr)); + if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert(torrent_finished_alert( + t->torrent_ptr->get_handle() + , "torrent is complete")); + } + + peer_id id; + std::fill(id.begin(), id.end(), 0); + for (std::vector
::const_iterator i = t->peers.begin(); + i != t->peers.end(); ++i) + { + t->torrent_ptr->get_policy().peer_from_tracker(*i, id); + } + m_torrents.pop_front(); } catch(const std::exception& e) { diff --git a/src/storage.cpp b/src/storage.cpp index 24d4d5206..9231f7688 100755 --- a/src/storage.cpp +++ b/src/storage.cpp @@ -1119,13 +1119,11 @@ namespace libtorrent std::vector piece_data(static_cast(m_info.piece_length())); + // this maps a piece hash to piece index. It will be + // build the first time it is used (to save time if it + // isn't needed) std::multimap hash_to_piece; // build the hash-map, that maps hashes to pieces - for (int i = 0; i < m_info.num_pieces(); ++i) - { - hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i)); - } - for (int current_slot = 0; current_slot < m_info.num_pieces(); ++current_slot) { try @@ -1137,6 +1135,14 @@ namespace libtorrent , 0 , static_cast(m_info.piece_size(current_slot))); + if (hash_to_piece.empty()) + { + for (int i = 0; i < m_info.num_pieces(); ++i) + { + hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i)); + } + } + int piece_index = identify_data( piece_data , current_slot diff --git a/src/torrent.cpp b/src/torrent.cpp index 53548f765..1f01f9ba2 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -555,6 +555,34 @@ namespace libtorrent return m_username + ":" + m_password; } + void torrent::filter_piece(int index, bool filter) + { + // this call is only valid on torrents with metadata + assert(m_picker.get()); + assert(index >= 0); + assert(index < m_torrent_file.num_pieces()); + + if (filter) m_picker->mark_as_filtered(index); + else m_picker->mark_as_unfiltered(index); + } + + bool torrent::is_piece_filtered(int index) const + { + // this call is only valid on torrents with metadata + assert(m_picker.get()); + assert(index >= 0); + assert(index < m_torrent_file.num_pieces()); + + return m_picker->is_filtered(index); + } + + void torrent::filtered_pieces(std::vector& bitmask) const + { + // this call is only valid on torrents with metadata + assert(m_picker.get()); + m_picker->filtered_pieces(bitmask); + } + void torrent::replace_trackers(std::vector const& urls) { assert(!urls.empty()); diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp index 9a0dfe1de..c8cafde1d 100755 --- a/src/torrent_handle.cpp +++ b/src/torrent_handle.cpp @@ -76,64 +76,11 @@ namespace libtorrent { namespace { -#if defined(_MSC_VER) && _MSC_VER < 1300 - - template - struct transform_void{ typedef T type; }; - - template<> - struct transform_void { typedef int type; }; - - template - struct void_call_wrapper + void throw_invalid_handle() { - template - static Ret call(F f, torrent& t) - { - return f(t); - } - }; - - template<> - struct void_call_wrapper - { - template - static int call(F f, torrent& t) - { - f(t); - return 0; - } - }; - - template - transform_void::type call_member( - detail::session_impl* ses - , detail::checker_impl* chk - , sha1_hash const& hash - , F f) - { - typedef typename transform_void::type ret; - if (ses == 0) throw invalid_handle(); - - { - boost::mutex::scoped_lock l(ses->m_mutex); - torrent* t = ses->find_torrent(hash); - if (t != 0) return void_call_wrapper::call(f, *t); - } - - - if (chk) - { - boost::mutex::scoped_lock l(chk->m_mutex); - - detail::piece_checker_data* d = chk->find_torrent(hash); - if (d != 0) return void_call_wrapper::call(f, *d->torrent_ptr); - } - throw invalid_handle(); + throw_invalid_handle(); } - -#else - + template Ret call_member( detail::session_impl* ses @@ -141,14 +88,7 @@ namespace libtorrent , sha1_hash const& hash , F f) { - if (ses == 0) throw invalid_handle(); - - { - boost::mutex::scoped_lock l(ses->m_mutex); - torrent* t = ses->find_torrent(hash); - if (t != 0) return f(*t); - } - + if (ses == 0) throw_invalid_handle(); if (chk) { @@ -157,10 +97,15 @@ namespace libtorrent detail::piece_checker_data* d = chk->find_torrent(hash); if (d != 0) return f(*d->torrent_ptr); } - throw invalid_handle(); + + { + boost::mutex::scoped_lock l(ses->m_mutex); + torrent* t = ses->find_torrent(hash); + if (t != 0) return f(*t); + } + + throw_invalid_handle(); } -#endif - } #ifndef NDEBUG @@ -281,13 +226,7 @@ namespace libtorrent { INVARIANT_CHECK; - 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 t->status(); - } + if (m_ses == 0) throw_invalid_handle(); if (m_chk) { @@ -308,9 +247,38 @@ namespace libtorrent } } - 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 t->status(); + } + + throw_invalid_handle(); } + void torrent_handle::filter_piece(int index, bool filter) + { + INVARIANT_CHECK; + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::filter_piece, _1, index, filter)); + } + + bool torrent_handle::is_piece_filtered(int index) const + { + INVARIANT_CHECK; + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::is_piece_filtered, _1, index)); + } + + std::vector torrent_handle::filtered_pieces() const + { + INVARIANT_CHECK; + std::vector ret; + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::filtered_pieces, _1, boost::ref(ret))); + return ret; + } + std::vector const& torrent_handle::trackers() const { INVARIANT_CHECK; @@ -331,7 +299,7 @@ namespace libtorrent { INVARIANT_CHECK; - if (!has_metadata()) throw invalid_handle(); + if (!has_metadata()) throw_invalid_handle(); return call_member(m_ses, m_chk, m_info_hash , bind(&torrent::torrent_file, _1)); } @@ -342,12 +310,6 @@ namespace libtorrent if (m_ses == 0) return false; - { - boost::mutex::scoped_lock l(m_ses->m_mutex); - torrent* t = m_ses->find_torrent(m_info_hash); - if (t != 0) return true; - } - if (m_chk) { boost::mutex::scoped_lock l(m_chk->m_mutex); @@ -355,6 +317,12 @@ namespace libtorrent if (d != 0) return true; } + { + boost::mutex::scoped_lock l(m_ses->m_mutex); + torrent* t = m_ses->find_torrent(m_info_hash); + if (t != 0) return true; + } + return false; } @@ -499,11 +467,11 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw invalid_handle(); + 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) throw invalid_handle(); + if (t == 0) throw_invalid_handle(); peer_id id; std::fill(id.begin(), id.end(), 0); @@ -515,11 +483,11 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw invalid_handle(); + 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) throw invalid_handle(); + if (t == 0) throw_invalid_handle(); using boost::posix_time::second_clock; t->force_tracker_request(second_clock::universal_time() @@ -530,11 +498,11 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw invalid_handle(); + 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) throw invalid_handle(); + if (t == 0) throw_invalid_handle(); t->force_tracker_request(); } @@ -557,7 +525,7 @@ namespace libtorrent INVARIANT_CHECK; v.clear(); - if (m_ses == 0) throw invalid_handle(); + if (m_ses == 0) throw_invalid_handle(); boost::mutex::scoped_lock l(m_ses->m_mutex); @@ -565,8 +533,7 @@ namespace libtorrent if (t == 0) return; for (torrent::const_peer_iterator i = t->begin(); - i != t->end(); - ++i) + i != t->end(); ++i) { peer_connection* peer = i->second; @@ -580,6 +547,8 @@ namespace libtorrent const stat& statistics = peer->statistics(); p.down_speed = statistics.download_rate(); p.up_speed = statistics.upload_rate(); + p.payload_down_speed = statistics.download_payload_rate(); + p.payload_up_speed = statistics.upload_payload_rate(); p.id = peer->get_peer_id(); p.ip = peer->get_socket()->sender(); @@ -632,7 +601,7 @@ namespace libtorrent bool torrent_handle::send_chat_message(address ip, std::string message) const { - if (m_ses == 0) throw invalid_handle(); + if (m_ses == 0) throw_invalid_handle(); boost::mutex::scoped_lock l(m_ses->m_mutex); const torrent* t = m_ses->find_torrent(m_info_hash); @@ -668,7 +637,7 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw invalid_handle(); + 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); diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index 24850a7f5..3d8ee7ffd 100755 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -501,9 +501,7 @@ namespace libtorrent tracker_connections_t keep_connections; for (tracker_connections_t::const_iterator i = - m_connections.begin(); - i != m_connections.end(); - ++i) + m_connections.begin(); i != m_connections.end(); ++i) { if (!(*i)->has_requester()) keep_connections.push_back(*i); }