diff --git a/ChangeLog b/ChangeLog index 944b1e229..60770eb9a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -62,6 +62,7 @@ release 0.14.5 * fixed bug when setting unlimited upload or download rates for torrents * fix to make torrent_status::list_peers more accurate. * fixed memory leak in disk io thread when not using the cache + * fixed bug in connect candidate counter release 0.14.4 diff --git a/include/libtorrent/policy.hpp b/include/libtorrent/policy.hpp index 61ca97d12..545aca538 100644 --- a/include/libtorrent/policy.hpp +++ b/include/libtorrent/policy.hpp @@ -88,6 +88,8 @@ namespace libtorrent // the given connection was just closed void connection_closed(const peer_connection& c, int session_time); + void ban_peer(policy::peer* p); + // the peer has got at least one interesting piece void peer_is_interesting(peer_connection& c); diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 75d35adf3..eb695f3da 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -4247,7 +4247,8 @@ namespace libtorrent { // if the remote endpoint is the same as the local endpoint, we're connected // to ourselves - if (m_peer_info) m_peer_info->banned = true; + boost::shared_ptr t = m_torrent.lock(); + if (m_peer_info && t) t->get_policy().ban_peer(m_peer_info); disconnect(error_code(errors::self_connection, libtorrent_category), 1); return; } diff --git a/src/policy.cpp b/src/policy.cpp index b4b46cbe7..70cc24871 100644 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -408,7 +408,10 @@ namespace libtorrent m_torrent->picker().clear_peer(*i); if ((*i)->seed) --m_num_seeds; if (is_connect_candidate(**i, m_finished)) + { + TORRENT_ASSERT(m_num_connect_candidates > 0); --m_num_connect_candidates; + } if (m_round_robin > i - m_peers.begin()) --m_round_robin; #if TORRENT_USE_IPV6 @@ -488,6 +491,16 @@ namespace libtorrent erase_peer(m_peers.begin() + erase_candidate); } + void policy::ban_peer(policy::peer* p) + { + INVARIANT_CHECK; + + if (is_connect_candidate(*p, m_finished)) + --m_num_connect_candidates; + + p->banned = true; + } + bool policy::is_connect_candidate(peer const& p, bool finished) const { if (p.connection @@ -714,6 +727,8 @@ namespace libtorrent if (iter != m_peers.end() && (*iter)->address() == c.remote().address()) found = true; } + bool was_conn_cand = false; + if (found) { i = *iter; @@ -724,6 +739,8 @@ namespace libtorrent return false; } + was_conn_cand = is_connect_candidate(*i, m_finished); + if (i->connection != 0) { boost::shared_ptr other_socket @@ -772,9 +789,6 @@ namespace libtorrent i->connection->disconnect(error_code(errors::duplicate_peer_id, libtorrent_category)); } } - - if (m_num_connect_candidates > 0) - --m_num_connect_candidates; } else { @@ -836,6 +850,13 @@ namespace libtorrent TORRENT_ASSERT(i->connection); if (!c.fast_reconnect()) i->last_connected = session_time; + + if (was_conn_cand != is_connect_candidate(*i, m_finished)) + { + m_num_connect_candidates += was_conn_cand ? -1 : 1; + TORRENT_ASSERT(m_num_connect_candidates >= 0); + if (m_num_connect_candidates < 0) m_num_connect_candidates = 0; + } return true; } @@ -844,6 +865,8 @@ namespace libtorrent TORRENT_ASSERT(p != 0); TORRENT_ASSERT(p->connection); + INVARIANT_CHECK; + if (p->port == port) return true; if (m_torrent->settings().allow_multiple_connections_per_ip) @@ -857,7 +880,15 @@ namespace libtorrent policy::peer& pp = **i; if (pp.connection) { + bool was_conn_cand = is_connect_candidate(pp, m_finished); + // if we already have an entry with this + // new endpoint, disconnect this one + pp.connectable = true; + pp.source |= src; + if (!was_conn_cand && is_connect_candidate(pp, m_finished)) + ++m_num_connect_candidates; p->connection->disconnect(error_code(errors::duplicate_peer_id, libtorrent_category)); + erase_peer(p); return false; } erase_peer(i); @@ -879,6 +910,7 @@ namespace libtorrent if (was_conn_cand != is_connect_candidate(*p, m_finished)) { m_num_connect_candidates += was_conn_cand ? -1 : 1; + TORRENT_ASSERT(m_num_connect_candidates >= 0); if (m_num_connect_candidates < 0) m_num_connect_candidates = 0; } return true; @@ -899,7 +931,14 @@ namespace libtorrent { if (p == 0) return; if (p->seed == s) return; + bool was_conn_cand = is_connect_candidate(*p, m_finished); p->seed = s; + if (was_conn_cand && !is_connect_candidate(*p, m_finished)) + { + --m_num_connect_candidates; + if (m_num_connect_candidates < 0) m_num_connect_candidates = 0; + } + if (s) ++m_num_seeds; else --m_num_seeds; } @@ -1220,6 +1259,8 @@ namespace libtorrent { // failcount is a 5 bit value if (p.failcount < 31) ++p.failcount; + if (!is_connect_candidate(p, m_finished)) + --m_num_connect_candidates; return false; } TORRENT_ASSERT(p.connection); @@ -1308,10 +1349,12 @@ namespace libtorrent void policy::recalculate_connect_candidates() { - m_num_connect_candidates = 0; + INVARIANT_CHECK; + const bool is_finished = m_torrent->is_finished(); if (is_finished == m_finished) return; + m_num_connect_candidates = 0; m_finished = is_finished; for (const_iterator i = m_peers.begin(); i != m_peers.end(); ++i) @@ -1346,6 +1389,7 @@ namespace libtorrent int total_connections = 0; int nonempty_connections = 0; + int connect_candidates = 0; std::set unique_test; const_iterator prev = m_peers.end(); @@ -1362,6 +1406,7 @@ namespace libtorrent TORRENT_ASSERT((*prev)->address() < (*i)->address()); } peer const& p = **i; + if (is_connect_candidate(p, m_finished)) ++connect_candidates; #ifndef TORRENT_DISABLE_GEO_IP TORRENT_ASSERT(p.inet_as == 0 || p.inet_as->first == p.inet_as_num); #endif @@ -1395,6 +1440,8 @@ namespace libtorrent ++connected_peers; } + TORRENT_ASSERT(m_num_connect_candidates == connect_candidates); + int num_torrent_peers = 0; for (torrent::const_peer_iterator i = m_torrent->begin(); i != m_torrent->end(); ++i) diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 71dfbd744..c52d0eada 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -609,6 +609,7 @@ namespace aux { void session_impl::set_port_filter(port_filter const& f) { m_port_filter = f; + // TODO: recalculate all connect candidates for all torrents } void session_impl::set_ip_filter(ip_filter const& f) diff --git a/src/smart_ban.cpp b/src/smart_ban.cpp index d5e853c3d..cfc3ba80c 100644 --- a/src/smart_ban.cpp +++ b/src/smart_ban.cpp @@ -213,7 +213,7 @@ namespace libtorrent { namespace << " | crc2: " << e.crc << " | ip: " << p->ip() << " ]\n"; #endif - p->banned = true; + m_torrent.get_policy().ban_peer(p); if (p->connection) p->connection->disconnect( error_code(errors::peer_banned, libtorrent_category)); } @@ -276,7 +276,7 @@ namespace libtorrent { namespace << " | bad_crc: " << b.second.crc << " | ip: " << p->ip() << " ]\n"; #endif - p->banned = true; + m_torrent.get_policy().ban_peer(p); if (p->connection) p->connection->disconnect( error_code(errors::peer_banned, libtorrent_category)); } diff --git a/src/torrent.cpp b/src/torrent.cpp index 41c8653f0..17ed06600 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -718,7 +718,7 @@ namespace libtorrent { policy::peer* p = m_policy.add_peer(read_v4_endpoint(ptr) , id, peer_info::resume_data, 0); - if (p) p->banned = true; + if (p) m_policy.ban_peer(p); } } @@ -742,7 +742,7 @@ namespace libtorrent { policy::peer* p = m_policy.add_peer(read_v6_endpoint(ptr) , id, peer_info::resume_data, 0); - if (p) p->banned = true; + if (p) m_policy.ban_peer(p); } } #endif @@ -778,7 +778,7 @@ namespace libtorrent tcp::endpoint a(address::from_string(ip, ec), (unsigned short)port); if (ec) continue; policy::peer* p = m_policy.add_peer(a, id, peer_info::resume_data, 0); - if (p) p->banned = true; + if (p) m_policy.ban_peer(p); } } } @@ -1916,7 +1916,7 @@ namespace libtorrent } // mark the peer as banned - p->banned = true; + m_policy.ban_peer(p); if (p->connection) {