diff --git a/libtorrent/include/libtorrent/alert.hpp b/libtorrent/include/libtorrent/alert.hpp index b6b6711dc..954e39ef5 100755 --- a/libtorrent/include/libtorrent/alert.hpp +++ b/libtorrent/include/libtorrent/alert.hpp @@ -36,7 +36,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #ifdef _MSC_VER @@ -56,6 +55,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/time.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" #ifndef TORRENT_MAX_ALERT_TYPES #define TORRENT_MAX_ALERT_TYPES 15 diff --git a/libtorrent/include/libtorrent/assert.hpp b/libtorrent/include/libtorrent/assert.hpp index 488afe778..8ab605080 100644 --- a/libtorrent/include/libtorrent/assert.hpp +++ b/libtorrent/include/libtorrent/assert.hpp @@ -33,15 +33,17 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_ASSERT_HPP_INCLUDED #define TORRENT_ASSERT_HPP_INCLUDED +#include + #ifndef NDEBUG -#if defined __linux__ && defined _GNUC +#if defined __linux__ && defined __GNUC__ #ifdef assert #undef assert #endif -void assert_fail(int line, char const* file); +void assert_fail(const char* expr, int line, char const* file, char const* function); -#define assert(x) if (!(x)) assert_fail(__LINE__, __FILE__) +#define assert(x) if (!(x)) assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__) #endif diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index e0962bf06..74ca7c8f7 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -240,7 +240,7 @@ namespace libtorrent bool is_listening() const; torrent_handle add_torrent( - torrent_info const& ti + boost::intrusive_ptr ti , fs::path const& save_path , entry const& resume_data , bool compact_mode diff --git a/libtorrent/include/libtorrent/config.hpp b/libtorrent/include/libtorrent/config.hpp index b36d4da22..1281ab84c 100755 --- a/libtorrent/include/libtorrent/config.hpp +++ b/libtorrent/include/libtorrent/config.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_CONFIG_HPP_INCLUDED #include +#include "libtorrent/assert.hpp" #if defined(__GNUC__) && __GNUC__ >= 4 diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp index 59e29803d..7fd6c8c53 100755 --- a/libtorrent/include/libtorrent/entry.hpp +++ b/libtorrent/include/libtorrent/entry.hpp @@ -64,10 +64,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include "libtorrent/size_type.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/hasher.hpp b/libtorrent/include/libtorrent/hasher.hpp index 932f2b100..71b7f9ede 100755 --- a/libtorrent/include/libtorrent/hasher.hpp +++ b/libtorrent/include/libtorrent/hasher.hpp @@ -33,11 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_HASHER_HPP_INCLUDED #define TORRENT_HASHER_HPP_INCLUDED -#include #include #include "libtorrent/peer_id.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" #include "zlib.h" #ifdef TORRENT_USE_OPENSSL diff --git a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp index a432bc350..ed6944ebb 100644 --- a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp +++ b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp @@ -34,14 +34,17 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_INTRUSIVE_PTR_BASE #include -#include #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { template struct intrusive_ptr_base { + intrusive_ptr_base(const intrusive_ptr_base& b) + : m_refs(0) {} + friend void intrusive_ptr_add_ref(intrusive_ptr_base const* s) { assert(s->m_refs >= 0); diff --git a/libtorrent/include/libtorrent/invariant_check.hpp b/libtorrent/include/libtorrent/invariant_check.hpp index c6eacf338..3eaacf34c 100755 --- a/libtorrent/include/libtorrent/invariant_check.hpp +++ b/libtorrent/include/libtorrent/invariant_check.hpp @@ -5,7 +5,7 @@ #ifndef TORRENT_INVARIANT_ACCESS_HPP_INCLUDED #define TORRENT_INVARIANT_ACCESS_HPP_INCLUDED -#include +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/kademlia/node.hpp b/libtorrent/include/libtorrent/kademlia/node.hpp index 850333043..ee75e7f0a 100644 --- a/libtorrent/include/libtorrent/kademlia/node.hpp +++ b/libtorrent/include/libtorrent/kademlia/node.hpp @@ -34,7 +34,6 @@ POSSIBILITY OF SUCH DAMAGE. #define NODE_HPP #include -#include #include #include @@ -45,6 +44,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include diff --git a/libtorrent/include/libtorrent/kademlia/node_id.hpp b/libtorrent/include/libtorrent/kademlia/node_id.hpp index eb4d6c539..5e732acac 100644 --- a/libtorrent/include/libtorrent/kademlia/node_id.hpp +++ b/libtorrent/include/libtorrent/kademlia/node_id.hpp @@ -33,10 +33,10 @@ POSSIBILITY OF SUCH DAMAGE. #define NODE_ID_HPP #include -#include #include #include "libtorrent/peer_id.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { namespace dht { diff --git a/libtorrent/include/libtorrent/pe_crypto.hpp b/libtorrent/include/libtorrent/pe_crypto.hpp index 91616c42d..e2276dee6 100644 --- a/libtorrent/include/libtorrent/pe_crypto.hpp +++ b/libtorrent/include/libtorrent/pe_crypto.hpp @@ -35,13 +35,12 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED #define TORRENT_PE_CRYPTO_HPP_INCLUDED -#include - #include #include #include -#include "peer_id.hpp" // For sha1_hash +#include "libtorrent/peer_id.hpp" // For sha1_hash +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index 8dfc2b805..7f6bce29a 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -152,11 +152,15 @@ namespace libtorrent int upload_limit() const { return m_upload_limit; } int download_limit() const { return m_download_limit; } - bool prefer_whole_pieces() const - { return m_prefer_whole_pieces; } + int prefer_whole_pieces() const + { + if (m_prefer_whole_pieces == 0) + return peer_info_struct() && peer_info_struct()->on_parole ? 1 : 0; + return m_prefer_whole_pieces; + } - void prefer_whole_pieces(bool b) - { m_prefer_whole_pieces = b; } + void prefer_whole_pieces(int num) + { m_prefer_whole_pieces = num; } bool request_large_blocks() const { return m_request_large_blocks; } @@ -219,6 +223,7 @@ namespace libtorrent std::vector const& get_bitfield() const; std::vector const& allowed_fast(); + std::vector const& suggested_pieces() const { return m_suggested_pieces; } void timed_out(); // this will cause this peer_connection to be disconnected. @@ -303,6 +308,7 @@ namespace libtorrent void incoming_have_all(); void incoming_have_none(); void incoming_allowed_fast(int index); + void incoming_suggest(int index); // the following functions appends messages // to the send buffer @@ -493,6 +499,11 @@ namespace libtorrent // the time we sent a request to // this peer the last time ptime m_last_request; + // the time we received the last + // piece request from the peer + ptime m_last_incoming_request; + // the time when we unchoked this peer + ptime m_last_unchoke; int m_packet_size; int m_recv_pos; @@ -590,7 +601,7 @@ namespace libtorrent std::deque m_requests; // the blocks we have reserved in the piece - // picker and will send to this peer. + // picker and will request from this peer. std::deque m_request_queue; // the queue of blocks we have requested @@ -658,12 +669,13 @@ namespace libtorrent bool m_writing; bool m_reading; - // if set to true, this peer will always prefer - // to request entire pieces, rather than blocks. - // if it is false, the download rate limit setting + // if set to non-zero, this peer will always prefer + // to request entire n pieces, rather than blocks. + // where n is the value of this variable. + // if it is 0, the download rate limit setting // will be used to determine if whole pieces // are preferred. - bool m_prefer_whole_pieces; + int m_prefer_whole_pieces; // if this is true, the blocks picked by the piece // picker will be merged before passed to the @@ -718,6 +730,10 @@ namespace libtorrent // requested (regardless of choke state) std::vector m_allowed_fast; + // pieces that has been suggested to be + // downloaded from this peer + std::vector m_suggested_pieces; + // the number of bytes send to the disk-io // thread that hasn't yet been completely written. int m_outstanding_writing_bytes; diff --git a/libtorrent/include/libtorrent/peer_id.hpp b/libtorrent/include/libtorrent/peer_id.hpp index b66c1d4bc..57303e2fd 100755 --- a/libtorrent/include/libtorrent/peer_id.hpp +++ b/libtorrent/include/libtorrent/peer_id.hpp @@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include #include #include #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index 8e396bdff..1bbe63332 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #ifdef _MSC_VER @@ -52,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/session_settings.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -191,9 +191,9 @@ namespace libtorrent // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION! // The last argument is the policy::peer pointer for the peer that // we'll download from. - void pick_pieces(const std::vector& pieces + void pick_pieces(std::vector const& pieces , std::vector& interesting_blocks - , int num_pieces, bool prefer_whole_pieces + , int num_pieces, int prefer_whole_pieces , void* peer, piece_state_t speed , bool rarest_first) const; @@ -202,11 +202,11 @@ namespace libtorrent // are added to interesting_blocks, and busy blocks are // added to backup_blocks. num blocks is the number of // blocks to be picked. - int add_interesting_blocks(const std::vector& piece_list + int add_interesting_blocks(std::vector const& piece_list , const std::vector& pieces , std::vector& interesting_blocks , std::vector& backup_blocks - , int num_blocks, bool prefer_whole_pieces + , int num_blocks, int prefer_whole_pieces , void* peer, piece_state_t speed , bool ignore_downloading_pieces) const; @@ -284,6 +284,9 @@ namespace libtorrent private: + std::pair expand_piece(int piece, int whole_pieces + , std::vector const& have) const; + struct piece_pos { piece_pos() {} diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index 7451f5915..a7ccc8d57 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -142,6 +142,14 @@ namespace libtorrent , entry const& resume_data = entry() , bool compact_mode = true , bool paused = false + , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED; + + torrent_handle add_torrent( + boost::intrusive_ptr ti + , fs::path const& save_path + , entry const& resume_data = entry() + , bool compact_mode = true + , bool paused = false , storage_constructor_type sc = default_storage_constructor); torrent_handle add_torrent( diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp index 8a10c7148..8cdab5476 100755 --- a/libtorrent/include/libtorrent/storage.hpp +++ b/libtorrent/include/libtorrent/storage.hpp @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #ifdef _MSC_VER @@ -147,10 +148,11 @@ namespace libtorrent }; typedef storage_interface* (&storage_constructor_type)( - torrent_info const&, fs::path const& + boost::intrusive_ptr, fs::path const& , file_pool&); - TORRENT_EXPORT storage_interface* default_storage_constructor(torrent_info const& ti + TORRENT_EXPORT storage_interface* default_storage_constructor( + boost::intrusive_ptr ti , fs::path const& path, file_pool& fp); // returns true if the filesystem the path relies on supports @@ -169,7 +171,7 @@ namespace libtorrent piece_manager( boost::shared_ptr const& torrent - , torrent_info const& ti + , boost::intrusive_ptr ti , fs::path const& path , file_pool& fp , disk_io_thread& io @@ -227,7 +229,7 @@ namespace libtorrent { return m_compact_mode; } #ifndef NDEBUG - std::string name() const { return m_info.name(); } + std::string name() const { return m_info->name(); } #endif private: @@ -283,7 +285,7 @@ namespace libtorrent // a bitmask representing the pieces we have std::vector m_have_piece; - torrent_info const& m_info; + boost::intrusive_ptr m_info; // slots that haven't had any file storage allocated std::vector m_unallocated_slots; @@ -313,12 +315,6 @@ namespace libtorrent mutable boost::recursive_mutex m_mutex; - bool m_allocating; - boost::mutex m_allocating_monitor; - boost::condition m_allocating_condition; - - // these states are used while checking/allocating the torrent - enum { // the default initial state state_none, @@ -333,6 +329,11 @@ namespace libtorrent } m_state; int m_current_slot; + // this is saved in case we need to instantiate a new + // storage (osed when remapping files) + storage_constructor_type m_storage_constructor; + + // temporary buffer used while checking std::vector m_piece_data; // this maps a piece hash to piece index. It will be @@ -340,6 +341,8 @@ namespace libtorrent // isn't needed) std::multimap m_hash_to_piece; + // this map contains partial hashes for downloading + // pieces. std::map m_piece_hasher; disk_io_thread& m_io_thread; diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index dabc34141..b8f8d7ae4 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -97,7 +97,7 @@ namespace libtorrent torrent( aux::session_impl& ses , aux::checker_impl& checker - , torrent_info const& tf + , boost::intrusive_ptr tf , fs::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode @@ -469,14 +469,14 @@ namespace libtorrent bool is_seed() const { return valid_metadata() - && m_num_pieces == m_torrent_file.num_pieces(); + && m_num_pieces == m_torrent_file->num_pieces(); } // this is true if we have all the pieces that we want bool is_finished() const { if (is_seed()) return true; - return valid_metadata() && m_torrent_file.num_pieces() + return valid_metadata() && m_torrent_file->num_pieces() - m_num_pieces - m_picker->num_filtered() == 0; } @@ -498,7 +498,7 @@ namespace libtorrent } piece_manager& filesystem(); torrent_info const& torrent_file() const - { return m_torrent_file; } + { return *m_torrent_file; } std::vector const& trackers() const { return m_trackers; } @@ -539,7 +539,7 @@ namespace libtorrent bool ready_for_connections() const { return m_connections_initialized; } bool valid_metadata() const - { return m_torrent_file.is_valid(); } + { return m_torrent_file->is_valid(); } // parses the info section from the given // bencoded tree and moves the torrent @@ -563,7 +563,7 @@ namespace libtorrent void update_peer_interest(); - torrent_info m_torrent_file; + boost::intrusive_ptr m_torrent_file; // is set to true when the torrent has // been aborted. diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp index 795289bf4..093d33781 100755 --- a/libtorrent/include/libtorrent/torrent_info.hpp +++ b/libtorrent/include/libtorrent/torrent_info.hpp @@ -57,6 +57,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/peer_request.hpp" #include "libtorrent/config.hpp" #include "libtorrent/time.hpp" +#include "libtorrent/intrusive_ptr_base.hpp" namespace libtorrent { @@ -96,7 +97,7 @@ namespace libtorrent virtual const char* what() const throw() { return "invalid torrent file"; } }; - class TORRENT_EXPORT torrent_info + class TORRENT_EXPORT torrent_info : public intrusive_ptr_base { public: diff --git a/libtorrent/src/assert.cpp b/libtorrent/src/assert.cpp index c2cb1b4a5..da79a745b 100644 --- a/libtorrent/src/assert.cpp +++ b/libtorrent/src/assert.cpp @@ -32,9 +32,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef NDEBUG +#include +#include #include -void assert_fail(int line, char const* file) +void assert_fail(char const* expr, int line, char const* file, char const* function) { fprintf(stderr, "assertion failed. Please file a bugreport at " @@ -42,9 +44,11 @@ void assert_fail(int line, char const* file) "Please include the following information:\n\n" "file: '%s'\n" "line: %d\n" - "stack:\n", file, line); + "function: %s\n" + "expression: %s\n" + "stack:\n", file, line, function, expr); - void* stacktrace[50]; + void* stack[50]; int size = backtrace(stack, 50); char** symbols = backtrace_symbols(stack, size); @@ -54,6 +58,7 @@ void assert_fail(int line, char const* file) } free(symbols); + exit(1); } #endif diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index 2a4347778..1b1de3a81 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -1062,8 +1062,14 @@ namespace libtorrent if (!m_supports_fast) throw protocol_error("got 'suggest_piece' without FAST extension support"); - // just ignore for now - return; + m_statistics.received_bytes(0, received); + if (!packet_finished()) return; + + buffer::const_interval recv_buffer = receive_buffer(); + + const char* ptr = recv_buffer.begin + 1; + int piece = detail::read_uint32(ptr); + incoming_suggest(piece); } void bt_peer_connection::on_have_all(int received) diff --git a/libtorrent/src/escape_string.cpp b/libtorrent/src/escape_string.cpp index 02a4fa085..673d56288 100755 --- a/libtorrent/src/escape_string.cpp +++ b/libtorrent/src/escape_string.cpp @@ -31,9 +31,9 @@ POSSIBILITY OF SUCH DAMAGE. */ #include "libtorrent/pch.hpp" +#include "libtorrent/assert.hpp" #include -#include #include #include #include diff --git a/libtorrent/src/kademlia/node_id.cpp b/libtorrent/src/kademlia/node_id.cpp index 4ed413714..ad06c515d 100644 --- a/libtorrent/src/kademlia/node_id.cpp +++ b/libtorrent/src/kademlia/node_id.cpp @@ -34,10 +34,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include #include "libtorrent/kademlia/node_id.hpp" +#include "libtorrent/assert.hpp" using boost::bind; diff --git a/libtorrent/src/pe_crypto.cpp b/libtorrent/src/pe_crypto.cpp index 437c93e2c..981eca63d 100644 --- a/libtorrent/src/pe_crypto.cpp +++ b/libtorrent/src/pe_crypto.cpp @@ -32,13 +32,13 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_DISABLE_ENCRYPTION -#include #include #include #include #include "libtorrent/pe_crypto.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index c6be880ad..3f1fe700d 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/policy.hpp" #include "libtorrent/socket_type.hpp" +#include "libtorrent/assert.hpp" using boost::bind; using boost::shared_ptr; @@ -76,6 +77,8 @@ namespace libtorrent , m_timeout(m_ses.settings().peer_timeout) , m_last_piece(time_now()) , m_last_request(time_now()) + , m_last_incoming_request(min_time()) + , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) @@ -154,6 +157,8 @@ namespace libtorrent , m_timeout(m_ses.settings().peer_timeout) , m_last_piece(time_now()) , m_last_request(time_now()) + , m_last_incoming_request(min_time()) + , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) @@ -338,7 +343,7 @@ namespace libtorrent // if this is a web seed. we don't have a peer_info struct if (m_peer_info) m_peer_info->seed = true; // if we're a seed too, disconnect - if (t->is_seed()) + if (t->is_finished()) { throw std::runtime_error("seed to seed connection redundant, disconnecting"); } @@ -395,7 +400,12 @@ namespace libtorrent { // dont announce during handshake if (in_handshake()) return; - + + // remove suggested pieces that we have + std::vector::iterator i = std::find( + m_suggested_pieces.begin(), m_suggested_pieces.end(), index); + if (i != m_suggested_pieces.end()) m_suggested_pieces.erase(i); + // optimization, don't send have messages // to peers that already have the piece if (!m_ses.settings().send_redundant_have @@ -511,6 +521,7 @@ namespace libtorrent assert(t); assert(t->valid_metadata()); + torrent_info const& ti = t->torrent_file(); return p.piece >= 0 && p.piece < t->torrent_file().num_pieces() @@ -518,11 +529,13 @@ namespace libtorrent && p.start >= 0 && (p.length == t->block_size() || (p.length < t->block_size() - && p.piece == t->torrent_file().num_pieces()-1 - && p.start + p.length == t->torrent_file().piece_size(p.piece)) + && p.piece == ti.num_pieces()-1 + && p.start + p.length == ti.piece_size(p.piece)) || (m_request_large_blocks - && p.length <= t->torrent_file().piece_size(p.piece))) - && p.start + p.length <= t->torrent_file().piece_size(p.piece) + && p.length <= ti.piece_length() * m_prefer_whole_pieces == 0 ? + 1 : m_prefer_whole_pieces)) + && p.piece * size_type(ti.piece_length()) + p.start + p.length + <= ti.total_size() && (p.start % t->block_size() == 0); } @@ -723,6 +736,33 @@ namespace libtorrent } } + // ----------------------------- + // -------- REJECT PIECE ------- + // ----------------------------- + + void peer_connection::incoming_suggest(int index) + { + INVARIANT_CHECK; + +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() + << " <== SUGGEST_PIECE [ piece: " << index << " ]\n"; +#endif + boost::shared_ptr t = m_torrent.lock(); + if (!t) return; + + if (t->have_piece(index)) return; + + if (m_suggested_pieces.size() > 9) + m_suggested_pieces.erase(m_suggested_pieces.begin()); + m_suggested_pieces.push_back(index); + +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << time_now_string() + << " ** SUGGEST_PIECE [ piece: " << index << " added to set: " << m_suggested_pieces.size() << " ]\n"; +#endif + } + // ----------------------------- // ---------- UNCHOKE ---------- // ----------------------------- @@ -877,7 +917,7 @@ namespace libtorrent { assert(m_peer_info); m_peer_info->seed = true; - if (t->is_seed()) + if (t->is_finished()) { throw protocol_error("seed to seed connection redundant, disconnecting"); } @@ -948,7 +988,7 @@ namespace libtorrent // if this is a web seed. we don't have a peer_info struct if (m_peer_info) m_peer_info->seed = true; // if we're a seed too, disconnect - if (t->is_seed()) + if (t->is_finished()) { throw protocol_error("seed to seed connection redundant, disconnecting"); } @@ -1096,6 +1136,7 @@ namespace libtorrent else { m_requests.push_back(r); + m_last_incoming_request = time_now(); fill_send_buffer(); } } @@ -1476,7 +1517,7 @@ namespace libtorrent #endif // if we're a seed too, disconnect - if (t->is_seed()) + if (t->is_finished()) throw protocol_error("seed to seed connection redundant, disconnecting"); assert(!m_have_piece.empty()); @@ -1585,6 +1626,7 @@ namespace libtorrent assert(block.block_index >= 0); assert(block.block_index < t->torrent_file().piece_size(block.piece_index)); assert(!t->picker().is_requested(block) || (t->picker().num_peers(block) > 0)); + assert(!t->have_piece(block.piece_index)); piece_picker::piece_state_t state; peer_speed_t speed = peer_speed(); @@ -1701,6 +1743,7 @@ namespace libtorrent INVARIANT_CHECK; if (!m_choked) return; + m_last_unchoke = time_now(); write_unchoke(); m_choked = false; @@ -1776,21 +1819,27 @@ namespace libtorrent // blocks that are in the same piece into larger requests if (m_request_large_blocks) { - while (!m_request_queue.empty() - && m_request_queue.front().piece_index == r.piece - && m_request_queue.front().block_index == block.block_index + 1) + int blocks_per_piece = t->torrent_file().piece_length() / t->block_size(); + + while (!m_request_queue.empty()) { + // check to see if this block is connected to the previous one + // if it is, merge them, otherwise, break this merge loop + piece_block const& front = m_request_queue.front(); + if (front.piece_index * blocks_per_piece + front.block_index + != block.piece_index * blocks_per_piece + block.block_index + 1) + break; block = m_request_queue.front(); m_request_queue.pop_front(); m_download_queue.push_back(block); -/* + #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() - << " *** REQUEST-QUEUE** [ " + << " *** MERGING REQUEST ** [ " "piece: " << block.piece_index << " | " "block: " << block.block_index << " ]\n"; #endif -*/ + block_offset = block.block_index * t->block_size(); block_size = (std::min)((int)t->torrent_file().piece_size( block.piece_index) - block_offset, t->block_size()); @@ -2137,7 +2186,7 @@ namespace libtorrent // maintain the share ratio given by m_ratio // with all peers. - if (t->is_seed() || is_choked() || t->ratio() == 0.0f) + if (t->is_finished() || is_choked() || t->ratio() == 0.0f) { // if we have downloaded more than one piece more // than we have uploaded OR if we are a seed @@ -2862,9 +2911,20 @@ namespace libtorrent // if the peer hasn't said a thing for a certain // time, it is considered to have timed out time_duration d; - d = time_now() - m_last_receive; + d = now - m_last_receive; if (d > seconds(m_timeout)) return true; + // disconnect peers that we unchoked, but + // they didn't send a request within 20 seconds. + // but only if we're a seed + boost::shared_ptr t = m_torrent.lock(); + d = now - (std::max)(m_last_unchoke, m_last_incoming_request); + if (m_requests.empty() + && !m_choked + && m_peer_interested + && t && t->is_finished() + && d > seconds(20)) return true; + // TODO: as long as we have less than 95% of the // global (or local) connection limit, connections should // never time out for another reason diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index d44dd1435..a7debe712 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -201,7 +201,7 @@ namespace libtorrent , end(in.end()); i != end; ++i) { m_piece_map[*i].index = c++; - assert(m_piece_map[*i].priority(old_limit) == old_limit); + assert(m_piece_map[*i].priority(old_limit) == old_limit * 2); } } } @@ -1079,7 +1079,7 @@ namespace libtorrent // or slow once they're started. void piece_picker::pick_pieces(const std::vector& pieces , std::vector& interesting_blocks - , int num_blocks, bool prefer_whole_pieces + , int num_blocks, int prefer_whole_pieces , void* peer, piece_state_t speed, bool rarest_first) const { TORRENT_PIECE_PICKER_INVARIANT_CHECK; @@ -1102,7 +1102,7 @@ namespace libtorrent // ignored as long as possible. All blocks found in downloading // pieces are regarded as backup blocks bool ignore_downloading_pieces = false; - if (prefer_whole_pieces) + if (prefer_whole_pieces > 0 || !rarest_first) { std::vector downloading_pieces; downloading_pieces.reserve(m_downloads.size()); @@ -1111,34 +1111,46 @@ namespace libtorrent { downloading_pieces.push_back(i->index); } - add_interesting_blocks(downloading_pieces, pieces - , backup_blocks, backup_blocks, num_blocks - , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); + if (prefer_whole_pieces > 0) + { + add_interesting_blocks(downloading_pieces, pieces + , backup_blocks, backup_blocks, num_blocks + , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); + } + else + { + num_blocks = add_interesting_blocks(downloading_pieces, pieces + , interesting_blocks, backup_blocks, num_blocks + , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); + } ignore_downloading_pieces = true; } - // this loop will loop from pieces with priority 1 and up - // until we either reach the end of the piece list or - // has filled the interesting_blocks with num_blocks - // blocks. - - // +1 is to ignore pieces that no peer has. The bucket with index 0 contains - // pieces that 0 other peers have. bucket will point to a bucket with - // pieces with the same priority. It will be iterated in priority - // order (high priority/rare pices first). The content of each - // bucket is randomized - for (std::vector >::const_iterator bucket - = m_piece_info.begin() + 1; bucket != m_piece_info.end(); - ++bucket) + if (rarest_first) { - if (bucket->empty()) continue; - num_blocks = add_interesting_blocks(*bucket, pieces - , interesting_blocks, backup_blocks, num_blocks - , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); - assert(num_blocks >= 0); - if (num_blocks == 0) return; - if (rarest_first) continue; + // this loop will loop from pieces with priority 1 and up + // until we either reach the end of the piece list or + // has filled the interesting_blocks with num_blocks + // blocks. + // +1 is to ignore pieces that no peer has. The bucket with index 0 contains + // pieces that 0 other peers have. bucket will point to a bucket with + // pieces with the same priority. It will be iterated in priority + // order (high priority/rare pices first). The content of each + // bucket is randomized + for (std::vector >::const_iterator bucket + = m_piece_info.begin() + 1; num_blocks > 0 && bucket != m_piece_info.end(); + ++bucket) + { + if (bucket->empty()) continue; + num_blocks = add_interesting_blocks(*bucket, pieces + , interesting_blocks, backup_blocks, num_blocks + , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); + assert(num_blocks >= 0); + } + } + else + { // we're not using rarest first (only for the first // bucket, since that's where the currently downloading // pieces are) @@ -1147,8 +1159,9 @@ namespace libtorrent while (num_blocks > 0) { while (!pieces[piece] - || m_piece_map[piece].index == piece_pos::we_have_index - || m_piece_map[piece].priority(m_sequenced_download_threshold) < 2) + || m_piece_map[piece].have() + || m_piece_map[piece].downloading + || m_piece_map[piece].filtered()) { ++piece; if (piece == int(m_piece_map.size())) piece = 0; @@ -1158,23 +1171,28 @@ namespace libtorrent assert(m_piece_map[piece].downloading == false); - int num_blocks_in_piece = blocks_in_piece(piece); - - if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks) - num_blocks_in_piece = num_blocks; - for (int j = 0; j < num_blocks_in_piece; ++j) - interesting_blocks.push_back(piece_block(piece, j)); - num_blocks -= (std::min)(num_blocks_in_piece, num_blocks); - ++piece; + int start, end; + boost::tie(start, end) = expand_piece(piece, prefer_whole_pieces, pieces); + for (int k = start; k < end; ++k) + { + int num_blocks_in_piece = blocks_in_piece(k); + if (prefer_whole_pieces == 0 && num_blocks_in_piece > num_blocks) + num_blocks_in_piece = num_blocks; + for (int j = 0; j < num_blocks_in_piece; ++j) + { + interesting_blocks.push_back(piece_block(k, j)); + --num_blocks; + } + } + piece = end; if (piece == int(m_piece_map.size())) piece = 0; // could not find any more pieces if (piece == start_piece) return; } - if (num_blocks == 0) return; - break; + } - assert(num_blocks > 0); + if (num_blocks <= 0) return; if (!backup_blocks.empty()) interesting_blocks.insert(interesting_blocks.end() @@ -1222,7 +1240,7 @@ namespace libtorrent , std::vector const& pieces , std::vector& interesting_blocks , std::vector& backup_blocks - , int num_blocks, bool prefer_whole_pieces + , int num_blocks, int prefer_whole_pieces , void* peer, piece_state_t speed , bool ignore_downloading_pieces) const { @@ -1266,7 +1284,7 @@ namespace libtorrent // blocks to the backup list. If the prioritized // blocks aren't enough, blocks from this list // will be picked. - if (prefer_whole_pieces && !exclusive) + if (prefer_whole_pieces > 0 && !exclusive) { for (int j = 0; j < num_blocks_in_piece; ++j) { @@ -1321,7 +1339,7 @@ namespace libtorrent num_blocks--; // if we prefer whole pieces, continue picking from this // piece even though we have num_blocks - if (prefer_whole_pieces) continue; + if (prefer_whole_pieces > 0) continue; assert(num_blocks >= 0); if (num_blocks == 0) return num_blocks; } @@ -1330,23 +1348,68 @@ namespace libtorrent backup_blocks.push_back(piece_block(*i, j)); } } - assert(num_blocks >= 0 || prefer_whole_pieces); + assert(num_blocks >= 0 || prefer_whole_pieces > 0); if (num_blocks < 0) num_blocks = 0; } else { - if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks) - num_blocks_in_piece = num_blocks; - for (int j = 0; j < num_blocks_in_piece; ++j) - interesting_blocks.push_back(piece_block(*i, j)); - num_blocks -= (std::min)(num_blocks_in_piece, num_blocks); + // pick a new piece + if (prefer_whole_pieces == 0) + { + if (num_blocks_in_piece > num_blocks) + num_blocks_in_piece = num_blocks; + for (int j = 0; j < num_blocks_in_piece; ++j) + interesting_blocks.push_back(piece_block(*i, j)); + num_blocks -= num_blocks_in_piece; + } + else + { + int start, end; + boost::tie(start, end) = expand_piece(*i, prefer_whole_pieces, pieces); + for (int k = start; k < end; ++k) + { + num_blocks_in_piece = blocks_in_piece(k); + for (int j = 0; j < num_blocks_in_piece; ++j) + { + interesting_blocks.push_back(piece_block(k, j)); + --num_blocks; + } + } + } } - assert(num_blocks >= 0); - if (num_blocks == 0) return num_blocks; + if (num_blocks <= 0) return num_blocks < 0 ? 0 : num_blocks; } return num_blocks; } + std::pair piece_picker::expand_piece(int piece, int whole_pieces + , std::vector const& have) const + { + if (whole_pieces == 0) return std::make_pair(piece, piece + 1); + + int start = piece - 1; + int lower_limit = piece - whole_pieces; + if (lower_limit < -1) lower_limit = -1; + while (start > lower_limit + && have[start] + && !m_piece_map[start].downloading + && !m_piece_map[start].filtered() + && !m_piece_map[start].have()) + --start; + ++start; + assert(start >= 0); + int end = piece + 1; + int upper_limit = start + whole_pieces; + if (upper_limit > int(m_piece_map.size())) upper_limit = int(m_piece_map.size()); + while (end < upper_limit + && have[end] + && !m_piece_map[end].downloading + && !m_piece_map[end].filtered() + && !m_piece_map[end].have()) + ++end; + return std::make_pair(start, end); + } + bool piece_picker::is_piece_finished(int index) const { assert(index < (int)m_piece_map.size()); @@ -1432,6 +1495,7 @@ namespace libtorrent assert(block.block_index >= 0); assert(block.piece_index < (int)m_piece_map.size()); assert(block.block_index < blocks_in_piece(block.piece_index)); + assert(!m_piece_map[block.piece_index].have()); piece_pos& p = m_piece_map[block.piece_index]; if (p.downloading == 0) diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 5683b74e5..83d4577e3 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -209,16 +209,15 @@ namespace libtorrent std::vector interesting_pieces; interesting_pieces.reserve(100); - bool prefer_whole_pieces = c.prefer_whole_pieces() - || (c.peer_info_struct() && c.peer_info_struct()->on_parole); + int prefer_whole_pieces = c.prefer_whole_pieces(); bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold; - if (!prefer_whole_pieces) + if (prefer_whole_pieces == 0) { prefer_whole_pieces = c.statistics().download_payload_rate() * t.settings().whole_pieces_threshold - > t.torrent_file().piece_length(); + > t.torrent_file().piece_length() ? 1 : 0; } // if we prefer whole pieces, the piece picker will pick at least @@ -258,6 +257,18 @@ namespace libtorrent } else { + if (!c.suggested_pieces().empty()) + { + // if the peer has suggested us to download certain pieces + // try to pick among those primarily + std::vector const& suggested = c.suggested_pieces(); + + p.add_interesting_blocks(suggested, c.get_bitfield() + , interesting_pieces, busy_pieces, num_requests + , prefer_whole_pieces, c.peer_info_struct(), state + , false); + } + // picks the interesting pieces from this peer // the integer is the number of pieces that // should be guaranteed to be available for download @@ -266,15 +277,18 @@ namespace libtorrent // the last argument is if we should prefer whole pieces // for this peer. If we're downloading one piece in 20 seconds // then use this mode. - p.pick_pieces(c.get_bitfield(), interesting_pieces - , num_requests, prefer_whole_pieces, c.peer_info_struct() - , state, rarest_first); - busy_pieces.reserve(10); + if (int(interesting_pieces.size()) < num_requests) + p.pick_pieces(c.get_bitfield(), interesting_pieces + , num_requests, prefer_whole_pieces, c.peer_info_struct() + , state, rarest_first); } #ifdef TORRENT_VERBOSE_LOGGING - (*c.m_logger) << time_now_string() << " PIECE_PICKER [ picked: " << interesting_pieces.size() << " ]\n"; + (*c.m_logger) << time_now_string() << " PIECE_PICKER [ php: " << prefer_whole_pieces + << " picked: " << interesting_pieces.size() << " ]\n"; #endif + std::deque const& dq = c.download_queue(); + std::deque const& rq = c.request_queue(); for (std::vector::iterator i = interesting_pieces.begin(); i != interesting_pieces.end(); ++i) { @@ -282,8 +296,6 @@ namespace libtorrent { if (num_requests <= 0) break; // don't request pieces we already have in our request queue - const std::deque& dq = c.download_queue(); - const std::deque& rq = c.request_queue(); if (std::find(dq.begin(), dq.end(), *i) != dq.end() || std::find(rq.begin(), rq.end(), *i) != rq.end()) continue; @@ -516,6 +528,7 @@ namespace libtorrent int max_failcount = m_torrent->settings().max_failcount; int min_reconnect_time = m_torrent->settings().min_reconnect_time; + bool finished = m_torrent->is_finished(); aux::session_impl& ses = m_torrent->session(); @@ -524,7 +537,7 @@ namespace libtorrent if (i->connection) continue; if (i->banned) continue; if (i->type == peer::not_connectable) continue; - if (i->seed && m_torrent->is_seed()) continue; + if (i->seed && finished) continue; if (i->failcount >= max_failcount) continue; if (now - i->connected < seconds(i->failcount * min_reconnect_time)) continue; @@ -1179,7 +1192,7 @@ namespace libtorrent && m_torrent->session().num_uploads() < m_torrent->session().max_uploads() && (m_torrent->ratio() == 0 || c.share_diff() >= -free_upload_amount - || m_torrent->is_seed())) + || m_torrent->is_finished())) { m_torrent->session().unchoke_peer(c); } diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index 8175cbdfe..818af3ada 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -181,6 +181,19 @@ namespace libtorrent , bool compact_mode , bool paused , storage_constructor_type sc) + { + boost::intrusive_ptr tip(new torrent_info(ti)); + return m_impl->add_torrent(tip, save_path, resume_data + , compact_mode, sc, paused); + } + + torrent_handle session::add_torrent( + boost::intrusive_ptr ti + , fs::path const& save_path + , entry const& resume_data + , bool compact_mode + , bool paused + , storage_constructor_type sc) { return m_impl->add_torrent(ti, save_path, resume_data , compact_mode, sc, paused); diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 125664302..55c5cc32c 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -786,8 +786,30 @@ namespace detail return; } + // check if we have any active torrents + // if we don't reject the connection + if (m_torrents.empty()) + { + return; + } + else + { + bool has_active_torrent = false; + for (torrent_map::iterator i = m_torrents.begin() + , end(m_torrents.end()); i != end; ++i) + { + if (!i->second->is_paused()) + { + has_active_torrent = true; + break; + } + } + if (!has_active_torrent) + return; + } + boost::intrusive_ptr c( - new bt_peer_connection(*this, s, 0)); + new bt_peer_connection(*this, s, 0)); #ifndef NDEBUG c->m_in_constructor = false; #endif @@ -1454,7 +1476,7 @@ namespace detail } torrent_handle session_impl::add_torrent( - torrent_info const& ti + boost::intrusive_ptr ti , fs::path const& save_path , entry const& resume_data , bool compact_mode @@ -1466,7 +1488,7 @@ namespace detail assert(m_external_listen_port > 0); assert(!save_path.empty()); - if (ti.begin_files() == ti.end_files()) + if (ti->begin_files() == ti->end_files()) throw std::runtime_error("no files in torrent"); // lock the session and the checker thread (the order is important!) @@ -1479,11 +1501,11 @@ namespace detail throw std::runtime_error("session is closing"); // is the torrent already active? - if (!find_torrent(ti.info_hash()).expired()) + if (!find_torrent(ti->info_hash()).expired()) throw duplicate_torrent(); // is the torrent currently being checked? - if (m_checker_impl.find_torrent(ti.info_hash())) + if (m_checker_impl.find_torrent(ti->info_hash())) throw duplicate_torrent(); // create the torrent and the data associated with @@ -1508,13 +1530,13 @@ namespace detail new aux::piece_checker_data); d->torrent_ptr = torrent_ptr; d->save_path = save_path; - d->info_hash = ti.info_hash(); + d->info_hash = ti->info_hash(); d->resume_data = resume_data; #ifndef TORRENT_DISABLE_DHT if (m_dht) { - torrent_info::nodes_t const& nodes = ti.nodes(); + torrent_info::nodes_t const& nodes = ti->nodes(); std::for_each(nodes.begin(), nodes.end(), bind( (void(dht::dht_tracker::*)(std::pair const&)) &dht::dht_tracker::add_node @@ -1528,7 +1550,7 @@ namespace detail // job in its queue m_checker_impl.m_cond.notify_one(); - return torrent_handle(this, &m_checker_impl, ti.info_hash()); + return torrent_handle(this, &m_checker_impl, ti->info_hash()); } torrent_handle session_impl::add_torrent( diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 64f601927..1cce6ad81 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -345,11 +345,11 @@ namespace libtorrent class storage : public storage_interface, boost::noncopyable { public: - storage(torrent_info const& info, fs::path const& path, file_pool& fp) + storage(boost::intrusive_ptr info, fs::path const& path, file_pool& fp) : m_info(info) , m_files(fp) { - assert(info.begin_files(true) != info.end_files(true)); + assert(info->begin_files(true) != info->end_files(true)); m_save_path = fs::complete(path); assert(m_save_path.is_complete()); } @@ -369,11 +369,9 @@ namespace libtorrent size_type read_impl(char* buf, int slot, int offset, int size, bool fill_zero); ~storage() - { - m_files.release(this); - } + { m_files.release(this); } - torrent_info const& m_info; + boost::intrusive_ptr m_info; fs::path m_save_path; // the file pool is typically stored in // the session, to make all storage @@ -412,8 +410,8 @@ namespace libtorrent { // first, create all missing directories fs::path last_path; - for (torrent_info::file_iterator file_iter = m_info.begin_files(true), - end_iter = m_info.end_files(true); file_iter != end_iter; ++file_iter) + for (torrent_info::file_iterator file_iter = m_info->begin_files(true), + end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter) { fs::path dir = (m_save_path / file_iter->path).branch_path(); @@ -461,7 +459,7 @@ namespace libtorrent void storage::write_resume_data(entry& rd) const { std::vector > file_sizes - = get_filesizes(m_info, m_save_path); + = get_filesizes(*m_info, m_save_path); rd["file sizes"] = entry::list_type(); entry::list_type& fl = rd["file sizes"].list(); @@ -495,7 +493,7 @@ namespace libtorrent } entry::list_type& slots = rd["slots"].list(); - bool seed = int(slots.size()) == m_info.num_pieces() + bool seed = int(slots.size()) == m_info->num_pieces() && std::find_if(slots.begin(), slots.end() , boost::bind(std::less() , boost::bind((size_type const& (entry::*)() const) @@ -510,11 +508,11 @@ namespace libtorrent if (seed) { - if (m_info.num_files(true) != (int)file_sizes.size()) + if (m_info->num_files(true) != (int)file_sizes.size()) { error = "the number of files does not match the torrent (num: " + boost::lexical_cast(file_sizes.size()) + " actual: " - + boost::lexical_cast(m_info.num_files(true)) + ")"; + + boost::lexical_cast(m_info->num_files(true)) + ")"; return false; } @@ -522,8 +520,8 @@ namespace libtorrent fs = file_sizes.begin(); // the resume data says we have the entire torrent // make sure the file sizes are the right ones - for (torrent_info::file_iterator i = m_info.begin_files(true) - , end(m_info.end_files(true)); i != end; ++i, ++fs) + for (torrent_info::file_iterator i = m_info->begin_files(true) + , end(m_info->end_files(true)); i != end; ++i, ++fs) { if (i->size != fs->first) { @@ -536,7 +534,7 @@ namespace libtorrent return true; } - return match_filesizes(m_info, m_save_path, file_sizes + return match_filesizes(*m_info, m_save_path, file_sizes , !full_allocation_mode, &error); } @@ -575,11 +573,11 @@ namespace libtorrent m_files.release(this); #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 - old_path = safe_convert((m_save_path / m_info.name()).string()); - new_path = safe_convert((save_path / m_info.name()).string()); + old_path = safe_convert((m_save_path / m_info->name()).string()); + new_path = safe_convert((save_path / m_info->name()).string()); #else - old_path = m_save_path / m_info.name(); - new_path = save_path / m_info.name(); + old_path = m_save_path / m_info->name(); + new_path = save_path / m_info->name(); #endif try @@ -601,7 +599,7 @@ namespace libtorrent /* void storage::shuffle() { - int num_pieces = m_info.num_pieces(); + int num_pieces = m_info->num_pieces(); std::vector pieces(num_pieces); for (std::vector::iterator i = pieces.begin(); @@ -618,7 +616,7 @@ namespace libtorrent { const int slot_index = targets[i]; const int piece_index = pieces[i]; - const int slot_size =static_cast(m_info.piece_size(slot_index)); + const int slot_size =static_cast(m_info->piece_size(slot_index)); std::vector buf(slot_size); read(&buf[0], piece_index, 0, slot_size); write(&buf[0], slot_index, 0, slot_size); @@ -629,7 +627,7 @@ namespace libtorrent void storage::move_slot(int src_slot, int dst_slot) { - int piece_size = m_info.piece_size(dst_slot); + int piece_size = m_info->piece_size(dst_slot); m_scratch_buffer.resize(piece_size); read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true); write(&m_scratch_buffer[0], dst_slot, 0, piece_size); @@ -638,9 +636,9 @@ namespace libtorrent void storage::swap_slots(int slot1, int slot2) { // the size of the target slot is the size of the piece - int piece_size = m_info.piece_length(); - int piece1_size = m_info.piece_size(slot2); - int piece2_size = m_info.piece_size(slot1); + int piece_size = m_info->piece_length(); + int piece1_size = m_info->piece_size(slot2); + int piece2_size = m_info->piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); @@ -651,10 +649,10 @@ namespace libtorrent void storage::swap_slots3(int slot1, int slot2, int slot3) { // the size of the target slot is the size of the piece - int piece_size = m_info.piece_length(); - int piece1_size = m_info.piece_size(slot2); - int piece2_size = m_info.piece_size(slot3); - int piece3_size = m_info.piece_size(slot1); + int piece_size = m_info->piece_length(); + int piece1_size = m_info->piece_size(slot2); + int piece2_size = m_info->piece_size(slot3); + int piece3_size = m_info->piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); @@ -681,25 +679,25 @@ namespace libtorrent , bool fill_zero) { assert(buf != 0); - assert(slot >= 0 && slot < m_info.num_pieces()); + assert(slot >= 0 && slot < m_info->num_pieces()); assert(offset >= 0); - assert(offset < m_info.piece_size(slot)); + assert(offset < m_info->piece_size(slot)); assert(size > 0); #ifndef NDEBUG std::vector slices - = m_info.map_block(slot, offset, size, true); + = m_info->map_block(slot, offset, size, true); assert(!slices.empty()); #endif - size_type start = slot * (size_type)m_info.piece_length() + offset; - assert(start + size <= m_info.total_size()); + size_type start = slot * (size_type)m_info->piece_length() + offset; + assert(start + size <= m_info->total_size()); // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info.begin_files(true);;) + for (file_iter = m_info->begin_files(true);;) { if (file_offset < file_iter->size) break; @@ -732,7 +730,7 @@ namespace libtorrent #endif int left_to_read = size; - int slot_size = static_cast(m_info.piece_size(slot)); + int slot_size = static_cast(m_info->piece_size(slot)); if (offset + left_to_read > slot_size) left_to_read = slot_size - offset; @@ -757,7 +755,7 @@ namespace libtorrent assert(int(slices.size()) > counter); size_type slice_size = slices[counter].size; assert(slice_size == read_bytes); - assert(m_info.file_at(slices[counter].file_index, true).path + assert(m_info->file_at(slices[counter].file_index, true).path == file_iter->path); #endif @@ -807,30 +805,30 @@ namespace libtorrent { assert(buf != 0); assert(slot >= 0); - assert(slot < m_info.num_pieces()); + assert(slot < m_info->num_pieces()); assert(offset >= 0); assert(size > 0); #ifndef NDEBUG std::vector slices - = m_info.map_block(slot, offset, size, true); + = m_info->map_block(slot, offset, size, true); assert(!slices.empty()); #endif - size_type start = slot * (size_type)m_info.piece_length() + offset; + size_type start = slot * (size_type)m_info->piece_length() + offset; // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info.begin_files(true);;) + for (file_iter = m_info->begin_files(true);;) { if (file_offset < file_iter->size) break; file_offset -= file_iter->size; ++file_iter; - assert(file_iter != m_info.end_files(true)); + assert(file_iter != m_info->end_files(true)); } fs::path p(m_save_path / file_iter->path); @@ -850,7 +848,7 @@ namespace libtorrent } int left_to_write = size; - int slot_size = static_cast(m_info.piece_size(slot)); + int slot_size = static_cast(m_info->piece_size(slot)); if (offset + left_to_write > slot_size) left_to_write = slot_size - offset; @@ -874,7 +872,7 @@ namespace libtorrent { assert(int(slices.size()) > counter); assert(slices[counter].size == write_bytes); - assert(m_info.file_at(slices[counter].file_index, true).path + assert(m_info->file_at(slices[counter].file_index, true).path == file_iter->path); assert(buf_pos >= 0); @@ -902,7 +900,7 @@ namespace libtorrent #endif ++file_iter; - assert(file_iter != m_info.end_files(true)); + assert(file_iter != m_info->end_files(true)); fs::path p = m_save_path / file_iter->path; file_offset = 0; out = m_files.open_file( @@ -913,7 +911,7 @@ namespace libtorrent } } - storage_interface* default_storage_constructor(torrent_info const& ti + storage_interface* default_storage_constructor(boost::intrusive_ptr ti , fs::path const& path, file_pool& fp) { return new storage(ti, path, fp); @@ -1027,7 +1025,7 @@ namespace libtorrent piece_manager::piece_manager( boost::shared_ptr const& torrent - , torrent_info const& ti + , boost::intrusive_ptr ti , fs::path const& save_path , file_pool& fp , disk_io_thread& io @@ -1037,7 +1035,7 @@ namespace libtorrent , m_fill_mode(true) , m_info(ti) , m_save_path(complete(save_path)) - , m_allocating(false) + , m_storage_constructor(sc) , m_io_thread(io) , m_torrent(torrent) { @@ -1140,7 +1138,7 @@ namespace libtorrent int slot = m_piece_to_slot[piece]; assert(slot != has_no_slot); - return m_storage->hash_for_slot(slot, ph, m_info.piece_size(piece)); + return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece)); } void piece_manager::release_files_impl() @@ -1200,7 +1198,7 @@ namespace libtorrent int piece_manager::slot_for_piece(int piece_index) const { - assert(piece_index >= 0 && piece_index < m_info.num_pieces()); + assert(piece_index >= 0 && piece_index < m_info->num_pieces()); return m_piece_to_slot[piece_index]; } @@ -1211,13 +1209,13 @@ namespace libtorrent try { assert(slot_index >= 0); - assert(slot_index < m_info.num_pieces()); + assert(slot_index < m_info->num_pieces()); assert(block_size > 0); adler32_crc crc; std::vector buf(block_size); - int num_blocks = static_cast(m_info.piece_size(slot_index)) / block_size; - int last_block_size = static_cast(m_info.piece_size(slot_index)) % block_size; + int num_blocks = static_cast(m_info->piece_size(slot_index)) / block_size; + int last_block_size = static_cast(m_info->piece_size(slot_index)) % block_size; if (last_block_size == 0) last_block_size = block_size; for (int i = 0; i < num_blocks-1; ++i) @@ -1310,11 +1308,11 @@ namespace libtorrent { // INVARIANT_CHECK; - assert((int)have_pieces.size() == m_info.num_pieces()); + assert((int)have_pieces.size() == m_info->num_pieces()); - const int piece_size = static_cast(m_info.piece_length()); - const int last_piece_size = static_cast(m_info.piece_size( - m_info.num_pieces() - 1)); + const int piece_size = static_cast(m_info->piece_length()); + const int last_piece_size = static_cast(m_info->piece_size( + m_info->num_pieces() - 1)); assert((int)piece_data.size() >= last_piece_size); @@ -1470,7 +1468,7 @@ namespace libtorrent INVARIANT_CHECK; - assert(m_info.piece_length() > 0); + assert(m_info->piece_length() > 0); m_compact_mode = compact_mode; @@ -1480,13 +1478,13 @@ namespace libtorrent // by check_pieces. // m_storage->shuffle(); - m_piece_to_slot.resize(m_info.num_pieces(), has_no_slot); - m_slot_to_piece.resize(m_info.num_pieces(), unallocated); + m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot); + m_slot_to_piece.resize(m_info->num_pieces(), unallocated); m_free_slots.clear(); m_unallocated_slots.clear(); pieces.clear(); - pieces.resize(m_info.num_pieces(), false); + pieces.resize(m_info->num_pieces(), false); num_pieces = 0; // if we have fast-resume info @@ -1591,7 +1589,7 @@ namespace libtorrent return std::make_pair(false, 1.f); } - if (int(m_unallocated_slots.size()) == m_info.num_pieces() + if (int(m_unallocated_slots.size()) == m_info->num_pieces() && !m_fill_mode) { // if there is not a single file on disk, just @@ -1633,8 +1631,8 @@ namespace libtorrent assert(!m_fill_mode); std::vector().swap(m_unallocated_slots); std::fill(m_slot_to_piece.begin(), m_slot_to_piece.end(), int(unassigned)); - m_free_slots.resize(m_info.num_pieces()); - for (int i = 0; i < m_info.num_pieces(); ++i) + m_free_slots.resize(m_info->num_pieces()); + for (int i = 0; i < m_info->num_pieces(); ++i) m_free_slots[i] = i; } @@ -1654,15 +1652,15 @@ namespace libtorrent if (m_hash_to_piece.empty()) { m_current_slot = 0; - for (int i = 0; i < m_info.num_pieces(); ++i) + for (int i = 0; i < m_info->num_pieces(); ++i) { - m_hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i)); + m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i)); } std::fill(pieces.begin(), pieces.end(), false); } - m_piece_data.resize(int(m_info.piece_length())); - int piece_size = int(m_info.piece_size(m_current_slot)); + m_piece_data.resize(int(m_info->piece_length())); + int piece_size = int(m_info->piece_size(m_current_slot)); int num_read = m_storage->read(&m_piece_data[0] , m_current_slot, 0, piece_size); @@ -1865,9 +1863,9 @@ namespace libtorrent { // find the file that failed, and skip all the blocks in that file size_type file_offset = 0; - size_type current_offset = m_current_slot * m_info.piece_length(); - for (torrent_info::file_iterator i = m_info.begin_files(true); - i != m_info.end_files(true); ++i) + size_type current_offset = m_current_slot * m_info->piece_length(); + for (torrent_info::file_iterator i = m_info->begin_files(true); + i != m_info->end_files(true); ++i) { file_offset += i->size; if (file_offset > current_offset) break; @@ -1875,8 +1873,8 @@ namespace libtorrent assert(file_offset > current_offset); int skip_blocks = static_cast( - (file_offset - current_offset + m_info.piece_length() - 1) - / m_info.piece_length()); + (file_offset - current_offset + m_info->piece_length() - 1) + / m_info->piece_length()); for (int i = m_current_slot; i < m_current_slot + skip_blocks; ++i) { @@ -1889,9 +1887,9 @@ namespace libtorrent } ++m_current_slot; - if (m_current_slot >= m_info.num_pieces()) + if (m_current_slot >= m_info->num_pieces()) { - assert(m_current_slot == m_info.num_pieces()); + assert(m_current_slot == m_info->num_pieces()); // clear the memory we've been using std::vector().swap(m_piece_data); @@ -1903,7 +1901,7 @@ namespace libtorrent assert(num_pieces == std::count(pieces.begin(), pieces.end(), true)); - return std::make_pair(false, (float)m_current_slot / m_info.num_pieces()); + return std::make_pair(false, (float)m_current_slot / m_info->num_pieces()); } int piece_manager::allocate_slot_for_piece(int piece_index) @@ -1945,7 +1943,7 @@ namespace libtorrent // special case to make sure we don't use the last slot // when we shouldn't, since it's smaller than ordinary slots - if (*iter == m_info.num_pieces() - 1 && piece_index != *iter) + if (*iter == m_info->num_pieces() - 1 && piece_index != *iter) { if (m_free_slots.size() == 1) allocate_slots(1); @@ -2050,7 +2048,7 @@ namespace libtorrent } else if (m_fill_mode) { - int piece_size = int(m_info.piece_size(pos)); + int piece_size = int(m_info->piece_size(pos)); int offset = 0; for (; piece_size > 0; piece_size -= stack_buffer_size , offset += stack_buffer_size) @@ -2076,8 +2074,8 @@ namespace libtorrent boost::recursive_mutex::scoped_lock lock(m_mutex); if (m_piece_to_slot.empty()) return; - assert((int)m_piece_to_slot.size() == m_info.num_pieces()); - assert((int)m_slot_to_piece.size() == m_info.num_pieces()); + assert((int)m_piece_to_slot.size() == m_info->num_pieces()); + assert((int)m_slot_to_piece.size() == m_info->num_pieces()); for (std::vector::const_iterator i = m_free_slots.begin(); i != m_free_slots.end(); ++i) @@ -2099,7 +2097,7 @@ namespace libtorrent == m_unallocated_slots.end()); } - for (int i = 0; i < m_info.num_pieces(); ++i) + for (int i = 0; i < m_info->num_pieces(); ++i) { // Check domain of piece_to_slot's elements if (m_piece_to_slot[i] != has_no_slot) @@ -2187,7 +2185,7 @@ namespace libtorrent s << "index\tslot\tpiece\n"; - for (int i = 0; i < m_info.num_pieces(); ++i) + for (int i = 0; i < m_info->num_pieces(); ++i) { s << i << "\t" << m_slot_to_piece[i] << "\t"; s << m_piece_to_slot[i] << "\n"; diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 9cd2c277c..1a3083b7d 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -150,7 +150,7 @@ namespace libtorrent torrent::torrent( session_impl& ses , aux::checker_impl& checker - , torrent_info const& tf + , boost::intrusive_ptr tf , fs::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode @@ -181,7 +181,7 @@ namespace libtorrent , m_ses(ses) , m_checker(checker) , m_picker(0) - , m_trackers(m_torrent_file.trackers()) + , m_trackers(m_torrent_file->trackers()) , m_last_working_tracker(-1) , m_currently_trying_tracker(0) , m_failed_trackers(0) @@ -221,7 +221,7 @@ namespace libtorrent , int block_size , storage_constructor_type sc , bool paused) - : m_torrent_file(info_hash) + : m_torrent_file(new torrent_info(info_hash)) , m_abort(false) , m_paused(paused) , m_just_paused(false) @@ -277,7 +277,7 @@ namespace libtorrent if (tracker_url) { m_trackers.push_back(announce_entry(tracker_url)); - m_torrent_file.add_tracker(tracker_url); + m_torrent_file->add_tracker(tracker_url); } m_policy.reset(new policy(this)); @@ -286,7 +286,7 @@ namespace libtorrent void torrent::start() { boost::weak_ptr self(shared_from_this()); - if (m_torrent_file.is_valid()) init(); + if (m_torrent_file->is_valid()) init(); m_announce_timer.expires_from_now(seconds(1)); m_announce_timer.async_wait(m_ses.m_strand.wrap( bind(&torrent::on_announce_disp, self, _1))); @@ -296,7 +296,7 @@ namespace libtorrent bool torrent::should_announce_dht() const { // don't announce private torrents - if (m_torrent_file.is_valid() && m_torrent_file.priv()) return false; + if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false; if (m_trackers.empty()) return true; @@ -334,7 +334,7 @@ namespace libtorrent std::string torrent::name() const { - if (valid_metadata()) return m_torrent_file.name(); + if (valid_metadata()) return m_torrent_file->name(); if (m_name) return *m_name; return ""; } @@ -350,22 +350,22 @@ namespace libtorrent // shared_from_this() void torrent::init() { - assert(m_torrent_file.is_valid()); - assert(m_torrent_file.num_files() > 0); - assert(m_torrent_file.total_size() >= 0); + assert(m_torrent_file->is_valid()); + assert(m_torrent_file->num_files() > 0); + assert(m_torrent_file->total_size() >= 0); - m_have_pieces.resize(m_torrent_file.num_pieces(), false); + m_have_pieces.resize(m_torrent_file->num_pieces(), false); // the shared_from_this() will create an intentional // cycle of ownership, se the hpp file for description. m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor); m_storage = m_owning_storage.get(); - m_block_size = calculate_block_size(m_torrent_file, m_default_block_size); + m_block_size = calculate_block_size(*m_torrent_file, m_default_block_size); m_picker.reset(new piece_picker( - static_cast(m_torrent_file.piece_length() / m_block_size) - , static_cast((m_torrent_file.total_size()+m_block_size-1)/m_block_size))); + static_cast(m_torrent_file->piece_length() / m_block_size) + , static_cast((m_torrent_file->total_size()+m_block_size-1)/m_block_size))); - std::vector const& url_seeds = m_torrent_file.url_seeds(); + std::vector const& url_seeds = m_torrent_file->url_seeds(); std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds , m_web_seeds.begin())); } @@ -393,7 +393,7 @@ namespace libtorrent { boost::weak_ptr self(shared_from_this()); - if (!m_torrent_file.priv()) + if (!m_torrent_file->priv()) { // announce on local network every 5 minutes m_announce_timer.expires_from_now(minutes(5)); @@ -401,7 +401,7 @@ namespace libtorrent bind(&torrent::on_announce_disp, self, _1))); // announce with the local discovery service - m_ses.announce_lsd(m_torrent_file.info_hash()); + m_ses.announce_lsd(m_torrent_file->info_hash()); } else { @@ -419,7 +419,7 @@ namespace libtorrent // TODO: There should be a way to abort an announce operation on the dht. // when the torrent is destructed assert(m_ses.m_external_listen_port > 0); - m_ses.m_dht->announce(m_torrent_file.info_hash() + m_ses.m_dht->announce(m_torrent_file->info_hash() , m_ses.m_external_listen_port , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1))); } @@ -465,7 +465,7 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_torrent_file.trackers().empty()) return false; + if (m_torrent_file->trackers().empty()) return false; if (m_just_paused) { @@ -615,7 +615,7 @@ namespace libtorrent // if we don't have the metadata yet, we // cannot tell how big the torrent is. if (!valid_metadata()) return -1; - return m_torrent_file.total_size() + return m_torrent_file->total_size() - quantized_bytes_done(); } @@ -625,23 +625,23 @@ namespace libtorrent if (!valid_metadata()) return 0; - if (m_torrent_file.num_pieces() == 0) + if (m_torrent_file->num_pieces() == 0) return 0; - if (is_seed()) return m_torrent_file.total_size(); + if (is_seed()) return m_torrent_file->total_size(); - const int last_piece = m_torrent_file.num_pieces() - 1; + const int last_piece = m_torrent_file->num_pieces() - 1; size_type total_done - = m_num_pieces * m_torrent_file.piece_length(); + = m_num_pieces * m_torrent_file->piece_length(); // if we have the last piece, we have to correct // the amount we have, since the first calculation // assumed all pieces were of equal size if (m_have_pieces[last_piece]) { - int corr = m_torrent_file.piece_size(last_piece) - - m_torrent_file.piece_length(); + int corr = m_torrent_file->piece_size(last_piece) + - m_torrent_file->piece_length(); total_done += corr; } return total_done; @@ -654,42 +654,42 @@ namespace libtorrent { INVARIANT_CHECK; - if (!valid_metadata() || m_torrent_file.num_pieces() == 0) + if (!valid_metadata() || m_torrent_file->num_pieces() == 0) return tuple(0,0); - const int last_piece = m_torrent_file.num_pieces() - 1; + const int last_piece = m_torrent_file->num_pieces() - 1; if (is_seed()) - return make_tuple(m_torrent_file.total_size() - , m_torrent_file.total_size()); + return make_tuple(m_torrent_file->total_size() + , m_torrent_file->total_size()); size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered()) - * m_torrent_file.piece_length(); + * m_torrent_file->piece_length(); size_type total_done - = m_num_pieces * m_torrent_file.piece_length(); - assert(m_num_pieces < m_torrent_file.num_pieces()); + = m_num_pieces * m_torrent_file->piece_length(); + assert(m_num_pieces < m_torrent_file->num_pieces()); // if we have the last piece, we have to correct // the amount we have, since the first calculation // assumed all pieces were of equal size if (m_have_pieces[last_piece]) { - int corr = m_torrent_file.piece_size(last_piece) - - m_torrent_file.piece_length(); + int corr = m_torrent_file->piece_size(last_piece) + - m_torrent_file->piece_length(); total_done += corr; if (m_picker->piece_priority(last_piece) != 0) wanted_done += corr; } - assert(total_done <= m_torrent_file.total_size()); - assert(wanted_done <= m_torrent_file.total_size()); + assert(total_done <= m_torrent_file->total_size()); + assert(wanted_done <= m_torrent_file->total_size()); const std::vector& dl_queue = m_picker->get_download_queue(); const int blocks_per_piece = static_cast( - m_torrent_file.piece_length() / m_block_size); + m_torrent_file->piece_length() / m_block_size); for (std::vector::const_iterator i = dl_queue.begin(); i != dl_queue.end(); ++i) @@ -722,15 +722,15 @@ namespace libtorrent == piece_picker::block_info::state_finished) { corr -= m_block_size; - corr += m_torrent_file.piece_size(last_piece) % m_block_size; + corr += m_torrent_file->piece_size(last_piece) % m_block_size; } total_done += corr; if (m_picker->piece_priority(index) != 0) wanted_done += corr; } - assert(total_done <= m_torrent_file.total_size()); - assert(wanted_done <= m_torrent_file.total_size()); + assert(total_done <= m_torrent_file->total_size()); + assert(wanted_done <= m_torrent_file->total_size()); std::map downloading_piece; for (const_peer_iterator i = begin(); i != end(); ++i) @@ -760,10 +760,10 @@ namespace libtorrent } #ifndef NDEBUG assert(p->bytes_downloaded <= p->full_block_bytes); - int last_piece = m_torrent_file.num_pieces() - 1; + int last_piece = m_torrent_file->num_pieces() - 1; if (p->piece_index == last_piece - && p->block_index == m_torrent_file.piece_size(last_piece) / block_size()) - assert(p->full_block_bytes == m_torrent_file.piece_size(last_piece) % block_size()); + && p->block_index == m_torrent_file->piece_size(last_piece) / block_size()) + assert(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size()); else assert(p->full_block_bytes == block_size()); #endif @@ -779,7 +779,7 @@ namespace libtorrent #ifndef NDEBUG - if (total_done >= m_torrent_file.total_size()) + if (total_done >= m_torrent_file->total_size()) { std::copy(m_have_pieces.begin(), m_have_pieces.end() , std::ostream_iterator(std::cerr, " ")); @@ -810,8 +810,8 @@ namespace libtorrent } - assert(total_done <= m_torrent_file.total_size()); - assert(wanted_done <= m_torrent_file.total_size()); + assert(total_done <= m_torrent_file->total_size()); + assert(wanted_done <= m_torrent_file->total_size()); #endif @@ -908,14 +908,14 @@ namespace libtorrent // think that it has received all of it until this function // resets the download queue. So, we cannot do the // invariant check here since it assumes: - // (total_done == m_torrent_file.total_size()) => is_seed() + // (total_done == m_torrent_file->total_size()) => is_seed() // INVARIANT_CHECK; assert(m_storage); assert(m_storage->refcount() > 0); assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file.num_pieces()); + assert(index < m_torrent_file->num_pieces()); if (m_ses.m_alerts.should_post(alert::info)) { @@ -924,7 +924,7 @@ namespace libtorrent m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index, s.str())); } // increase the total amount of failed bytes - m_total_failed_bytes += m_torrent_file.piece_size(index); + m_total_failed_bytes += m_torrent_file->piece_size(index); std::vector downloaders; m_picker->get_downloaders(downloaders, index); @@ -1047,7 +1047,7 @@ namespace libtorrent // INVARIANT_CHECK; assert(index >= 0); - assert(index < m_torrent_file.num_pieces()); + assert(index < m_torrent_file->num_pieces()); std::vector downloaders; m_picker->get_downloaders(downloaders, index); @@ -1090,7 +1090,7 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file.seed_free(); + m_torrent_file->seed_free(); } } @@ -1124,7 +1124,7 @@ namespace libtorrent // this call is only valid on torrents with metadata assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file.num_pieces()); + assert(index < m_torrent_file->num_pieces()); bool filter_updated = m_picker->set_piece_priority(index, priority); if (filter_updated) update_peer_interest(); @@ -1140,7 +1140,7 @@ namespace libtorrent // this call is only valid on torrents with metadata assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file.num_pieces()); + assert(index < m_torrent_file->num_pieces()); return m_picker->piece_priority(index); } @@ -1176,7 +1176,7 @@ namespace libtorrent if (is_seed()) { pieces.clear(); - pieces.resize(m_torrent_file.num_pieces(), 1); + pieces.resize(m_torrent_file->num_pieces(), 1); return; } @@ -1201,20 +1201,20 @@ namespace libtorrent // the bitmask need to have exactly one bit for every file // in the torrent - assert(int(files.size()) == m_torrent_file.num_files()); + assert(int(files.size()) == m_torrent_file->num_files()); size_type position = 0; - if (m_torrent_file.num_pieces() == 0) return; + if (m_torrent_file->num_pieces() == 0) return; - int piece_length = m_torrent_file.piece_length(); + int piece_length = m_torrent_file->piece_length(); // initialize the piece priorities to 0, then only allow // setting higher priorities - std::vector pieces(m_torrent_file.num_pieces(), 0); + std::vector pieces(m_torrent_file->num_pieces(), 0); for (int i = 0; i < int(files.size()); ++i) { size_type start = position; - size_type size = m_torrent_file.file_at(i).size; + size_type size = m_torrent_file->file_at(i).size; if (size == 0) continue; position += size; // mark all pieces of the file with this file's priority @@ -1250,7 +1250,7 @@ namespace libtorrent // this call is only valid on torrents with metadata assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file.num_pieces()); + assert(index < m_torrent_file->num_pieces()); m_picker->set_piece_priority(index, filter ? 1 : 0); update_peer_interest(); @@ -1287,7 +1287,7 @@ namespace libtorrent assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file.num_pieces()); + assert(index < m_torrent_file->num_pieces()); return m_picker->piece_priority(index) == 0; } @@ -1301,7 +1301,7 @@ namespace libtorrent if (is_seed()) { bitmask.clear(); - bitmask.resize(m_torrent_file.num_pieces(), false); + bitmask.resize(m_torrent_file->num_pieces(), false); return; } @@ -1318,20 +1318,20 @@ namespace libtorrent // the bitmask need to have exactly one bit for every file // in the torrent - assert((int)bitmask.size() == m_torrent_file.num_files()); + assert((int)bitmask.size() == m_torrent_file->num_files()); size_type position = 0; - if (m_torrent_file.num_pieces()) + if (m_torrent_file->num_pieces()) { - int piece_length = m_torrent_file.piece_length(); + int piece_length = m_torrent_file->piece_length(); // mark all pieces as filtered, then clear the bits for files // that should be downloaded - std::vector piece_filter(m_torrent_file.num_pieces(), true); + std::vector piece_filter(m_torrent_file->num_pieces(), true); for (int i = 0; i < (int)bitmask.size(); ++i) { size_type start = position; - position += m_torrent_file.file_at(i).size; + position += m_torrent_file->file_at(i).size; // is the file selected for download? if (!bitmask[i]) { @@ -1366,7 +1366,7 @@ namespace libtorrent m_next_request = time_now() + seconds(tracker_retry_delay_max); tracker_request req; - req.info_hash = m_torrent_file.info_hash(); + req.info_hash = m_torrent_file->info_hash(); req.pid = m_ses.get_peer_id(); req.downloaded = m_stat.total_payload_download(); req.uploaded = m_stat.total_payload_upload(); @@ -1890,8 +1890,8 @@ namespace libtorrent { INVARIANT_CHECK; - assert(!m_torrent_file.is_valid()); - m_torrent_file.parse_info_section(metadata); + assert(!m_torrent_file->is_valid()); + m_torrent_file->parse_info_section(metadata); init(); @@ -1901,12 +1901,12 @@ namespace libtorrent new aux::piece_checker_data); d->torrent_ptr = shared_from_this(); d->save_path = m_save_path; - d->info_hash = m_torrent_file.info_hash(); + d->info_hash = m_torrent_file->info_hash(); // add the torrent to the queue to be checked m_checker.m_torrents.push_back(d); typedef session_impl::torrent_map torrent_map; torrent_map::iterator i = m_ses.m_torrents.find( - m_torrent_file.info_hash()); + m_torrent_file->info_hash()); assert(i != m_ses.m_torrents.end()); m_ses.m_torrents.erase(i); // and notify the thread that it got another @@ -2291,7 +2291,7 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file.seed_free(); + m_torrent_file->seed_free(); } if (!m_connections_initialized) @@ -2374,7 +2374,7 @@ namespace libtorrent torrent_handle torrent::get_handle() const { - return torrent_handle(&m_ses, &m_checker, m_torrent_file.info_hash()); + return torrent_handle(&m_ses, &m_checker, m_torrent_file->info_hash()); } session_settings const& torrent::settings() const @@ -2417,7 +2417,7 @@ namespace libtorrent if (valid_metadata()) { - assert(m_abort || int(m_have_pieces.size()) == m_torrent_file.num_pieces()); + assert(m_abort || int(m_have_pieces.size()) == m_torrent_file->num_pieces()); } else { @@ -2425,12 +2425,12 @@ namespace libtorrent } size_type total_done = quantized_bytes_done(); - if (m_torrent_file.is_valid()) + if (m_torrent_file->is_valid()) { if (is_seed()) - assert(total_done == m_torrent_file.total_size()); + assert(total_done == m_torrent_file->total_size()); else - assert(total_done != m_torrent_file.total_size()); + assert(total_done != m_torrent_file->total_size()); } else { @@ -2441,7 +2441,7 @@ namespace libtorrent assert(m_num_pieces == std::count(m_have_pieces.begin(), m_have_pieces.end(), true)); assert(!valid_metadata() || m_block_size > 0); - assert(!valid_metadata() || (m_torrent_file.piece_length() % m_block_size) == 0); + assert(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0); // if (is_seed()) assert(m_picker.get() == 0); } #endif @@ -2678,7 +2678,7 @@ namespace libtorrent assert(m_storage); assert(m_storage->refcount() > 0); assert(piece_index >= 0); - assert(piece_index < m_torrent_file.num_pieces()); + assert(piece_index < m_torrent_file->num_pieces()); assert(piece_index < (int)m_have_pieces.size()); m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified @@ -2690,7 +2690,7 @@ namespace libtorrent { sha1_hash h(j.str); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); - f(m_torrent_file.hash_for_piece(j.piece) == h); + f(m_torrent_file->hash_for_piece(j.piece) == h); } const tcp::endpoint& torrent::current_tracker() const @@ -2706,12 +2706,12 @@ namespace libtorrent assert(valid_metadata()); fp.clear(); - fp.resize(m_torrent_file.num_files(), 0.f); + fp.resize(m_torrent_file->num_files(), 0.f); - for (int i = 0; i < m_torrent_file.num_files(); ++i) + for (int i = 0; i < m_torrent_file->num_files(); ++i) { - peer_request ret = m_torrent_file.map_file(i, 0, 0); - size_type size = m_torrent_file.file_at(i).size; + peer_request ret = m_torrent_file->map_file(i, 0, 0); + size_type size = m_torrent_file->file_at(i).size; // zero sized files are considered // 100% done all the time @@ -2724,7 +2724,7 @@ namespace libtorrent size_type done = 0; while (size > 0) { - size_type bytes_step = (std::min)(m_torrent_file.piece_size(ret.piece) + size_type bytes_step = (std::min)(m_torrent_file->piece_size(ret.piece) - ret.start, size); if (m_have_pieces[ret.piece]) done += bytes_step; ++ret.piece; @@ -2733,7 +2733,7 @@ namespace libtorrent } assert(size == 0); - fp[i] = static_cast(done) / m_torrent_file.file_at(i).size; + fp[i] = static_cast(done) / m_torrent_file->file_at(i).size; } } @@ -2820,21 +2820,21 @@ namespace libtorrent // fill in status that depends on metadata - st.total_wanted = m_torrent_file.total_size(); + st.total_wanted = m_torrent_file->total_size(); if (m_picker.get() && (m_picker->num_filtered() > 0 || m_picker->num_have_filtered() > 0)) { int filtered_pieces = m_picker->num_filtered() + m_picker->num_have_filtered(); - int last_piece_index = m_torrent_file.num_pieces() - 1; + int last_piece_index = m_torrent_file->num_pieces() - 1; if (m_picker->piece_priority(last_piece_index) == 0) { - st.total_wanted -= m_torrent_file.piece_size(last_piece_index); + st.total_wanted -= m_torrent_file->piece_size(last_piece_index); --filtered_pieces; } - st.total_wanted -= filtered_pieces * m_torrent_file.piece_length(); + st.total_wanted -= filtered_pieces * m_torrent_file->piece_length(); } assert(st.total_wanted >= st.total_wanted_done); @@ -2852,7 +2852,7 @@ namespace libtorrent } else if (is_seed()) { - assert(st.total_done == m_torrent_file.total_size()); + assert(st.total_done == m_torrent_file->total_size()); st.state = torrent_status::seeding; } else if (st.total_wanted_done == st.total_wanted) diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index aefff41b1..e16c136bb 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -323,7 +323,13 @@ try #endif { using namespace libtorrent::detail; - if (e) return; + if (e) + { +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() << " *** on_reply aborted: " << e.message() << std::endl; +#endif + return; + } // parse out the url for the device @@ -843,9 +849,16 @@ void upnp::on_upnp_map_response(asio::error_code const& e { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() - << " <== error while adding portmap: " << p.message() << std::endl; + << " <== error while adding portmap: " << p.status_code() << " " << p.message() << std::endl; #endif - m_devices.erase(d); + for (int i = 0; i < num_mappings; ++i) + { + if (d.mapping[i].need_update) + { + map_port(d, i); + return; + } + } return; } diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index cddb35e42..df7a8a685 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -69,9 +69,6 @@ namespace libtorrent { INVARIANT_CHECK; - // we always prefer downloading entire - // pieces from web seeds - prefer_whole_pieces(true); // we want large blocks as well, so // we can request more bytes at once request_large_blocks(true); @@ -80,6 +77,10 @@ namespace libtorrent shared_ptr tor = t.lock(); assert(tor); int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size(); + + // we always prefer downloading 1 MB chunks + // from web seeds + prefer_whole_pieces((1024 * 1024) / tor->torrent_file().piece_length()); // multiply with the blocks per piece since that many requests are // merged into one http request @@ -178,13 +179,16 @@ namespace libtorrent int size = r.length; const int block_size = t->block_size(); + const int piece_size = t->torrent_file().piece_length(); + peer_request pr; while (size > 0) { - int request_size = (std::min)(block_size, size); - peer_request pr = {r.piece, r.start + r.length - size - , request_size}; + int request_offset = r.start + r.length - size; + pr.start = request_offset % piece_size; + pr.length = (std::min)(block_size, size); + pr.piece = r.piece + request_offset / piece_size; m_requests.push_back(pr); - size -= request_size; + size -= pr.length; } proxy_settings const& ps = m_ses.web_seed_proxy(); @@ -477,8 +481,11 @@ namespace libtorrent peer_request front_request = m_requests.front(); - if (in_range.piece != front_request.piece - || in_range.start > front_request.start + int(m_piece.size())) + size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start; + size_type re = rs + in_range.length; + size_type fs = size_type(front_request.piece) * info.piece_length() + front_request.start; + size_type fe = fs + front_request.length; + if (fs < rs || fe > re) { throw std::runtime_error("invalid range in HTTP response"); }