forked from premiere/premiere-libtorrent
when reaching peer list size limit, rank peers to be removed. Fix for updating IP filter
This commit is contained in:
parent
a14bc56520
commit
136f101449
|
@ -282,7 +282,7 @@ namespace libtorrent
|
|||
|
||||
struct peer_ptr_compare
|
||||
{
|
||||
bool operator()(peer* lhs, peer* rhs) const
|
||||
bool operator()(peer const* lhs, peer const* rhs) const
|
||||
{ return lhs->address() < rhs->address(); }
|
||||
};
|
||||
|
||||
|
@ -294,12 +294,19 @@ namespace libtorrent
|
|||
iterator end_peer() { return m_peers.end(); }
|
||||
const_iterator begin_peer() const { return m_peers.begin(); }
|
||||
const_iterator end_peer() const { return m_peers.end(); }
|
||||
|
||||
std::pair<iterator, iterator> find_peers(address const& a)
|
||||
{
|
||||
peer tmp(a);
|
||||
peer_ptr_compare cmp;
|
||||
return std::equal_range(m_peers.begin(), m_peers.end()
|
||||
, &tmp, cmp);
|
||||
return std::equal_range(m_peers.begin(), m_peers.end(), &tmp, cmp);
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> find_peers(address const& a) const
|
||||
{
|
||||
peer tmp(a);
|
||||
peer_ptr_compare cmp;
|
||||
return std::equal_range(m_peers.begin(), m_peers.end(), &tmp, cmp);
|
||||
}
|
||||
|
||||
bool connect_one_peer(int session_time);
|
||||
|
@ -310,16 +317,22 @@ namespace libtorrent
|
|||
int num_connect_candidates() const { return m_num_connect_candidates; }
|
||||
void recalculate_connect_candidates();
|
||||
|
||||
void erase_peer(policy::peer* p);
|
||||
void erase_peer(iterator i);
|
||||
|
||||
private:
|
||||
|
||||
bool compare_peer_erase(policy::peer const& lhs, policy::peer const& rhs) const;
|
||||
bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||
, address const& external_ip) const;
|
||||
|
||||
iterator find_connect_candidate(int session_time);
|
||||
|
||||
bool is_connect_candidate(peer const& p, bool finished);
|
||||
bool is_connect_candidate(peer const& p, bool finished) const;
|
||||
bool is_erase_candidate(peer const& p, bool finished) const;
|
||||
bool should_erase_immediately(peer const& p) const;
|
||||
|
||||
void erase_peers();
|
||||
|
||||
peers_t m_peers;
|
||||
|
||||
|
|
194
src/policy.cpp
194
src/policy.cpp
|
@ -357,8 +357,8 @@ namespace libtorrent
|
|||
{
|
||||
aux::session_impl& ses = m_torrent->session();
|
||||
piece_picker* p = 0;
|
||||
if (m_torrent->has_picker())
|
||||
p = &m_torrent->picker();
|
||||
if (m_torrent->has_picker()) p = &m_torrent->picker();
|
||||
|
||||
for (iterator i = m_peers.begin(); i != m_peers.end();)
|
||||
{
|
||||
if ((ses.m_ip_filter.access((*i)->address()) & ip_filter::blocked) == 0)
|
||||
|
@ -380,10 +380,22 @@ namespace libtorrent
|
|||
if (ses.m_alerts.should_post<peer_blocked_alert>())
|
||||
ses.m_alerts.post_alert(peer_blocked_alert((*i)->address()));
|
||||
}
|
||||
erase_peer(i++);
|
||||
int current = i - m_peers.begin();
|
||||
erase_peer(i);
|
||||
i = m_peers.begin() + current;
|
||||
}
|
||||
}
|
||||
|
||||
void policy::erase_peer(policy::peer* p)
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
std::pair<iterator, iterator> range = find_peers(p->address());
|
||||
iterator iter = std::find_if(range.first, range.second, match_peer_endpoint(p->ip()));
|
||||
if (iter == range.second) return;
|
||||
erase_peer(iter);
|
||||
}
|
||||
|
||||
// any peer that is erased from m_peers will be
|
||||
// erased through this function. This way we can make
|
||||
// sure that any references to the peer are removed
|
||||
|
@ -405,7 +417,72 @@ namespace libtorrent
|
|||
m_peers.erase(i);
|
||||
}
|
||||
|
||||
bool policy::is_connect_candidate(peer const& p, bool finished)
|
||||
bool policy::should_erase_immediately(peer const& p) const
|
||||
{
|
||||
return p.source == peer_info::resume_data
|
||||
&& p.failcount > 0
|
||||
&& !p.banned;
|
||||
}
|
||||
|
||||
bool policy::is_erase_candidate(peer const& pe, bool finished) const
|
||||
{
|
||||
return pe.connection == 0
|
||||
&& pe.last_connected != 0
|
||||
&& !pe.banned
|
||||
&& !is_connect_candidate(pe, m_finished)
|
||||
&& m_peers.size() >= m_torrent->settings().max_peerlist_size * 0.95
|
||||
&& m_torrent->settings().max_peerlist_size > 0;
|
||||
}
|
||||
|
||||
void policy::erase_peers()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
if (m_torrent->settings().max_peerlist_size == 0
|
||||
|| m_peers.empty()) return;
|
||||
|
||||
int erase_candidate = -1;
|
||||
|
||||
TORRENT_ASSERT(m_finished == m_torrent->is_finished());
|
||||
|
||||
int round_robin = rand() % m_peers.size();
|
||||
|
||||
for (int iterations = (std::min)(int(m_peers.size()), 300);
|
||||
iterations > 0; --iterations)
|
||||
{
|
||||
if (m_peers.size() < m_torrent->settings().max_peerlist_size * 0.95)
|
||||
break;
|
||||
|
||||
if (round_robin == m_peers.size()) round_robin = 0;
|
||||
|
||||
peer& pe = *m_peers[round_robin];
|
||||
int current = round_robin;
|
||||
|
||||
{
|
||||
if (is_erase_candidate(pe, m_finished)
|
||||
&& (erase_candidate == -1
|
||||
|| !compare_peer_erase(*m_peers[erase_candidate], pe)))
|
||||
{
|
||||
if (should_erase_immediately(pe))
|
||||
{
|
||||
if (erase_candidate > current) --erase_candidate;
|
||||
erase_peer(m_peers.begin() + current);
|
||||
}
|
||||
else
|
||||
{
|
||||
erase_candidate = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++round_robin;
|
||||
}
|
||||
|
||||
if (erase_candidate > -1)
|
||||
erase_peer(m_peers.begin() + erase_candidate);
|
||||
}
|
||||
|
||||
bool policy::is_connect_candidate(peer const& p, bool finished) const
|
||||
{
|
||||
if (p.connection
|
||||
|| p.banned
|
||||
|
@ -414,7 +491,7 @@ namespace libtorrent
|
|||
|| p.failcount >= m_torrent->settings().max_failcount)
|
||||
return false;
|
||||
|
||||
aux::session_impl& ses = m_torrent->session();
|
||||
aux::session_impl const& ses = m_torrent->session();
|
||||
if (ses.m_port_filter.access(p.port) & port_filter::blocked)
|
||||
return false;
|
||||
return true;
|
||||
|
@ -425,6 +502,7 @@ namespace libtorrent
|
|||
INVARIANT_CHECK;
|
||||
|
||||
int candidate = -1;
|
||||
int erase_candidate = -1;
|
||||
|
||||
TORRENT_ASSERT(m_finished == m_torrent->is_finished());
|
||||
|
||||
|
@ -470,22 +548,25 @@ namespace libtorrent
|
|||
#endif
|
||||
// if the number of peers is growing large
|
||||
// we need to start weeding.
|
||||
// don't remove peers we're connected to
|
||||
// don't remove peers we've never even tried
|
||||
// don't remove banned peers unless they're 2
|
||||
// hours old. They should remain banned for
|
||||
// at least that long
|
||||
// don't remove peers that we still can try again
|
||||
if (pe.connection == 0
|
||||
&& pe.last_connected != 0
|
||||
&& (!pe.banned || session_time - pe.last_connected > 2 * 60 * 60)
|
||||
&& !is_connect_candidate(pe, m_finished)
|
||||
&& m_peers.size() >= m_torrent->settings().max_peerlist_size * 0.9
|
||||
|
||||
if (m_peers.size() >= m_torrent->settings().max_peerlist_size * 0.95
|
||||
&& m_torrent->settings().max_peerlist_size > 0)
|
||||
{
|
||||
if (candidate > m_round_robin) --candidate;
|
||||
erase_peer(m_peers.begin() + m_round_robin);
|
||||
continue;
|
||||
if (is_erase_candidate(pe, m_finished)
|
||||
&& (erase_candidate == -1
|
||||
|| !compare_peer_erase(*m_peers[erase_candidate], pe)))
|
||||
{
|
||||
if (should_erase_immediately(pe))
|
||||
{
|
||||
if (erase_candidate > current) --erase_candidate;
|
||||
if (candidate > current) --candidate;
|
||||
erase_peer(m_peers.begin() + current);
|
||||
}
|
||||
else
|
||||
{
|
||||
erase_candidate = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++m_round_robin;
|
||||
|
@ -507,6 +588,12 @@ namespace libtorrent
|
|||
candidate = current;
|
||||
}
|
||||
|
||||
if (erase_candidate > -1)
|
||||
{
|
||||
if (candidate > erase_candidate) --candidate;
|
||||
erase_peer(m_peers.begin() + erase_candidate);
|
||||
}
|
||||
|
||||
#if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING
|
||||
if (candidate != -1)
|
||||
{
|
||||
|
@ -558,6 +645,8 @@ namespace libtorrent
|
|||
, m_torrent->end()
|
||||
, m_available_free_upload);
|
||||
}
|
||||
|
||||
erase_peers();
|
||||
}
|
||||
|
||||
bool policy::new_connection(peer_connection& c, int session_time)
|
||||
|
@ -691,6 +780,7 @@ namespace libtorrent
|
|||
|
||||
if (m_round_robin > iter - m_peers.begin()) ++m_round_robin;
|
||||
peer* p = m_torrent->session().m_peer_pool.malloc();
|
||||
if (p == 0) return false;
|
||||
m_torrent->session().m_peer_pool.set_next_size(500);
|
||||
new (p) peer(c.remote(), false, 0);
|
||||
iter = m_peers.insert(iter, p);
|
||||
|
@ -792,6 +882,16 @@ namespace libtorrent
|
|||
return 0;
|
||||
}
|
||||
|
||||
// if the IP is blocked, don't add it
|
||||
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
|
||||
{
|
||||
if (ses.m_alerts.should_post<peer_blocked_alert>())
|
||||
{
|
||||
ses.m_alerts.post_alert(peer_blocked_alert(remote.address()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
iterator iter;
|
||||
peer* i = 0;
|
||||
|
||||
|
@ -813,25 +913,29 @@ namespace libtorrent
|
|||
|
||||
if (!found)
|
||||
{
|
||||
// if the IP is blocked, don't add it
|
||||
if (ses.m_ip_filter.access(remote.address()) & ip_filter::blocked)
|
||||
{
|
||||
if (ses.m_alerts.should_post<peer_blocked_alert>())
|
||||
{
|
||||
ses.m_alerts.post_alert(peer_blocked_alert(remote.address()));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (m_torrent->settings().max_peerlist_size
|
||||
&& int(m_peers.size()) >= m_torrent->settings().max_peerlist_size)
|
||||
return 0;
|
||||
{
|
||||
if (src == peer_info::resume_data) return 0;
|
||||
|
||||
erase_peers();
|
||||
if (int(m_peers.size()) >= m_torrent->settings().max_peerlist_size)
|
||||
return 0;
|
||||
|
||||
// since some peers were removed, we need to
|
||||
// update the iterator to make it valid again
|
||||
peer tmp(remote.address());
|
||||
peer_ptr_compare cmp;
|
||||
iter = std::lower_bound(m_peers.begin(), m_peers.end()
|
||||
, &tmp, cmp);
|
||||
}
|
||||
|
||||
if (m_round_robin > iter - m_peers.begin()) ++m_round_robin;
|
||||
|
||||
// we don't have any info about this peer.
|
||||
// add a new entry
|
||||
peer* p = m_torrent->session().m_peer_pool.malloc();
|
||||
if (p == 0) return 0;
|
||||
m_torrent->session().m_peer_pool.set_next_size(500);
|
||||
new (p) peer(remote, true, src);
|
||||
iter = m_peers.insert(iter, p);
|
||||
|
@ -1108,6 +1212,17 @@ namespace libtorrent
|
|||
TORRENT_ASSERT(p->prev_amount_download == 0);
|
||||
p->prev_amount_download += c.statistics().total_payload_download();
|
||||
p->prev_amount_upload += c.statistics().total_payload_upload();
|
||||
|
||||
// if we're already a seed, it's not as important
|
||||
// to keep all the possibly stale peers
|
||||
// if we're not a seed, but we have too many peers
|
||||
// start weeding the ones we only know from resume
|
||||
// data first
|
||||
if (m_torrent->is_seed() || m_peers.size() >= m_torrent->settings().max_peerlist_size * 0.9)
|
||||
{
|
||||
if (p->source == peer_info::resume_data)
|
||||
erase_peer(p);
|
||||
}
|
||||
}
|
||||
|
||||
void policy::peer_is_interesting(peer_connection& c)
|
||||
|
@ -1184,10 +1299,7 @@ namespace libtorrent
|
|||
#endif
|
||||
if (!m_torrent->settings().allow_multiple_connections_per_ip)
|
||||
{
|
||||
peer tmp(p.address());
|
||||
peer_ptr_compare cmp;
|
||||
std::pair<const_iterator, const_iterator> range = std::equal_range(
|
||||
m_peers.begin(), m_peers.end(), &tmp, cmp);
|
||||
std::pair<const_iterator, const_iterator> range = find_peers(p.address());
|
||||
TORRENT_ASSERT(range.second - range.first == 1);
|
||||
}
|
||||
else
|
||||
|
@ -1356,6 +1468,20 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
// this returns true if lhs is a better erase candidate than rhs
|
||||
bool policy::compare_peer_erase(policy::peer const& lhs, policy::peer const& rhs) const
|
||||
{
|
||||
bool lhs_resume_data_source = lhs.source == peer_info::resume_data;
|
||||
bool rhs_resume_data_source = rhs.source == peer_info::resume_data;
|
||||
|
||||
// prefer to drop peers whose only source is resume data
|
||||
if (lhs_resume_data_source != rhs_resume_data_source)
|
||||
return lhs_resume_data_source > rhs_resume_data_source;
|
||||
|
||||
// prefer peers with higher failcount
|
||||
return lhs.failcount > rhs.failcount;
|
||||
}
|
||||
|
||||
// this returns true if lhs is a better connect candidate than rhs
|
||||
bool policy::compare_peer(policy::peer const& lhs, policy::peer const& rhs
|
||||
, address const& external_ip) const
|
||||
|
|
|
@ -1544,6 +1544,8 @@ namespace aux {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// m_peer_pool.release_memory();
|
||||
}
|
||||
|
||||
namespace
|
||||
|
|
Loading…
Reference in New Issue