diff --git a/src/ip_voter.cpp b/src/ip_voter.cpp index 21129ec0f..94ada6557 100644 --- a/src/ip_voter.cpp +++ b/src/ip_voter.cpp @@ -118,7 +118,9 @@ namespace libtorrent address external_ip::external_address(address const& ip) const { - return m_vote_group[ip.is_v6()].external_address(); + address ext = m_vote_group[ip.is_v6()].external_address(); + if (ip.is_v6() && ext == address_v4()) return address_v6(); + return ext; } } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 43ee3b7f8..7814a6dcd 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -4830,11 +4830,27 @@ retry: return boost::weak_ptr(); } + // returns true if lhs is a better disconnect candidate than rhs + bool compare_disconnect_torrent(session_impl::torrent_map::value_type const& lhs + , session_impl::torrent_map::value_type const& rhs) + { + // a torrent with 0 peers is never a good disconnect candidate + // since there's nothing to disconnect + if ((lhs.second->num_peers() == 0) != (lhs.second->num_peers() == 0)) + return lhs.second->num_peers() != 0; + + // other than that, always prefer to disconnect peers from seeding torrents + // in order to not harm downloading ones + if (lhs.second->is_seed() != rhs.second->is_seed()) + return lhs.second->is_seed(); + + return lhs.second->num_peers() > rhs.second->num_peers(); + } + boost::weak_ptr session_impl::find_disconnect_candidate_torrent() { - aux::session_impl::torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end() - , boost::bind(&torrent::num_peers, boost::bind(&session_impl::torrent_map::value_type::second, _1)) - < boost::bind(&torrent::num_peers, boost::bind(&session_impl::torrent_map::value_type::second, _2))); + aux::session_impl::torrent_map::iterator i = std::min_element(m_torrents.begin(), m_torrents.end() + , boost::bind(&compare_disconnect_torrent, _1, _2)); TORRENT_ASSERT(i != m_torrents.end()); if (i == m_torrents.end()) return boost::shared_ptr(); diff --git a/src/torrent.cpp b/src/torrent.cpp index 6ddd3e478..b20be387e 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -4328,7 +4328,8 @@ namespace libtorrent if (ready_for_connections()) { - TORRENT_ASSERT(p->associated_torrent().lock().get() == this); + TORRENT_ASSERT(p->associated_torrent().lock().get() == NULL + || p->associated_torrent().lock().get() == this); if (p->is_seed()) { @@ -5890,6 +5891,8 @@ namespace libtorrent return false; } + bool maybe_replace_peer = false; + if (m_connections.size() >= m_max_connections) { // if more than 10% of the connections are outgoing @@ -5923,21 +5926,7 @@ namespace libtorrent } else { - // now, find the lowest rank peer and disconnect that - // if it's lower rank than the incoming connection - peer_connection* peer = find_lowest_ranking_peer(); - - // TODO: if peer is a really good peer, maybe we shouldn't disconnect it - if (peer && peer->peer_rank() < p->peer_rank()) - { - peer->disconnect(errors::too_many_connections); - p->peer_disconnected_other(); - } - else - { - p->disconnect(errors::too_many_connections); - return false; - } + maybe_replace_peer = true; } } @@ -5979,6 +5968,34 @@ namespace libtorrent TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec); #endif + TORRENT_ASSERT(p->peer_info_struct() != NULL); + + // we need to do this after we've added the peer to the policy + // since that's when the peer is assigned its peer_info object, + // which holds the rank + if (maybe_replace_peer) + { + // now, find the lowest rank peer and disconnect that + // if it's lower rank than the incoming connection + peer_connection* peer = find_lowest_ranking_peer(); + + // TODO: if peer is a really good peer, maybe we shouldn't disconnect it + if (peer && peer->peer_rank() < p->peer_rank()) + { + peer->disconnect(errors::too_many_connections); + p->peer_disconnected_other(); + } + else + { + p->disconnect(errors::too_many_connections); + // we have to do this here because from the peer's point of + // it wasn't really attached to the torrent, but we do need + // to let policy know we're removing it + remove_peer(p); + return false; + } + } + #if defined TORRENT_DEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS m_policy.check_invariant(); #endif