diff --git a/ChangeLog b/ChangeLog index c496367c6..acdfb3d72 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * fix issue where num_seeds could be greater than num_peers in torrent_status * finished non-seed torrents can also be in super-seeding mode * fix issue related to unloading torrents * fixed finished-time calculation diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 9c9e33076..d5f6a305e 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -1110,12 +1110,26 @@ namespace libtorrent void inc_refcount(char const* purpose); int refcount() const { return m_refcount; } - void inc_num_connecting() - { ++m_num_connecting; } - void dec_num_connecting() + void inc_num_connecting(torrent_peer* pp) + { + ++m_num_connecting; + TORRENT_ASSERT(m_num_connecting <= int(m_connections.size())); + if (pp->seed) + { + ++m_num_connecting_seeds; + TORRENT_ASSERT(m_num_connecting_seeds <= int(m_connections.size())); + } + } + void dec_num_connecting(torrent_peer* pp) { TORRENT_ASSERT(m_num_connecting > 0); --m_num_connecting; + if (pp->seed) + { + TORRENT_ASSERT(m_num_connecting_seeds > 0); + --m_num_connecting_seeds; + } + TORRENT_ASSERT(m_num_connecting <= int(m_connections.size())); } bool is_ssl_torrent() const { return m_ssl_torrent; } @@ -1127,7 +1141,7 @@ namespace libtorrent void set_ssl_cert_buffer(std::string const& certificate , std::string const& private_key , std::string const& dh_params); - boost::asio::ssl::context* ssl_ctx() const { return m_ssl_ctx.get(); } + boost::asio::ssl::context* ssl_ctx() const { return m_ssl_ctx.get(); } #endif int num_time_critical_pieces() const @@ -1646,6 +1660,10 @@ namespace libtorrent // counting the peer connections that say true for is_seed() boost::uint16_t m_num_seeds; + // this is the number of peers that are seeds, and count against + // m_num_seeds, but have not yet been connected + boost::uint16_t m_num_connecting_seeds; + // the timestamp of the last byte uploaded from this torrent specified in // session_time. This is signed because it must be able to represent time // before the session started. diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index d3b40967e..5bd8fa46a 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -208,7 +208,6 @@ namespace libtorrent // if t is NULL, we better not be connecting, since // we can't decrement the connecting counter TORRENT_ASSERT(t || !m_connecting); - if (m_connecting && t) t->inc_num_connecting(); m_est_reciprocation_rate = m_settings.get_int(settings_pack::default_est_reciprocation_rate); m_channel_state[upload_channel] = peer_info::bw_idle; @@ -369,6 +368,8 @@ namespace libtorrent // if this is an incoming connection, we're done here if (!m_connecting) return; + if (m_connecting && t) t->inc_num_connecting(m_peer_info); + #ifndef TORRENT_DISABLE_LOGGING peer_log(peer_log_alert::outgoing, "OPEN", "protocol: %s" , (m_remote.address().is_v4()?"IPv4":"IPv6")); @@ -820,7 +821,7 @@ namespace libtorrent if (m_connecting) { m_counters.inc_stats_counter(counters::num_peers_half_open, -1); - if (t) t->dec_num_connecting(); + if (t) t->dec_num_connecting(m_peer_info); m_connecting = false; } @@ -4014,7 +4015,7 @@ namespace libtorrent if (m_connecting) { m_counters.inc_stats_counter(counters::num_peers_half_open, -1); - if (t) t->dec_num_connecting(); + if (t) t->dec_num_connecting(m_peer_info); m_connecting = false; } @@ -4228,7 +4229,7 @@ namespace libtorrent if (m_connecting) { m_counters.inc_stats_counter(counters::num_peers_half_open, -1); - if (t) t->dec_num_connecting(); + if (t) t->dec_num_connecting(m_peer_info); m_connecting = false; } @@ -4730,7 +4731,7 @@ namespace libtorrent if (m_connecting) { m_counters.inc_stats_counter(counters::num_peers_half_open, -1); - if (t) t->dec_num_connecting(); + if (t) t->dec_num_connecting(m_peer_info); m_connecting = false; } disconnect(errors::torrent_aborted, op_bittorrent); @@ -6330,7 +6331,7 @@ namespace libtorrent if (m_connecting) { m_counters.inc_stats_counter(counters::num_peers_half_open, -1); - if (t) t->dec_num_connecting(); + if (t) t->dec_num_connecting(m_peer_info); m_connecting = false; } @@ -6358,7 +6359,7 @@ namespace libtorrent } // if there are outgoing interfaces specified, verify this - // peer is correctly bound to on of them + // peer is correctly bound to one of them if (!m_settings.get_str(settings_pack::outgoing_interfaces).empty()) { if (!m_ses.verify_bound_address(m_local.address() diff --git a/src/torrent.cpp b/src/torrent.cpp index a3ba94ea3..0dc816308 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -269,6 +269,7 @@ namespace libtorrent , m_should_be_loaded(true) , m_last_download((std::numeric_limits::min)()) , m_num_seeds(0) + , m_num_connecting_seeds(0) , m_last_upload((std::numeric_limits::min)()) , m_storage_tick(0) , m_auto_managed(p.flags & add_torrent_params::flag_auto_managed) @@ -3662,7 +3663,7 @@ namespace libtorrent return; } - if (int(m_connections.size()) - m_num_connecting < 10) + if (int(m_connections.size() - m_num_connecting) < 10) { // there are too few peers. Be conservative and don't assume it's // well seeded until we can connect to more peers @@ -3673,8 +3674,8 @@ namespace libtorrent // if there are at least 10 seeds, and there are 10 times more // seeds than downloaders, enter sequential download mode // (for performance) - int downloaders = num_downloaders(); - int seeds = num_seeds(); + int const downloaders = num_downloaders(); + int const seeds = num_seeds(); m_auto_sequential = downloaders * 10 <= seeds && seeds > 9; } @@ -9063,6 +9064,8 @@ namespace libtorrent int seeds = 0; int num_uploads = 0; + int num_connecting = 0; + int num_connecting_seeds = 0; std::map num_requests; for (const_peer_iterator i = this->begin(); i != this->end(); ++i) { @@ -9072,6 +9075,11 @@ namespace libtorrent #endif peer_connection const& p = *(*i); + if (p.is_connecting()) ++num_connecting; + + if (p.is_connecting() && p.peer_info_struct()->seed) + ++num_connecting_seeds; + if (p.peer_info_struct() && p.peer_info_struct()->seed) ++seeds; @@ -9094,6 +9102,14 @@ namespace libtorrent } TORRENT_ASSERT(num_uploads == int(m_num_uploads)); TORRENT_ASSERT(seeds == int(m_num_seeds)); + TORRENT_ASSERT(num_connecting == int(m_num_connecting)); + TORRENT_ASSERT(num_connecting_seeds == int(m_num_connecting_seeds)); + TORRENT_ASSERT(int(m_num_uploads) <= int(m_connections.size())); + TORRENT_ASSERT(int(m_num_seeds) <= int(m_connections.size())); + TORRENT_ASSERT(int(m_num_connecting) <= int(m_connections.size())); + TORRENT_ASSERT(int(m_num_connecting_seeds) <= int(m_connections.size())); + TORRENT_ASSERT(int(m_num_connecting) + int(m_num_seeds) >= int(m_num_connecting_seeds)); + TORRENT_ASSERT(int(m_num_connecting) + int(m_num_seeds) - int(m_num_connecting_seeds) <= int(m_connections.size())); if (has_picker()) { @@ -12244,20 +12260,27 @@ namespace libtorrent m_stats_counters.inc_stats_counter(counters::recv_failed_bytes, b); } + // the number of connected peers that are seeds int torrent::num_seeds() const { TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; - return m_num_seeds; + return int(m_num_seeds) - int(m_num_connecting_seeds); } + // the number of connected peers that are not seeds int torrent::num_downloaders() const { TORRENT_ASSERT(is_single_thread()); INVARIANT_CHECK; - return (std::max)(0, int(m_connections.size()) - m_num_seeds - m_num_connecting); + int const ret = int(m_connections.size()) + - m_num_seeds + - m_num_connecting + + m_num_connecting_seeds; + TORRENT_ASSERT(ret >= 0); + return ret; } void torrent::tracker_request_error(tracker_request const& r