From a9961adda782f4defb88531bf9fb9c9f08c3c0ca Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Fri, 21 Sep 2007 00:05:59 +0000 Subject: [PATCH] finish sync --- libtorrent/include/libtorrent/assert.hpp | 6 +- .../include/libtorrent/aux_/session_impl.hpp | 10 +- .../include/libtorrent/bandwidth_manager.hpp | 25 +- .../include/libtorrent/broadcast_socket.hpp | 6 +- libtorrent/include/libtorrent/config.hpp | 1 - .../include/libtorrent/disk_io_thread.hpp | 15 + libtorrent/include/libtorrent/extensions.hpp | 6 + .../extensions/metadata_transfer.hpp | 2 +- .../include/libtorrent/extensions/ut_pex.hpp | 2 +- .../libtorrent/http_tracker_connection.hpp | 1 - .../include/libtorrent/intrusive_ptr_base.hpp | 2 +- libtorrent/include/libtorrent/peer_info.hpp | 3 +- .../include/libtorrent/piece_picker.hpp | 2 +- libtorrent/include/libtorrent/session.hpp | 8 +- .../include/libtorrent/session_impl.hpp | 594 ++++++++++++++++++ libtorrent/include/libtorrent/storage.hpp | 6 +- .../include/libtorrent/torrent_handle.hpp | 1 + .../include/libtorrent/tracker_manager.hpp | 3 +- libtorrent/src/Makefile.am | 3 +- libtorrent/src/assert.cpp | 10 +- libtorrent/src/broadcast_socket.cpp | 84 ++- libtorrent/src/bt_peer_connection.cpp | 16 +- libtorrent/src/disk_io_thread.cpp | 53 +- libtorrent/src/enum_net.cpp | 13 +- libtorrent/src/file.cpp | 19 +- libtorrent/src/http_tracker_connection.cpp | 1 - libtorrent/src/metadata_transfer.cpp | 2 +- libtorrent/src/peer_connection.cpp | 34 +- libtorrent/src/piece_picker.cpp | 87 ++- libtorrent/src/policy.cpp | 44 +- libtorrent/src/session.cpp | 14 +- libtorrent/src/session_impl.cpp | 12 +- libtorrent/src/storage.cpp | 24 +- libtorrent/src/torrent.cpp | 16 +- libtorrent/src/torrent_handle.cpp | 239 +++++-- libtorrent/src/tracker_manager.cpp | 16 +- libtorrent/src/udp_tracker_connection.cpp | 38 +- libtorrent/src/upnp.cpp | 1 - libtorrent/src/ut_pex.cpp | 71 ++- 39 files changed, 1277 insertions(+), 213 deletions(-) create mode 100644 libtorrent/include/libtorrent/session_impl.hpp diff --git a/libtorrent/include/libtorrent/assert.hpp b/libtorrent/include/libtorrent/assert.hpp index 62425809e..6577acc46 100644 --- a/libtorrent/include/libtorrent/assert.hpp +++ b/libtorrent/include/libtorrent/assert.hpp @@ -33,12 +33,14 @@ POSSIBILITY OF SUCH DAMAGE. #include #ifndef NDEBUG -#if defined __linux__ && defined __GNUC__ +#if (defined __linux__ || defined __MACH__) && defined __GNUC__ #ifdef assert #undef assert #endif -void assert_fail(const char* expr, int line, char const* file, char const* function); +#include "libtorrent/config.hpp" + +TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, char const* function); #define assert(x) if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__) diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index 0389bf3dc..9300a1ce3 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -185,7 +185,7 @@ namespace libtorrent ~session_impl(); #ifndef TORRENT_DISABLE_EXTENSIONS - void add_extension(boost::function(torrent*)> ext); + void add_extension(boost::function(torrent*, void*)> ext); #endif void operator()(); @@ -246,7 +246,8 @@ namespace libtorrent , entry const& resume_data , bool compact_mode , storage_constructor_type sc - , bool paused); + , bool paused + , void* userdata); torrent_handle add_torrent( char const* tracker_url @@ -256,7 +257,8 @@ namespace libtorrent , entry const& resume_data , bool compact_mode , storage_constructor_type sc - , bool paused); + , bool paused + , void* userdata); void remove_torrent(torrent_handle const& h); @@ -519,7 +521,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_EXTENSIONS typedef std::list(torrent*)> > extension_list_t; + torrent_plugin>(torrent*, void*)> > extension_list_t; extension_list_t m_extensions; #endif diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index 03d4f65ae..38aa67f43 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -180,6 +180,7 @@ struct bandwidth_manager , m_limit(bandwidth_limit::inf) , m_current_quota(0) , m_channel(channel) + , m_in_hand_out_bandwidth(false) {} void throttle(int limit) throw() @@ -328,6 +329,10 @@ private: void hand_out_bandwidth() throw() { + // if we're already handing out bandwidth, just return back + // to the loop further down on the callstack + if (m_in_hand_out_bandwidth) return; + m_in_hand_out_bandwidth = true; #ifndef NDEBUG try { #endif @@ -361,6 +366,7 @@ private: if (qe.peer->is_disconnecting()) { t->expire_bandwidth(m_channel, qe.max_block_size); + assert(amount == limit - m_current_quota); continue; } @@ -374,6 +380,7 @@ private: if (max_assignable == 0) { t->expire_bandwidth(m_channel, qe.max_block_size); + assert(amount == limit - m_current_quota); continue; } @@ -388,15 +395,15 @@ private: // the history window is one second, and the block will be forgotten // after one second. int block_size = (std::min)(qe.peer->bandwidth_throttle(m_channel) - , m_limit / 10); + , limit / 10); if (block_size < min_bandwidth_block_size) { - block_size = (std::min)(int(min_bandwidth_block_size), m_limit); + block_size = (std::min)(int(min_bandwidth_block_size), limit); } else if (block_size > max_bandwidth_block_size) { - if (m_limit == bandwidth_limit::inf) + if (limit == bandwidth_limit::inf) { block_size = max_bandwidth_block_size; } @@ -407,8 +414,8 @@ private: // as possible // TODO: move this calculcation to where the limit // is changed - block_size = m_limit - / (m_limit / max_bandwidth_block_size); + block_size = limit + / (limit / max_bandwidth_block_size); } } if (block_size > qe.max_block_size) block_size = qe.max_block_size; @@ -428,18 +435,21 @@ private: int hand_out_amount = (std::min)((std::min)(block_size, max_assignable) , amount); assert(hand_out_amount > 0); + assert(amount == limit - m_current_quota); amount -= hand_out_amount; assert(hand_out_amount <= qe.max_block_size); t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size); qe.peer->assign_bandwidth(m_channel, hand_out_amount); add_history_entry(history_entry( qe.peer, t, hand_out_amount, now + bw_window_size)); + assert(amount == limit - m_current_quota); } #ifndef NDEBUG } catch (std::exception& e) { assert(false); }; #endif + m_in_hand_out_bandwidth = false; } @@ -472,6 +482,11 @@ private: // this is the channel within the consumers // that bandwidth is assigned to (upload or download) int m_channel; + + // this is true while we're in the hand_out_bandwidth loop + // to prevent recursive invocations to interfere + bool m_in_hand_out_bandwidth; + }; } diff --git a/libtorrent/include/libtorrent/broadcast_socket.hpp b/libtorrent/include/libtorrent/broadcast_socket.hpp index bdfe30b6e..23be67b0d 100644 --- a/libtorrent/include/libtorrent/broadcast_socket.hpp +++ b/libtorrent/include/libtorrent/broadcast_socket.hpp @@ -42,6 +42,9 @@ namespace libtorrent { bool is_local(address const& a); + bool is_loopback(address const& addr); + bool is_multicast(address const& addr); + address_v4 guess_local_address(asio::io_service&); typedef boost::function -#include "libtorrent/assert.hpp" #if defined(__GNUC__) && __GNUC__ >= 4 diff --git a/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp index 16ee0bca4..61ca9bc53 100644 --- a/libtorrent/include/libtorrent/disk_io_thread.hpp +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -30,6 +30,10 @@ POSSIBILITY OF SUCH DAMAGE. */ +#ifdef TORRENT_DISK_STATS +#include +#endif + #include "libtorrent/storage.hpp" #include #include @@ -50,6 +54,7 @@ namespace libtorrent , buffer_size(0) , piece(0) , offset(0) + , priority(0) {} enum action_t @@ -72,6 +77,12 @@ namespace libtorrent // to the error message std::string str; + // priority decides whether or not this + // job will skip entries in the queue or + // not. It always skips in front of entries + // with lower priority + int priority; + // this is called when operation completes boost::function callback; }; @@ -115,6 +126,10 @@ namespace libtorrent int m_block_size; #endif +#ifdef TORRENT_DISK_STATS + std::ofstream m_log; +#endif + // thread for performing blocking disk io operations boost::thread m_disk_io_thread; }; diff --git a/libtorrent/include/libtorrent/extensions.hpp b/libtorrent/include/libtorrent/extensions.hpp index 44fff9c36..fd48588e1 100644 --- a/libtorrent/include/libtorrent/extensions.hpp +++ b/libtorrent/include/libtorrent/extensions.hpp @@ -149,6 +149,12 @@ namespace libtorrent virtual bool on_cancel(peer_request const& req) { return false; } + virtual bool on_reject(peer_request const& req) + { return false; } + + virtual bool on_suggest(int index) + { return false; } + // called when an extended message is received. If returning true, // the message is not processed by any other plugin and if false // is returned the next plugin in the chain will receive it to diff --git a/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp index 210642161..c42136d70 100644 --- a/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp +++ b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp @@ -48,7 +48,7 @@ namespace libtorrent { struct torrent_plugin; class torrent; - TORRENT_EXPORT boost::shared_ptr create_metadata_plugin(torrent*); + TORRENT_EXPORT boost::shared_ptr create_metadata_plugin(torrent*, void*); } #endif // TORRENT_METADATA_TRANSFER_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/extensions/ut_pex.hpp b/libtorrent/include/libtorrent/extensions/ut_pex.hpp index efd9ab4f6..ebf6aa834 100644 --- a/libtorrent/include/libtorrent/extensions/ut_pex.hpp +++ b/libtorrent/include/libtorrent/extensions/ut_pex.hpp @@ -48,7 +48,7 @@ namespace libtorrent { struct torrent_plugin; class torrent; - TORRENT_EXPORT boost::shared_ptr create_ut_pex_plugin(torrent*); + TORRENT_EXPORT boost::shared_ptr create_ut_pex_plugin(torrent*, void*); } #endif // TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/http_tracker_connection.hpp b/libtorrent/include/libtorrent/http_tracker_connection.hpp index b3f35084c..76c3aac98 100755 --- a/libtorrent/include/libtorrent/http_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -180,4 +180,3 @@ namespace libtorrent #endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED - diff --git a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp index ed6944ebb..d2c35ffe3 100644 --- a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp +++ b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp @@ -42,7 +42,7 @@ namespace libtorrent template struct intrusive_ptr_base { - intrusive_ptr_base(const intrusive_ptr_base& b) + intrusive_ptr_base(intrusive_ptr_base const&) : m_refs(0) {} friend void intrusive_ptr_add_ref(intrusive_ptr_base const* s) diff --git a/libtorrent/include/libtorrent/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp index 046df2a6b..b07acffd4 100755 --- a/libtorrent/include/libtorrent/peer_info.hpp +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -72,7 +72,8 @@ namespace libtorrent dht = 0x2, pex = 0x4, lsd = 0x8, - resume_data = 0x10 + resume_data = 0x10, + incoming = 0x20 }; int source; diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index 94f274a27..64f6203d5 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -233,7 +233,7 @@ namespace libtorrent bool is_finished(piece_block block) const; // marks this piece-block as queued for downloading - void mark_as_downloading(piece_block block, void* peer + bool mark_as_downloading(piece_block block, void* peer , piece_state_t s); void mark_as_writing(piece_block block, void* peer); void mark_as_finished(piece_block block, void* peer); diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index 2ce19349e..3a9eb563b 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -150,7 +150,8 @@ namespace libtorrent , entry const& resume_data = entry() , bool compact_mode = true , bool paused = false - , storage_constructor_type sc = default_storage_constructor); + , storage_constructor_type sc = default_storage_constructor + , void* userdata = 0); torrent_handle add_torrent( char const* tracker_url @@ -160,7 +161,8 @@ namespace libtorrent , entry const& resume_data = entry() , bool compact_mode = true , bool paused = false - , storage_constructor_type sc = default_storage_constructor); + , storage_constructor_type sc = default_storage_constructor + , void* userdata = 0); session_proxy abort() { return session_proxy(m_impl); } @@ -181,7 +183,7 @@ namespace libtorrent #endif #ifndef TORRENT_DISABLE_EXTENSIONS - void add_extension(boost::function(torrent*)> ext); + void add_extension(boost::function(torrent*, void*)> ext); #endif void set_ip_filter(ip_filter const& f); diff --git a/libtorrent/include/libtorrent/session_impl.hpp b/libtorrent/include/libtorrent/session_impl.hpp new file mode 100644 index 000000000..67c3fef1d --- /dev/null +++ b/libtorrent/include/libtorrent/session_impl.hpp @@ -0,0 +1,594 @@ +/* + +Copyright (c) 2006, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_SESSION_IMPL_HPP_INCLUDED +#define TORRENT_SESSION_IMPL_HPP_INCLUDED + +#include +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(push, 1) +#endif + +#include +#include +#include +#include +#include + +#ifdef _MSC_VER +#pragma warning(pop) +#endif + +#include "libtorrent/torrent_handle.hpp" +#include "libtorrent/entry.hpp" +#include "libtorrent/torrent_info.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/peer_connection.hpp" +#include "libtorrent/peer_id.hpp" +#include "libtorrent/policy.hpp" +#include "libtorrent/tracker_manager.hpp" +#include "libtorrent/peer_info.hpp" +#include "libtorrent/alert.hpp" +#include "libtorrent/fingerprint.hpp" +#include "libtorrent/debug.hpp" +#include "libtorrent/peer_request.hpp" +#include "libtorrent/piece_block_progress.hpp" +#include "libtorrent/ip_filter.hpp" +#include "libtorrent/config.hpp" +#include "libtorrent/session_settings.hpp" +#include "libtorrent/kademlia/dht_tracker.hpp" +#include "libtorrent/session_status.hpp" +#include "libtorrent/session.hpp" +#include "libtorrent/stat.hpp" +#include "libtorrent/file_pool.hpp" +#include "libtorrent/bandwidth_manager.hpp" +#include "libtorrent/natpmp.hpp" +#include "libtorrent/upnp.hpp" +#include "libtorrent/lsd.hpp" +#include "libtorrent/socket_type.hpp" +#include "libtorrent/connection_queue.hpp" +#include "libtorrent/disk_io_thread.hpp" + +namespace libtorrent +{ + + namespace fs = boost::filesystem; + + namespace aux + { + struct session_impl; + + // this data is shared between the main thread and the + // thread that initialize pieces + struct piece_checker_data + { + piece_checker_data() + : processing(false), progress(0.f), abort(false) {} + + boost::shared_ptr torrent_ptr; + fs::path save_path; + + sha1_hash info_hash; + + void parse_resume_data( + const entry& rd + , const torrent_info& info + , std::string& error); + + std::vector piece_map; + std::vector unfinished_pieces; + std::vector block_info; + std::vector peers; + entry resume_data; + + // this is true if this torrent is being processed (checked) + // if it is not being processed, then it can be removed from + // the queue without problems, otherwise the abort flag has + // to be set. + bool processing; + + // is filled in by storage::initialize_pieces() + // and represents the progress. It should be a + // value in the range [0, 1] + float progress; + + // abort defaults to false and is typically + // filled in by torrent_handle when the user + // aborts the torrent + bool abort; + }; + + struct checker_impl: boost::noncopyable + { + checker_impl(session_impl& s): m_ses(s), m_abort(false) {} + void operator()(); + piece_checker_data* find_torrent(const sha1_hash& info_hash); + void remove_torrent(sha1_hash const& info_hash); + +#ifndef NDEBUG + void check_invariant() const; +#endif + + // when the files has been checked + // the torrent is added to the session + session_impl& m_ses; + + mutable boost::mutex m_mutex; + boost::condition m_cond; + + // a list of all torrents that are currently in queue + // or checking their files + std::deque > m_torrents; + std::deque > m_processing; + + bool m_abort; + }; + +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + struct tracker_logger; +#endif + + // this is the link between the main thread and the + // thread started to run the main downloader loop + struct session_impl: boost::noncopyable + { +#ifndef NDEBUG + friend class ::libtorrent::peer_connection; +#endif + friend struct checker_impl; + friend class invariant_access; + typedef std::map + , boost::intrusive_ptr > + connection_map; + typedef std::map > torrent_map; + + session_impl( + std::pair listen_port_range + , fingerprint const& cl_fprint + , char const* listen_interface = "0.0.0.0"); + ~session_impl(); + +#ifndef TORRENT_DISABLE_EXTENSIONS + void add_extension(boost::function(torrent*)> ext); +#endif + void operator()(); + + void open_listen_port(); + + void async_accept(); + void on_incoming_connection(boost::shared_ptr const& s + , boost::weak_ptr const& as, asio::error_code const& e); + + // must be locked to access the data + // in this struct + typedef boost::recursive_mutex mutex_t; + mutable mutex_t m_mutex; + + boost::weak_ptr find_torrent(const sha1_hash& info_hash); + peer_id const& get_peer_id() const { return m_peer_id; } + + void close_connection(boost::intrusive_ptr const& p); + void connection_failed(boost::shared_ptr const& s + , tcp::endpoint const& a, char const* message); + + void set_settings(session_settings const& s); + session_settings const& settings() const { return m_settings; } + +#ifndef TORRENT_DISABLE_DHT + void add_dht_node(std::pair const& node); + void add_dht_node(udp::endpoint n); + void add_dht_router(std::pair const& node); + void set_dht_settings(dht_settings const& s); + dht_settings const& get_dht_settings() const { return m_dht_settings; } + void start_dht(entry const& startup_state); + void stop_dht(); + entry dht_state() const; +#endif + +#ifndef TORRENT_DISABLE_ENCRYPTION + void set_pe_settings(pe_settings const& settings); + pe_settings const& get_pe_settings() const { return m_pe_settings; } +#endif + + // called when a port mapping is successful, or a router returns + // a failure to map a port + void on_port_mapping(int tcp_port, int udp_port, std::string const& errmsg); + + bool is_aborted() const { return m_abort; } + + void set_ip_filter(ip_filter const& f); + void set_port_filter(port_filter const& f); + + bool listen_on( + std::pair const& port_range + , const char* net_interface = 0); + bool is_listening() const; + + torrent_handle add_torrent( + torrent_info const& ti + , fs::path const& save_path + , entry const& resume_data + , bool compact_mode + , int block_size + , storage_constructor_type sc); + + torrent_handle add_torrent( + char const* tracker_url + , sha1_hash const& info_hash + , char const* name + , fs::path const& save_path + , entry const& resume_data + , bool compact_mode + , int block_size + , storage_constructor_type sc); + + void remove_torrent(torrent_handle const& h); + + std::vector get_torrents(); + + void set_severity_level(alert::severity_t s); + std::auto_ptr pop_alert(); + + int upload_rate_limit() const; + int download_rate_limit() const; + + void set_download_rate_limit(int bytes_per_second); + void set_upload_rate_limit(int bytes_per_second); + void set_max_half_open_connections(int limit); + void set_max_connections(int limit); + void set_max_uploads(int limit); + + int max_connections() const { return m_max_connections; } + int max_uploads() const { return m_max_uploads; } + + int num_uploads() const { return m_num_unchoked; } + int num_connections() const + { return m_connections.size(); } + + void unchoke_peer(peer_connection& c) + { + c.send_unchoke(); + ++m_num_unchoked; + } + + session_status status() const; + void set_peer_id(peer_id const& id); + void set_key(int key); + unsigned short listen_port() const; + + void abort(); + + torrent_handle find_torrent_handle(sha1_hash const& info_hash); + + void announce_lsd(sha1_hash const& ih); + + void set_peer_proxy(proxy_settings const& s) + { m_peer_proxy = s; } + void set_web_seed_proxy(proxy_settings const& s) + { m_web_seed_proxy = s; } + void set_tracker_proxy(proxy_settings const& s) + { m_tracker_proxy = s; } + + proxy_settings const& peer_proxy() const + { return m_peer_proxy; } + proxy_settings const& web_seed_proxy() const + { return m_web_seed_proxy; } + proxy_settings const& tracker_proxy() const + { return m_tracker_proxy; } + +#ifndef TORRENT_DISABLE_DHT + void set_dht_proxy(proxy_settings const& s) + { m_dht_proxy = s; } + proxy_settings const& dht_proxy() const + { return m_dht_proxy; } +#endif + + void start_lsd(); + void start_natpmp(); + void start_upnp(); + + void stop_lsd(); + void stop_natpmp(); + void stop_upnp(); + + // handles delayed alerts + alert_manager m_alerts; + +// private: + + void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih); + + // this is where all active sockets are stored. + // the selector can sleep while there's no activity on + // them + io_service m_io_service; + asio::strand m_strand; + + // the file pool that all storages in this session's + // torrents uses. It sets a limit on the number of + // open files by this session. + // file pool must be destructed after the torrents + // since they will still have references to it + // when they are destructed. + file_pool m_files; + + // handles disk io requests asynchronously + disk_io_thread m_disk_thread; + + // this is a list of half-open tcp connections + // (only outgoing connections) + // this has to be one of the last + // members to be destructed + connection_queue m_half_open; + + // the bandwidth manager is responsible for + // handing out bandwidth to connections that + // asks for it, it can also throttle the + // rate. + bandwidth_manager m_download_channel; + bandwidth_manager m_upload_channel; + + bandwidth_manager* m_bandwidth_manager[2]; + + tracker_manager m_tracker_manager; + torrent_map m_torrents; + + // this maps sockets to their peer_connection + // object. It is the complete list of all connected + // peers. + connection_map m_connections; + + // filters incoming connections + ip_filter m_ip_filter; + + // filters outgoing connections + port_filter m_port_filter; + + // the peer id that is generated at the start of the session + peer_id m_peer_id; + + // the key is an id that is used to identify the + // client with the tracker only. It is randomized + // at startup + int m_key; + + // the range of ports we try to listen on + std::pair m_listen_port_range; + + // the ip-address of the interface + // we are supposed to listen on. + // if the ip is set to zero, it means + // that we should let the os decide which + // interface to listen on + tcp::endpoint m_listen_interface; + + // this is typically set to the same as the local + // listen port. In case a NAT port forward was + // successfully opened, this will be set to the + // port that is open on the external (NAT) interface + // on the NAT box itself. This is the port that has + // to be published to peers, since this is the port + // the client is reachable through. + int m_external_listen_port; + + boost::shared_ptr m_listen_socket; + + // the settings for the client + session_settings m_settings; + // the proxy settings for different + // kinds of connections + proxy_settings m_peer_proxy; + proxy_settings m_web_seed_proxy; + proxy_settings m_tracker_proxy; +#ifndef TORRENT_DISABLE_DHT + proxy_settings m_dht_proxy; +#endif + + // set to true when the session object + // is being destructed and the thread + // should exit + volatile bool m_abort; + + int m_max_uploads; + int m_max_connections; + + // the number of unchoked peers + int m_num_unchoked; + + // this is initialized to the unchoke_interval + // session_setting and decreased every second. + // when it reaches zero, it is reset to the + // unchoke_interval and the unchoke set is + // recomputed. + int m_unchoke_time_scaler; + + // works like unchoke_time_scaler but it + // is only decresed when the unchoke set + // is recomputed, and when it reaches zero, + // the optimistic unchoke is moved to another peer. + int m_optimistic_unchoke_time_scaler; + + // works like unchoke_time_scaler. Each time + // it reaches 0, and all the connections are + // used, the worst connection will be disconnected + // from the torrent with the most peers + int m_disconnect_time_scaler; + + // statistics gathered from all torrents. + stat m_stat; + + // is false by default and set to true when + // the first incoming connection is established + // this is used to know if the client is behind + // NAT or not. + bool m_incoming_connection; + + void second_tick(asio::error_code const& e); + ptime m_last_tick; + +#ifndef TORRENT_DISABLE_DHT + boost::intrusive_ptr m_dht; + dht_settings m_dht_settings; + // if this is set to true, the dht listen port + // will be set to the same as the tcp listen port + // and will be synchronlized with it as it changes + // it defaults to true + bool m_dht_same_port; + + // see m_external_listen_port. This is the same + // but for the udp port used by the DHT. + int m_external_udp_port; +#endif + +#ifndef TORRENT_DISABLE_ENCRYPTION + pe_settings m_pe_settings; +#endif + + boost::shared_ptr m_natpmp; + boost::shared_ptr m_upnp; + boost::shared_ptr m_lsd; + + // the timer used to fire the second_tick + deadline_timer m_timer; + + // the index of the torrent that will be offered to + // connect to a peer next time second_tick is called. + // This implements a round robin. + int m_next_connect_torrent; +#ifndef NDEBUG + void check_invariant(const char *place = 0); +#endif + +#ifdef TORRENT_STATS + // logger used to write bandwidth usage statistics + std::ofstream m_stats_logger; + int m_second_counter; +#endif +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + boost::shared_ptr create_log(std::string const& name + , int instance, bool append = true); + + // this list of tracker loggers serves as tracker_callbacks when + // shutting down. This list is just here to keep them alive during + // whe shutting down process + std::list > m_tracker_loggers; + + public: + boost::shared_ptr m_logger; + private: +#endif + +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list(torrent*)> > extension_list_t; + + extension_list_t m_extensions; +#endif + + // data shared between the main thread + // and the checker thread + checker_impl m_checker_impl; + + // the main working thread + boost::scoped_ptr m_thread; + + // the thread that calls initialize_pieces() + // on all torrents before they start downloading + boost::scoped_ptr m_checker_thread; + }; + +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + struct tracker_logger : request_callback + { + tracker_logger(session_impl& ses): m_ses(ses) {} + void tracker_warning(std::string const& str) + { + debug_log("*** tracker warning: " + str); + } + + void tracker_response(tracker_request const& + , std::vector& peers + , int interval + , int complete + , int incomplete) + { + std::stringstream s; + s << "TRACKER RESPONSE:\n" + "interval: " << interval << "\n" + "peers:\n"; + for (std::vector::const_iterator i = peers.begin(); + i != peers.end(); ++i) + { + s << " " << std::setfill(' ') << std::setw(16) << i->ip + << " " << std::setw(5) << std::dec << i->port << " "; + if (!i->pid.is_all_zeros()) s << " " << i->pid; + s << "\n"; + } + debug_log(s.str()); + } + + void tracker_request_timed_out( + tracker_request const&) + { + debug_log("*** tracker timed out"); + } + + void tracker_request_error( + tracker_request const& + , int response_code + , const std::string& str) + { + debug_log(std::string("*** tracker error: ") + + boost::lexical_cast(response_code) + ": " + + str); + } + + void debug_log(const std::string& line) + { + (*m_ses.m_logger) << line << "\n"; + } + session_impl& m_ses; + }; +#endif + + } +} + + +#endif + diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp index e52196c76..9db79ea3d 100755 --- a/libtorrent/include/libtorrent/storage.hpp +++ b/libtorrent/include/libtorrent/storage.hpp @@ -202,7 +202,8 @@ namespace libtorrent void async_read( peer_request const& r , boost::function const& handler - , char* buffer = 0); + , char* buffer = 0 + , int priority = 0); void async_write( peer_request const& r @@ -343,7 +344,8 @@ namespace libtorrent std::multimap m_hash_to_piece; // this map contains partial hashes for downloading - // pieces. + // pieces. This is only accessed from within the + // disk-io thread. std::map m_piece_hasher; disk_io_thread& m_io_thread; diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index 31a39c38e..287c57305 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -399,6 +399,7 @@ namespace libtorrent , m_info_hash(h) { assert(m_ses != 0); + assert(m_chk != 0); } #ifndef NDEBUG diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp index 1435ceda6..57f7bd851 100755 --- a/libtorrent/include/libtorrent/tracker_manager.hpp +++ b/libtorrent/include/libtorrent/tracker_manager.hpp @@ -194,11 +194,10 @@ namespace libtorrent , address bind_interface , boost::weak_ptr r); - request_callback& requester(); + boost::shared_ptr requester(); virtual ~tracker_connection() {} tracker_request const& tracker_req() const { return m_req; } - bool has_requester() const { return !m_requester.expired(); } void fail(int code, char const* msg); void fail_timeout(); diff --git a/libtorrent/src/Makefile.am b/libtorrent/src/Makefile.am index 671cb75e5..3ab9f73bd 100644 --- a/libtorrent/src/Makefile.am +++ b/libtorrent/src/Makefile.am @@ -13,7 +13,7 @@ kademlia/traversal_algorithm.cpp endif libtorrent_la_SOURCES = entry.cpp escape_string.cpp \ -enum_net.cpp broadcast_socket.cpp \ +assert.cpp enum_net.cpp broadcast_socket.cpp \ peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \ natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \ stat.cpp storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \ @@ -28,6 +28,7 @@ $(kademlia_sources) noinst_HEADERS = \ $(top_srcdir)/include/libtorrent/alert.hpp \ $(top_srcdir)/include/libtorrent/alert_types.hpp \ +$(top_srcdir)/include/libtorrent/assert.hpp \ $(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \ $(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \ $(top_srcdir)/include/libtorrent/bencode.hpp \ diff --git a/libtorrent/src/assert.cpp b/libtorrent/src/assert.cpp index da79a745b..b4f011978 100644 --- a/libtorrent/src/assert.cpp +++ b/libtorrent/src/assert.cpp @@ -34,7 +34,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include +#if defined __linux__ && defined __GNUC__ #include +#endif void assert_fail(char const* expr, int line, char const* file, char const* function) { @@ -48,6 +51,7 @@ void assert_fail(char const* expr, int line, char const* file, char const* funct "expression: %s\n" "stack:\n", file, line, function, expr); +#if defined __linux__ && defined __GNUC__ void* stack[50]; int size = backtrace(stack, 50); char** symbols = backtrace_symbols(stack, size); @@ -58,7 +62,11 @@ void assert_fail(char const* expr, int line, char const* file, char const* funct } free(symbols); - exit(1); +#endif + // send SIGINT to the current process + // to break into the debugger + raise(SIGINT); + abort(); } #endif diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index a937fc11b..3aaadcc81 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/src/broadcast_socket.cpp @@ -43,7 +43,7 @@ namespace libtorrent { bool is_local(address const& a) { - if (a.is_v6()) return false; + if (a.is_v6()) return a.to_v6().is_link_local(); address_v4 a4 = a.to_v4(); unsigned long ip = a4.to_ulong(); return ((ip & 0xff000000) == 0x0a000000 @@ -58,25 +58,40 @@ namespace libtorrent udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); for (;i != udp::resolver_iterator(); ++i) { - // ignore the loopback - if (i->endpoint().address() == address_v4((127 << 24) + 1)) continue; - // ignore addresses that are not on a local network - if (!is_local(i->endpoint().address())) continue; + address const& a = i->endpoint().address(); // ignore non-IPv4 addresses - if (i->endpoint().address().is_v4()) break; + if (!a.is_v4()) break; + // ignore the loopback + if (a.to_v4() == address_v4::loopback()) continue; } if (i == udp::resolver_iterator()) return address_v4::any(); return i->endpoint().address().to_v4(); } + bool is_loopback(address const& addr) + { + if (addr.is_v4()) + return addr.to_v4() == address_v4::loopback(); + else + return addr.to_v6() == address_v6::loopback(); + } + + bool is_multicast(address const& addr) + { + if (addr.is_v4()) + return addr.to_v4().is_multicast(); + else + return addr.to_v6().is_multicast(); + } + broadcast_socket::broadcast_socket(asio::io_service& ios , udp::endpoint const& multicast_endpoint - , receive_handler_t const& handler) + , receive_handler_t const& handler + , bool loopback) : m_multicast_endpoint(multicast_endpoint) , m_on_receive(handler) { - assert(m_multicast_endpoint.address().is_v4()); - assert(m_multicast_endpoint.address().to_v4().is_multicast()); + assert(is_multicast(m_multicast_endpoint.address())); using namespace asio::ip::multicast; @@ -87,26 +102,51 @@ namespace libtorrent , end(interfaces.end()); i != end; ++i) { // only broadcast to IPv4 addresses that are not local - if (!i->is_v4() || !is_local(*i)) continue; - // ignore the loopback interface - if (i->to_v4() == address_v4((127 << 24) + 1)) continue; + if (!is_local(*i)) continue; + // only multicast on compatible networks + if (i->is_v4() != multicast_endpoint.address().is_v4()) continue; + // ignore any loopback interface + if (is_loopback(*i)) continue; boost::shared_ptr s(new datagram_socket(ios)); - s->open(udp::v4(), ec); + if (i->is_v4()) + { + s->open(udp::v4(), ec); + if (ec) continue; + s->set_option(datagram_socket::reuse_address(true), ec); + if (ec) continue; + s->bind(udp::endpoint(address_v4::any(), multicast_endpoint.port()), ec); + if (ec) continue; + s->set_option(join_group(multicast_endpoint.address()), ec); + if (ec) continue; + s->set_option(outbound_interface(i->to_v4()), ec); + if (ec) continue; + } + else + { + s->open(udp::v6(), ec); + if (ec) continue; + s->set_option(datagram_socket::reuse_address(true), ec); + if (ec) continue; + s->bind(udp::endpoint(address_v6::any(), multicast_endpoint.port()), ec); + if (ec) continue; + s->set_option(join_group(multicast_endpoint.address()), ec); + if (ec) continue; +// s->set_option(outbound_interface(i->to_v6()), ec); +// if (ec) continue; + } + s->set_option(hops(255), ec); if (ec) continue; - s->set_option(datagram_socket::reuse_address(true), ec); + s->set_option(enable_loopback(loopback), ec); if (ec) continue; - s->bind(udp::endpoint(*i, 0), ec); - if (ec) continue; - s->set_option(join_group(multicast_endpoint.address()), ec); - if (ec) continue; - s->set_option(outbound_interface(i->to_v4()), ec); - if (ec) continue; - s->set_option(hops(255)); m_sockets.push_back(socket_entry(s)); socket_entry& se = m_sockets.back(); s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer)) , se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2)); +#ifndef NDEBUG +// std::cerr << "broadcast socket [ if: " << i->to_v4().to_string() +// << " group: " << multicast_endpoint.address() << " ]" << std::endl; +#endif } } @@ -117,7 +157,9 @@ namespace libtorrent { asio::error_code e; i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e); +#ifndef NDEBUG // std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl; +#endif if (e) ec = e; } } diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index 11a39675f..ab61d98f9 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -50,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/version.hpp" #include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_impl.hpp" +#include "libtorrent/enum_net.hpp" #ifndef TORRENT_DISABLE_ENCRYPTION #include "libtorrent/pe_crypto.hpp" @@ -1221,7 +1222,7 @@ namespace libtorrent { tcp::endpoint adr(remote().address() , (unsigned short)listen_port->integer()); - t->get_policy().peer_from_tracker(adr, pid(), 0, 0); + t->get_policy().peer_from_tracker(adr, pid(), peer_info::incoming, 0); } } // there should be a version too @@ -1474,6 +1475,19 @@ namespace libtorrent detail::write_address(remote().address(), out); handshake["yourip"] = remote_address; handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue; + asio::error_code ec; + std::vector
const& interfaces = enum_net_interfaces(get_socket()->io_service(), ec); + for (std::vector
::const_iterator i = interfaces.begin() + , end(interfaces.end()); i != end; ++i) + { + // TODO: only use global IPv6 addresses + if (!i->is_v6() || i->to_v6().is_link_local()) continue; + std::string ipv6_address; + std::back_insert_iterator out(ipv6_address); + detail::write_address(*i, out); + handshake["ipv6"] = ipv6_address; + break; + } // loop backwards, to make the first extension be the last // to fill in the handshake (i.e. give the first extensions priority) diff --git a/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index e07a884cf..4fb2cfb3a 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -34,6 +34,24 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/disk_io_thread.hpp" +#ifdef TORRENT_DISK_STATS + +#include "libtorrent/time.hpp" +#include + +namespace +{ + std::string log_time() + { + using namespace libtorrent; + static ptime start = time_now(); + return boost::lexical_cast( + total_milliseconds(time_now() - start)); + } +} + +#endif + namespace libtorrent { @@ -45,7 +63,12 @@ namespace libtorrent , m_block_size(block_size) #endif , m_disk_io_thread(boost::ref(*this)) - {} + { + +#ifdef TORRENT_DISK_STATS + m_log.open("disk_io_thread.log", std::ios::trunc); +#endif + } disk_io_thread::~disk_io_thread() { @@ -89,8 +112,15 @@ namespace libtorrent namespace { + // The semantic of this operator is: + // shouls lhs come before rhs in the job queue bool operator<(disk_io_job const& lhs, disk_io_job const& rhs) { + // NOTE: comparison inverted to make higher priority + // skip _in_front_of_ lower priority + if (lhs.priority > rhs.priority) return true; + if (lhs.priority < rhs.priority) return false; + if (lhs.storage.get() < rhs.storage.get()) return true; if (lhs.storage.get() > rhs.storage.get()) return false; if (lhs.piece < rhs.piece) return true; @@ -165,6 +195,9 @@ namespace libtorrent { for (;;) { +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " idle" << std::endl; +#endif boost::mutex::scoped_lock l(m_mutex); while (m_jobs.empty() && !m_abort) m_signal.wait(l); @@ -182,10 +215,16 @@ namespace libtorrent bool free_buffer = true; try { +#ifdef TORRENT_DISK_STATS + ptime start = time_now(); +#endif // std::cerr << "DISK THREAD: executing job: " << j.action << std::endl; switch (j.action) { case disk_io_job::read: +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " read " << j.buffer_size << std::endl; +#endif if (j.buffer == 0) { l.lock(); @@ -210,6 +249,9 @@ namespace libtorrent // usleep(300); break; case disk_io_job::write: +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " write " << j.buffer_size << std::endl; +#endif assert(j.buffer); assert(j.buffer_size <= m_block_size); j.storage->write_impl(j.buffer, j.piece, j.offset @@ -220,16 +262,25 @@ namespace libtorrent break; case disk_io_job::hash: { +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " hash" << std::endl; +#endif sha1_hash h = j.storage->hash_for_piece_impl(j.piece); j.str.resize(20); std::memcpy(&j.str[0], &h[0], 20); } break; case disk_io_job::move_storage: +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " move" << std::endl; +#endif ret = j.storage->move_storage_impl(j.str) ? 1 : 0; j.str = j.storage->save_path().string(); break; case disk_io_job::release_files: +#ifdef TORRENT_DISK_STATS + m_log << log_time() << " release" << std::endl; +#endif j.storage->release_files_impl(); break; } diff --git a/libtorrent/src/enum_net.cpp b/libtorrent/src/enum_net.cpp index 54af814d6..172719793 100644 --- a/libtorrent/src/enum_net.cpp +++ b/libtorrent/src/enum_net.cpp @@ -72,8 +72,17 @@ namespace libtorrent ifreq const& item = *reinterpret_cast(ifr); if (item.ifr_addr.sa_family == AF_INET) { - ret.push_back(address::from_string( - inet_ntoa(((sockaddr_in const*)&item.ifr_addr)->sin_addr))); + typedef asio::ip::address_v4::bytes_type bytes_t; + bytes_t b; + memcpy(&b[0], &((sockaddr_in const*)&item.ifr_addr)->sin_addr, b.size()); + ret.push_back(address_v4(b)); + } + else if (item.ifr_addr.sa_family == AF_INET6) + { + typedef asio::ip::address_v6::bytes_type bytes_t; + bytes_t b; + memcpy(&b[0], &((sockaddr_in6 const*)&item.ifr_addr)->sin6_addr, b.size()); + ret.push_back(address_v6(b)); } #if defined __MACH__ || defined(__FreeBSD__) diff --git a/libtorrent/src/file.cpp b/libtorrent/src/file.cpp index 3d568d1f7..72876d528 100755 --- a/libtorrent/src/file.cpp +++ b/libtorrent/src/file.cpp @@ -247,19 +247,16 @@ namespace libtorrent void set_size(size_type s) { - size_type pos = tell(); - // Only set size if current file size not equals s. - // 2 as "m" argument is to be sure seek() sets SEEK_END on - // all compilers. - if(s != seek(0, 2)) +#ifdef _WIN32 +#error file.cpp is for posix systems only. use file_win.cpp on windows +#else + if (ftruncate(m_fd, s) < 0) { - seek(s - 1); - char dummy = 0; - read(&dummy, 1); - seek(s - 1); - write(&dummy, 1); + std::stringstream msg; + msg << "ftruncate failed: '" << strerror(errno); + throw file_error(msg.str()); } - seek(pos); +#endif } size_type seek(size_type offset, int m = 1) diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 2a3c4449a..0a0e59c48 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -952,4 +952,3 @@ namespace libtorrent } - diff --git a/libtorrent/src/metadata_transfer.cpp b/libtorrent/src/metadata_transfer.cpp index a19dd3d3f..0623b156f 100644 --- a/libtorrent/src/metadata_transfer.cpp +++ b/libtorrent/src/metadata_transfer.cpp @@ -556,7 +556,7 @@ namespace libtorrent { namespace namespace libtorrent { - boost::shared_ptr create_metadata_plugin(torrent* t) + boost::shared_ptr create_metadata_plugin(torrent* t, void*) { return boost::shared_ptr(new metadata_plugin(*t)); } diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index ad2102f0d..25bc0ba63 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -687,6 +687,14 @@ namespace libtorrent boost::shared_ptr t = m_torrent.lock(); assert(t); +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_reject(r)) return; + } +#endif + std::deque::iterator i = std::find_if( m_download_queue.begin(), m_download_queue.end() , bind(match_request, boost::cref(r), _1, t->block_size())); @@ -743,7 +751,7 @@ namespace libtorrent void peer_connection::incoming_suggest(int index) { INVARIANT_CHECK; - + #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " <== SUGGEST_PIECE [ piece: " << index << " ]\n"; @@ -751,6 +759,14 @@ namespace libtorrent boost::shared_ptr t = m_torrent.lock(); if (!t) return; +#ifndef TORRENT_DISABLE_EXTENSIONS + for (extension_list_t::iterator i = m_extensions.begin() + , end(m_extensions.end()); i != end; ++i) + { + if ((*i)->on_suggest(index)) return; + } +#endif + if (t->have_piece(index)) return; if (m_suggested_pieces.size() > 9) @@ -1647,7 +1663,9 @@ namespace libtorrent state = piece_picker::slow; } - t->picker().mark_as_downloading(block, peer_info_struct(), state); + if (!t->picker().mark_as_downloading(block, peer_info_struct(), state)) + return; + if (t->alerts().should_post(alert::info)) { t->alerts().post_alert(block_downloading_alert(t->get_handle(), @@ -1934,7 +1952,6 @@ namespace libtorrent } t->remove_peer(this); - m_torrent.reset(); } @@ -2838,6 +2855,8 @@ namespace libtorrent return; } + assert(t->connection_for(remote()) != 0 || m_in_constructor); + if (!m_in_constructor && t->connection_for(remote()) != this && !m_ses.settings().allow_multiple_connections_per_ip) { @@ -2897,11 +2916,6 @@ namespace libtorrent // TODO: the timeout should be called by an event INVARIANT_CHECK; -#ifndef NDEBUG - // allow step debugging without timing out - return false; -#endif - ptime now(time_now()); // if the socket is still connecting, don't @@ -2915,6 +2929,10 @@ namespace libtorrent d = now - m_last_receive; if (d > seconds(m_timeout)) return true; + // if it takes more than 5 seconds to receive + // handshake, disconnect + if (in_handshake() && d > seconds(5)) return true; + // disconnect peers that we unchoked, but // they didn't send a request within 20 seconds. // but only if we're a seed diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index 8fa623fa3..398573d33 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -1229,6 +1229,7 @@ namespace libtorrent bool piece_picker::can_pick(int piece, std::vector const& bitmask) const { + assert(piece >= 0 && piece < int(m_piece_map.size())); return bitmask[piece] && !m_piece_map[piece].have() && !m_piece_map[piece].downloading @@ -1375,10 +1376,8 @@ namespace libtorrent { // ignore completed blocks and already requested blocks block_info const& info = i->info[j]; - if (info.state == block_info::state_finished - || info.state == block_info::state_writing - || info.state == block_info::state_requested) - continue; + if (info.state != block_info::state_none) + continue; assert(i->info[j].state == block_info::state_none); @@ -1432,6 +1431,80 @@ namespace libtorrent if (num_blocks <= 0) return 0; + if (prefer_whole_pieces > 0) + { + for (std::vector::const_iterator i = m_downloads.begin() + , end(m_downloads.end()); i != end; ++i) + { + if (!pieces[i->index]) continue; + int num_blocks_in_piece = blocks_in_piece(i->index); + bool exclusive; + bool exclusive_active; + boost::tie(exclusive, exclusive_active) + = requested_from(*i, num_blocks_in_piece, peer); + + if (exclusive_active) continue; + + for (int j = 0; j < num_blocks_in_piece; ++j) + { + block_info const& info = i->info[j]; + if (info.state != block_info::state_none) continue; + backup_blocks.push_back(piece_block(i->index, j)); + } + } + } + + if (int(backup_blocks.size()) >= num_blocks) return num_blocks; + + +#ifndef NDEBUG +// make sure that we at this point has added requests to all unrequested blocks +// in all downloading pieces + + for (std::vector::const_iterator i = m_downloads.begin() + , end(m_downloads.end()); i != end; ++i) + { + if (!pieces[i->index]) continue; + + int num_blocks_in_piece = blocks_in_piece(i->index); + for (int j = 0; j < num_blocks_in_piece; ++j) + { + block_info const& info = i->info[j]; + if (info.state != block_info::state_none) continue; + std::vector::iterator k = std::find( + interesting_blocks.begin(), interesting_blocks.end() + , piece_block(i->index, j)); + if (k != interesting_blocks.end()) continue; + + k = std::find(backup_blocks.begin() + , backup_blocks.end(), piece_block(i->index, j)); + if (k != backup_blocks.end()) continue; + + std::cerr << "interesting blocks:" << std::endl; + for (k = interesting_blocks.begin(); k != interesting_blocks.end(); ++k) + std::cerr << "(" << k->piece_index << ", " << k->block_index << ") "; + std::cerr << std::endl; + std::cerr << "backup blocks:" << std::endl; + for (k = backup_blocks.begin(); k != backup_blocks.end(); ++k) + std::cerr << "(" << k->piece_index << ", " << k->block_index << ") "; + std::cerr << std::endl; + std::cerr << "num_blocks: " << num_blocks << std::endl; + + for (std::vector::const_iterator l = m_downloads.begin() + , end(m_downloads.end()); l != end; ++l) + { + std::cerr << l->index << " : "; + int num_blocks_in_piece = blocks_in_piece(l->index); + for (int m = 0; m < num_blocks_in_piece; ++m) + std::cerr << l->info[m].state; + std::cerr << std::endl; + } + + assert(false); + } + } +#endif + for (std::vector::const_iterator i = m_downloads.begin() , end(m_downloads.end()); i != end; ++i) { @@ -1554,7 +1627,7 @@ namespace libtorrent } - void piece_picker::mark_as_downloading(piece_block block + bool piece_picker::mark_as_downloading(piece_block block , void* peer, piece_state_t state) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; @@ -1589,6 +1662,9 @@ namespace libtorrent = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); assert(i != m_downloads.end()); block_info& info = i->info[block.block_index]; + if (info.state == block_info::state_writing + || info.state == block_info::state_finished) + return false; assert(info.state == block_info::state_none || (info.state == block_info::state_requested && (info.num_peers > 0))); @@ -1601,6 +1677,7 @@ namespace libtorrent ++info.num_peers; if (i->state == none) i->state = state; } + return true; } int piece_picker::num_peers(piece_block block) const diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 6e81da0d5..4faed837e 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -138,28 +138,28 @@ namespace return free_upload; } - struct match_peer_ip + struct match_peer_address { - match_peer_ip(address const& ip) - : m_ip(ip) + match_peer_address(address const& addr) + : m_addr(addr) {} bool operator()(policy::peer const& p) const - { return p.ip.address() == m_ip; } + { return p.ip.address() == m_addr; } - address const& m_ip; + address const& m_addr; }; - struct match_peer_id + struct match_peer_endpoint { - match_peer_id(peer_id const& id_) - : m_id(id_) + match_peer_endpoint(tcp::endpoint const& ep) + : m_ep(ep) {} bool operator()(policy::peer const& p) const - { return p.connection && p.connection->pid() == m_id; } + { return p.ip == m_ep; } - peer_id const& m_id; + tcp::endpoint const& m_ep; }; struct match_peer_connection @@ -939,7 +939,7 @@ namespace libtorrent i = std::find_if( m_peers.begin() , m_peers.end() - , match_peer_ip(c.remote().address())); + , match_peer_address(c.remote().address())); } if (i != m_peers.end()) @@ -1029,14 +1029,14 @@ namespace libtorrent i = std::find_if( m_peers.begin() , m_peers.end() - , match_peer_id(pid)); + , match_peer_endpoint(remote)); } else { i = std::find_if( m_peers.begin() , m_peers.end() - , match_peer_ip(remote.address())); + , match_peer_address(remote.address())); } if (i == m_peers.end()) @@ -1291,9 +1291,15 @@ namespace libtorrent try { + INVARIANT_CHECK; p->connected = time_now(); p->connection = m_torrent->connect_to_peer(&*p); - if (p->connection == 0) return false; + assert(p->connection == m_torrent->connection_for(p->ip)); + if (p->connection == 0) + { + ++p->failcount; + return false; + } p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload); p->prev_amount_download = 0; p->prev_amount_upload = 0; @@ -1305,6 +1311,7 @@ namespace libtorrent (*m_torrent->session().m_logger) << "*** CONNECTION FAILED '" << e.what() << "'\n"; #endif + std::cerr << e.what() << std::endl; ++p->failcount; return false; } @@ -1402,15 +1409,22 @@ namespace libtorrent int nonempty_connections = 0; std::set
unique_test; + std::set unique_test2; for (const_iterator i = m_peers.begin(); i != m_peers.end(); ++i) { peer const& p = *i; if (!m_torrent->settings().allow_multiple_connections_per_ip) assert(unique_test.find(p.ip.address()) == unique_test.end()); + assert(unique_test2.find(p.ip) == unique_test2.end()); unique_test.insert(p.ip.address()); + unique_test2.insert(p.ip); ++total_connections; - if (!p.connection) continue; + if (!p.connection) + { +// assert(m_torrent->connection_for(p.ip) == 0); + continue; + } if (!m_torrent->settings().allow_multiple_connections_per_ip) { std::vector conns; diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index 1d7a070c2..6298b3c2c 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -132,7 +132,7 @@ namespace libtorrent m_impl->abort(); } - void session::add_extension(boost::function(torrent*)> ext) + void session::add_extension(boost::function(torrent*, void*)> ext) { m_impl->add_extension(ext); } @@ -185,7 +185,7 @@ namespace libtorrent assert(!ti.m_half_metadata); boost::intrusive_ptr tip(new torrent_info(ti)); return m_impl->add_torrent(tip, save_path, resume_data - , compact_mode, sc, paused); + , compact_mode, sc, paused, 0); } torrent_handle session::add_torrent( @@ -194,11 +194,12 @@ namespace libtorrent , entry const& resume_data , bool compact_mode , bool paused - , storage_constructor_type sc) + , storage_constructor_type sc + , void* userdata) { assert(!ti->m_half_metadata); return m_impl->add_torrent(ti, save_path, resume_data - , compact_mode, sc, paused); + , compact_mode, sc, paused, userdata); } torrent_handle session::add_torrent( @@ -209,10 +210,11 @@ namespace libtorrent , entry const& e , bool compact_mode , bool paused - , storage_constructor_type sc) + , storage_constructor_type sc + , void* userdata) { return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e - , compact_mode, sc, paused); + , compact_mode, sc, paused, userdata); } void session::remove_torrent(const torrent_handle& h) diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 0aeb84bbe..6e1129b99 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -593,7 +593,7 @@ namespace detail #ifndef TORRENT_DISABLE_EXTENSIONS void session_impl::add_extension( - boost::function(torrent*)> ext) + boost::function(torrent*, void*)> ext) { m_extensions.push_back(ext); } @@ -1474,7 +1474,8 @@ namespace detail , entry const& resume_data , bool compact_mode , storage_constructor_type sc - , bool paused) + , bool paused + , void* userdata) { // if you get this assert, you haven't managed to // open a listen port. call listen_on() first. @@ -1514,7 +1515,7 @@ namespace detail for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) { - boost::shared_ptr tp((*i)(torrent_ptr.get())); + boost::shared_ptr tp((*i)(torrent_ptr.get(), userdata)); if (tp) torrent_ptr->add_extension(tp); } #endif @@ -1554,7 +1555,8 @@ namespace detail , entry const& , bool compact_mode , storage_constructor_type sc - , bool paused) + , bool paused + , void* userdata) { // TODO: support resume data in this case @@ -1593,7 +1595,7 @@ namespace detail for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) { - boost::shared_ptr tp((*i)(torrent_ptr.get())); + boost::shared_ptr tp((*i)(torrent_ptr.get(), userdata)); if (tp) torrent_ptr->add_extension(tp); } #endif diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index e1ddd20ae..dbf6a9382 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -403,13 +403,19 @@ namespace libtorrent assert(ph.offset == 0 || partial_copy.final() == partial.final()); #endif int slot_size = piece_size - ph.offset; - if (slot_size == 0) return ph.h.final(); - m_scratch_buffer.resize(slot_size); - read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true); - ph.h.update(&m_scratch_buffer[0], slot_size); + if (slot_size > 0) + { + m_scratch_buffer.resize(slot_size); + read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true); + ph.h.update(&m_scratch_buffer[0], slot_size); + } +#ifndef NDEBUG sha1_hash ret = ph.h.final(); - assert(whole.final() == ret); + assert(ret == whole.final()); return ret; +#else + return ph.h.final(); +#endif } void storage::initialize(bool allocate_files) @@ -996,9 +1002,6 @@ namespace libtorrent int err = statfs(query_path.native_directory_string().c_str(), &buf); if (err == 0) { -#ifndef NDEBUG - std::cerr << "buf.f_type " << std::hex << buf.f_type << std::endl; -#endif switch (buf.f_type) { case 0x5346544e: // NTFS @@ -1084,7 +1087,8 @@ namespace libtorrent void piece_manager::async_read( peer_request const& r , boost::function const& handler - , char* buffer) + , char* buffer + , int priority) { disk_io_job j; j.storage = this; @@ -1093,6 +1097,7 @@ namespace libtorrent j.offset = r.start; j.buffer_size = r.length; j.buffer = buffer; + j.priority = priority; // if a buffer is not specified, only one block can be read // since that is the size of the pool allocator's buffers assert(r.length <= 16 * 1024 || buffer != 0); @@ -1295,6 +1300,7 @@ namespace libtorrent if (i != m_piece_hasher.end()) { assert(i->second.offset > 0); + assert(offset >= i->second.offset); if (offset == i->second.offset) { i->second.offset += size; diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index ddf8a9164..252461bc6 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -1653,6 +1653,7 @@ namespace libtorrent assert(m_connections.find(a) == m_connections.end()); // add the newly connected peer to this torrent's peer list + assert(m_connections.find(a) == m_connections.end()); m_connections.insert( std::make_pair(a, boost::get_pointer(c))); m_ses.m_connections.insert(std::make_pair(s, c)); @@ -1669,8 +1670,8 @@ namespace libtorrent #endif // TODO: post an error alert! - std::map::iterator i = m_connections.find(a); - if (i != m_connections.end()) m_connections.erase(i); +// std::map::iterator i = m_connections.find(a); +// if (i != m_connections.end()) m_connections.erase(i); m_ses.connection_failed(s, a, e.what()); c->disconnect(); } @@ -1857,6 +1858,8 @@ namespace libtorrent try { + assert(m_connections.find(a) == m_connections.end()); + // add the newly connected peer to this torrent's peer list m_connections.insert( std::make_pair(a, boost::get_pointer(c))); @@ -1869,6 +1872,7 @@ namespace libtorrent } catch (std::exception& e) { + assert(false); // TODO: post an error alert! std::map::iterator i = m_connections.find(a); if (i != m_connections.end()) m_connections.erase(i); @@ -1925,6 +1929,7 @@ namespace libtorrent = m_connections.find(p->remote()); if (c != m_connections.end()) { + assert(p != c->second); // we already have a peer_connection to this ip. // It may currently be waiting for completing a // connection attempt that might fail. So, @@ -1948,6 +1953,7 @@ namespace libtorrent throw protocol_error("session is closing"); } + assert(m_connections.find(p->remote()) == m_connections.end()); peer_iterator ci = m_connections.insert( std::make_pair(p->remote(), p)).first; try @@ -2408,6 +2414,12 @@ namespace libtorrent assert(m_abort || m_have_pieces.empty()); } +/* for (policy::const_iterator i = m_policy->begin_peer() + , end(m_policy->end_peer()); i != end; ++i) + { + assert(i->connection == const_cast(this)->connection_for(i->ip)); + } +*/ size_type total_done = quantized_bytes_done(); if (m_torrent_file->is_valid()) { diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index 3cf1f2bac..ebef802a8 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -94,18 +94,11 @@ namespace libtorrent , aux::checker_impl* chk , sha1_hash const& hash) { - if (ses == 0) throw_invalid_handle(); + aux::piece_checker_data* d = chk->find_torrent(hash); + if (d != 0) return d->torrent_ptr; - if (chk) - { - aux::piece_checker_data* d = chk->find_torrent(hash); - if (d != 0) return d->torrent_ptr; - } - - { - boost::shared_ptr t = ses->find_torrent(hash).lock(); - if (t) return t; - } + boost::shared_ptr t = ses->find_torrent(hash).lock(); + if (t) return t; // throwing directly instead of calling // the throw_invalid_handle() function @@ -118,7 +111,7 @@ namespace libtorrent void torrent_handle::check_invariant() const { - assert((m_ses == 0 && m_chk == 0) || (m_ses != 0)); + assert((m_ses == 0 && m_chk == 0) || (m_ses != 0 && m_chk != 0)); } #endif @@ -127,6 +120,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + assert(max_uploads >= 2 || max_uploads == -1); session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); @@ -138,6 +134,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->use_interface(net_interface); @@ -147,6 +146,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + assert(max_connections >= 2 || max_connections == -1); session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); @@ -159,6 +161,9 @@ namespace libtorrent INVARIANT_CHECK; assert(limit >= -1); + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->set_peer_upload_limit(ip, limit); @@ -169,6 +174,9 @@ namespace libtorrent INVARIANT_CHECK; assert(limit >= -1); + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->set_peer_download_limit(ip, limit); @@ -178,6 +186,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + assert(limit >= -1); session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); @@ -188,6 +199,10 @@ namespace libtorrent int torrent_handle::upload_limit() const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->upload_limit(); @@ -197,6 +212,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + assert(limit >= -1); session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); @@ -208,6 +226,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->download_limit(); @@ -218,6 +239,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->move_storage(save_path); @@ -227,6 +251,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->valid_metadata(); @@ -236,6 +263,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->is_seed(); @@ -245,6 +275,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->is_paused(); @@ -254,6 +287,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->pause(); @@ -263,6 +299,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->resume(); @@ -273,6 +312,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->set_tracker_login(name, password); @@ -283,31 +325,27 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); + mutex::scoped_lock l2(m_chk->m_mutex); - if (m_chk) + aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); + if (d != 0) { - mutex::scoped_lock l(m_chk->m_mutex); - - aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); - if (d != 0) + if (!d->processing) { - if (!d->processing) - { - torrent_info const& info = d->torrent_ptr->torrent_file(); - progress.clear(); - progress.resize(info.num_files(), 0.f); - return; - } - d->torrent_ptr->file_progress(progress); + torrent_info const& info = d->torrent_ptr->torrent_file(); + progress.clear(); + progress.resize(info.num_files(), 0.f); return; } + d->torrent_ptr->file_progress(progress); + return; } - { - session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); - boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); - if (t) return t->file_progress(progress); - } + boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); + if (t) return t->file_progress(progress); throw_invalid_handle(); } @@ -317,36 +355,32 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); + mutex::scoped_lock l2(m_chk->m_mutex); - if (m_chk) + aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); + if (d != 0) { - mutex::scoped_lock l(m_chk->m_mutex); + torrent_status st; - aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); - if (d != 0) + if (d->processing) { - torrent_status st; - - if (d->processing) - { - if (d->torrent_ptr->is_allocating()) - st.state = torrent_status::allocating; - else - st.state = torrent_status::checking_files; - } + if (d->torrent_ptr->is_allocating()) + st.state = torrent_status::allocating; else - st.state = torrent_status::queued_for_checking; - st.progress = d->progress; - st.paused = d->torrent_ptr->is_paused(); - return st; + st.state = torrent_status::checking_files; } + else + st.state = torrent_status::queued_for_checking; + st.progress = d->progress; + st.paused = d->torrent_ptr->is_paused(); + return st; } - { - session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); - boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); - if (t) return t->status(); - } + boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); + if (t) return t->status(); throw_invalid_handle(); return torrent_status(); @@ -355,6 +389,10 @@ namespace libtorrent void torrent_handle::set_sequenced_download_threshold(int threshold) const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->set_sequenced_download_threshold(threshold); @@ -364,6 +402,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->name(); @@ -374,6 +415,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->piece_availability(avail); @@ -383,6 +427,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->set_piece_priority(index, priority); @@ -392,6 +439,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->piece_priority(index); @@ -401,6 +451,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->prioritize_pieces(pieces); @@ -409,6 +462,10 @@ namespace libtorrent std::vector torrent_handle::piece_priorities() const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + std::vector ret; session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); @@ -420,6 +477,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->prioritize_files(files); @@ -430,6 +490,10 @@ namespace libtorrent void torrent_handle::filter_piece(int index, bool filter) const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->filter_piece(index, filter); @@ -438,6 +502,10 @@ namespace libtorrent void torrent_handle::filter_pieces(std::vector const& pieces) const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->filter_pieces(pieces); @@ -446,6 +514,10 @@ namespace libtorrent bool torrent_handle::is_piece_filtered(int index) const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->is_piece_filtered(index); @@ -454,6 +526,10 @@ namespace libtorrent std::vector torrent_handle::filtered_pieces() const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + std::vector ret; session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); @@ -464,6 +540,10 @@ namespace libtorrent void torrent_handle::filter_files(std::vector const& files) const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->filter_files(files); @@ -476,6 +556,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->trackers(); @@ -485,6 +568,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->add_url_seed(url); @@ -494,6 +580,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->remove_url_seed(url); @@ -503,6 +592,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->url_seeds(); @@ -513,6 +605,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->replace_trackers(urls); @@ -521,6 +616,10 @@ namespace libtorrent torrent_info const& torrent_handle::get_torrent_info() const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); boost::shared_ptr t = find_torrent(m_ses, m_chk, m_info_hash); @@ -533,16 +632,14 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) return false; + assert(m_chk); - if (m_chk) - { - mutex::scoped_lock l(m_chk->m_mutex); - aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); - if (d != 0) return true; - } + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); + mutex::scoped_lock l2(m_chk->m_mutex); + aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); + if (d != 0) return true; { - session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::weak_ptr t = m_ses->find_torrent(m_info_hash); if (!t.expired()) return true; } @@ -556,6 +653,7 @@ namespace libtorrent std::vector piece_index; if (m_ses == 0) return entry(); + assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -674,6 +772,9 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->save_path(); @@ -684,6 +785,7 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -712,6 +814,7 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -726,6 +829,7 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -738,8 +842,10 @@ namespace libtorrent { INVARIANT_CHECK; + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + assert(ratio >= 0.f); - if (ratio < 1.f && ratio > 0.f) ratio = 1.f; @@ -752,6 +858,10 @@ namespace libtorrent void torrent_handle::resolve_countries(bool r) { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); find_torrent(m_ses, m_chk, m_info_hash)->resolve_countries(r); @@ -760,6 +870,10 @@ namespace libtorrent bool torrent_handle::resolve_countries() const { INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex); return find_torrent(m_ses, m_chk, m_info_hash)->resolving_countries(); @@ -770,8 +884,10 @@ namespace libtorrent { INVARIANT_CHECK; - v.clear(); if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); + + v.clear(); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); @@ -803,6 +919,7 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); + assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); diff --git a/libtorrent/src/tracker_manager.cpp b/libtorrent/src/tracker_manager.cpp index 358ac3838..981eb4caf 100755 --- a/libtorrent/src/tracker_manager.cpp +++ b/libtorrent/src/tracker_manager.cpp @@ -365,23 +365,22 @@ namespace libtorrent , m_req(req) {} - request_callback& tracker_connection::requester() + boost::shared_ptr tracker_connection::requester() { - boost::shared_ptr r = m_requester.lock(); - assert(r); - return *r; + return m_requester.lock(); } void tracker_connection::fail(int code, char const* msg) { - if (has_requester()) requester().tracker_request_error( - m_req, code, msg); + boost::shared_ptr cb = requester(); + if (cb) cb->tracker_request_error(m_req, code, msg); close(); } void tracker_connection::fail_timeout() { - if (has_requester()) requester().tracker_request_timed_out(m_req); + boost::shared_ptr cb = requester(); + if (cb) cb->tracker_request_timed_out(m_req); close(); } @@ -548,7 +547,8 @@ namespace libtorrent m_connections.push_back(con); - if (con->has_requester()) con->requester().m_manager = this; + boost::shared_ptr cb = con->requester(); + if (cb) cb->m_manager = this; } catch (std::exception& e) { diff --git a/libtorrent/src/udp_tracker_connection.cpp b/libtorrent/src/udp_tracker_connection.cpp index d08abd359..cd500d98c 100755 --- a/libtorrent/src/udp_tracker_connection.cpp +++ b/libtorrent/src/udp_tracker_connection.cpp @@ -110,8 +110,9 @@ namespace libtorrent return; } + boost::shared_ptr cb = requester(); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("udp tracker name lookup successful"); + if (cb) cb->debug_log("udp tracker name lookup successful"); #endif restart_read_timeout(); @@ -126,11 +127,11 @@ namespace libtorrent if (target == end) { assert(target_address.address().is_v4() != bind_interface().is_v4()); - if (has_requester()) + if (cb) { std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6"; std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6"; - requester().tracker_warning("the tracker only resolves to an " + cb->tracker_warning("the tracker only resolves to an " + tracker_address_type + " address, and you're listening on an " + bind_address_type + " socket. This may prevent you from receiving incoming connections."); } @@ -140,7 +141,7 @@ namespace libtorrent target_address = *target; } - if (has_requester()) requester().m_tracker_address = tcp::endpoint(target_address.address(), target_address.port()); + if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port()); m_target = target_address; m_socket.reset(new datagram_socket(m_name_lookup.io_service())); m_socket->open(target_address.protocol()); @@ -163,9 +164,10 @@ namespace libtorrent void udp_tracker_connection::send_udp_connect() { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) + boost::shared_ptr cb = requester(); + if (cb) { - requester().debug_log("==> UDP_TRACKER_CONNECT [" + cb->debug_log("==> UDP_TRACKER_CONNECT [" + lexical_cast(tracker_req().info_hash) + "]"); } #endif @@ -259,9 +261,10 @@ namespace libtorrent m_connection_id = detail::read_int64(ptr); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) + boost::shared_ptr cb = requester(); + if (cb) { - requester().debug_log("<== UDP_TRACKER_CONNECT_RESPONSE [" + cb->debug_log("<== UDP_TRACKER_CONNECT_RESPONSE [" + lexical_cast(m_connection_id) + "]"); } #endif @@ -321,9 +324,10 @@ namespace libtorrent detail::write_uint16(0, out); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) + boost::shared_ptr cb = requester(); + if (cb) { - requester().debug_log("==> UDP_TRACKER_ANNOUNCE [" + cb->debug_log("==> UDP_TRACKER_ANNOUNCE [" + lexical_cast(req.info_hash) + "]"); } #endif @@ -431,14 +435,15 @@ namespace libtorrent return; } + boost::shared_ptr cb = requester(); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) + if (cb) { - requester().debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE"); + cb->debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE"); } #endif - if (!has_requester()) + if (!cb) { m_man.remove_request(this); return; @@ -459,7 +464,7 @@ namespace libtorrent peer_list.push_back(e); } - requester().tracker_response(tracker_req(), peer_list, interval + cb->tracker_response(tracker_req(), peer_list, interval , complete, incomplete); m_man.remove_request(this); @@ -534,14 +539,15 @@ namespace libtorrent /*int downloaded = */detail::read_int32(buf); int incomplete = detail::read_int32(buf); - if (!has_requester()) + boost::shared_ptr cb = requester(); + if (!cb) { m_man.remove_request(this); return; } std::vector peer_list; - requester().tracker_response(tracker_req(), peer_list, 0 + cb->tracker_response(tracker_req(), peer_list, 0 , complete, incomplete); m_man.remove_request(this); diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index 33168c2bd..87f950b48 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -997,4 +997,3 @@ void upnp::close() } } - diff --git a/libtorrent/src/ut_pex.cpp b/libtorrent/src/ut_pex.cpp index 18cbf6c2f..18fe715ee 100644 --- a/libtorrent/src/ut_pex.cpp +++ b/libtorrent/src/ut_pex.cpp @@ -67,8 +67,6 @@ namespace libtorrent { namespace if (!p.is_local()) return false; // don't send out peers that we haven't successfully connected to if (p.is_connecting()) return false; - // ut pex does not support IPv6 - if (!p.remote().address().is_v4()) return false; return true; } @@ -98,9 +96,15 @@ namespace libtorrent { namespace std::string& pla = pex["added"].string(); std::string& pld = pex["dropped"].string(); std::string& plf = pex["added.f"].string(); + std::string& pla6 = pex["added6"].string(); + std::string& pld6 = pex["dropped6"].string(); + std::string& plf6 = pex["added6.f"].string(); std::back_insert_iterator pla_out(pla); std::back_insert_iterator pld_out(pld); std::back_insert_iterator plf_out(plf); + std::back_insert_iterator pla6_out(pla6); + std::back_insert_iterator pld6_out(pld6); + std::back_insert_iterator plf6_out(plf6); std::set dropped; m_old_peers.swap(dropped); @@ -123,8 +127,6 @@ namespace libtorrent { namespace bt_peer_connection* p = dynamic_cast(i->second); if (!p) continue; - // i->first was added since the last time - detail::write_endpoint(i->first, pla_out); // no supported flags to set yet // 0x01 - peer supports encryption // 0x02 - peer is a seed @@ -132,7 +134,17 @@ namespace libtorrent { namespace #ifndef TORRENT_DISABLE_ENCRYPTION flags |= p->supports_encryption() ? 1 : 0; #endif - detail::write_uint8(flags, plf_out); + // i->first was added since the last time + if (i->first.address().is_v4()) + { + detail::write_endpoint(i->first, pla_out); + detail::write_uint8(flags, plf_out); + } + else + { + detail::write_endpoint(i->first, pla6_out); + detail::write_uint8(flags, plf6_out); + } ++num_added; } else @@ -146,8 +158,10 @@ namespace libtorrent { namespace for (std::set::const_iterator i = dropped.begin() , end(dropped.end());i != end; ++i) { - if (!i->address().is_v4()) continue; - detail::write_endpoint(*i, pld_out); + if (i->address().is_v4()) + detail::write_endpoint(*i, pld_out); + else + detail::write_endpoint(*i, pld6_out); } m_ut_pex_msg.clear(); @@ -227,6 +241,28 @@ namespace libtorrent { namespace char flags = detail::read_uint8(fin); p.peer_from_tracker(adr, pid, peer_info::pex, flags); } + + if (entry const* p6 = pex_msg.find_key("added6")) + { + std::string const& peers6 = p6->string(); + std::string const& peer6_flags = pex_msg["added6.f"].string(); + + int num_peers = peers6.length() / 18; + char const* in = peers6.c_str(); + char const* fin = peer6_flags.c_str(); + + if (int(peer6_flags.size()) != num_peers) + return true; + + peer_id pid(0); + policy& p = m_torrent.get_policy(); + for (int i = 0; i < num_peers; ++i) + { + tcp::endpoint adr = detail::read_v6_endpoint(in); + char flags = detail::read_uint8(fin); + p.peer_from_tracker(adr, pid, peer_info::pex, flags); + } + } } catch (std::exception&) { @@ -279,8 +315,13 @@ namespace libtorrent { namespace pex["dropped"].string(); std::string& pla = pex["added"].string(); std::string& plf = pex["added.f"].string(); + pex["dropped6"].string(); + std::string& pla6 = pex["added6"].string(); + std::string& plf6 = pex["added6.f"].string(); std::back_insert_iterator pla_out(pla); std::back_insert_iterator plf_out(plf); + std::back_insert_iterator pla6_out(pla6); + std::back_insert_iterator plf6_out(plf6); int num_added = 0; for (torrent::peer_iterator i = m_torrent.begin() @@ -295,8 +336,6 @@ namespace libtorrent { namespace bt_peer_connection* p = dynamic_cast(i->second); if (!p) continue; - // i->first was added since the last time - detail::write_endpoint(i->first, pla_out); // no supported flags to set yet // 0x01 - peer supports encryption // 0x02 - peer is a seed @@ -304,7 +343,17 @@ namespace libtorrent { namespace #ifndef TORRENT_DISABLE_ENCRYPTION flags |= p->supports_encryption() ? 1 : 0; #endif - detail::write_uint8(flags, plf_out); + // i->first was added since the last time + if (i->first.address().is_v4()) + { + detail::write_endpoint(i->first, pla_out); + detail::write_uint8(flags, plf_out); + } + else + { + detail::write_endpoint(i->first, pla6_out); + detail::write_uint8(flags, plf6_out); + } ++num_added; } std::vector pex_msg; @@ -347,7 +396,7 @@ namespace libtorrent { namespace namespace libtorrent { - boost::shared_ptr create_ut_pex_plugin(torrent* t) + boost::shared_ptr create_ut_pex_plugin(torrent* t, void*) { if (t->torrent_file().priv()) {