diff --git a/libtransmission/peer-mgr.c b/libtransmission/peer-mgr.c index b26d27633..6070b4dfb 100644 --- a/libtransmission/peer-mgr.c +++ b/libtransmission/peer-mgr.c @@ -1727,11 +1727,20 @@ shouldPeerBeClosed( const Torrent * t, const tr_peer * peer, int peerCount ) return TRUE; } - /* if we're both seeds and it's been long enough for a pex exchange, close it */ + /* if we're seeding and the peer has everything we have, + * and enough time has passed for a pex exchange, then disconnect */ if( 1 ) { const int clientIsSeed = tr_torrentIsSeed( tor ); - const int peerIsSeed = atom->flags & ADDED_F_SEED_FLAG; - if( peerIsSeed && clientIsSeed && ( !tr_torrentAllowsPex(tor) || (now-atom->time>=30) ) ) { + int peerHasEverything; + if( atom->flags & ADDED_F_SEED_FLAG ) + peerHasEverything = TRUE; + else { + tr_bitfield * tmp = tr_bitfieldDup( tr_cpPieceBitfield( tor->completion ) ); + tr_bitfieldDifference( tmp, peer->have ); + peerHasEverything = tr_bitfieldCountTrueBits( tmp ) == 0; + tr_bitfieldFree( tmp ); + } + if( clientIsSeed && peerHasEverything && ( !tr_torrentAllowsPex(tor) || (now-atom->time>=30) ) ) { tordbg( t, "purging peer %s because we're both seeds", tr_peerIoAddrStr(&atom->addr,atom->port) ); return TRUE; } diff --git a/libtransmission/utils.c b/libtransmission/utils.c index f804b962c..5a593ee1b 100644 --- a/libtransmission/utils.c +++ b/libtransmission/utils.c @@ -783,6 +783,20 @@ tr_bitfieldOr( tr_bitfield * a, const tr_bitfield * b ) return a; } +/* set 'a' to all the flags that were in 'a' but not 'b' */ +void +tr_bitfieldDifference( tr_bitfield * a, const tr_bitfield * b ) +{ + uint8_t *ait; + const uint8_t *aend, *bit; + + assert( a->len == b->len ); + + for( ait=a->bits, bit=b->bits, aend=ait+a->len; ait!=aend; ) + *ait++ &= ~(*bit++); +} + + size_t tr_bitfieldCountTrueBits( const tr_bitfield* b ) { diff --git a/libtransmission/utils.h b/libtransmission/utils.h index 8ced7755c..ebf5f937f 100644 --- a/libtransmission/utils.h +++ b/libtransmission/utils.h @@ -189,6 +189,7 @@ int tr_bitfieldAdd( tr_bitfield*, size_t bit ); int tr_bitfieldRem( tr_bitfield*, size_t bit ); int tr_bitfieldAddRange( tr_bitfield *, size_t begin, size_t end ); int tr_bitfieldRemRange ( tr_bitfield*, size_t begin, size_t end ); +void tr_bitfieldDifference( tr_bitfield *, const tr_bitfield * ); int tr_bitfieldHas( const tr_bitfield*, size_t bit ); int tr_bitfieldIsEmpty( const tr_bitfield* );