Adds automatic peer banning.
At first, peers get only banned for the bad pieces they've contributed to, i.e. we continue to ask them for other parts of the torrent. If more bad data keeps coming, the peer gets completely banned. Based on Jeremiah Morris' patch.
This commit is contained in:
parent
f80ab0832f
commit
a006c25025
|
@ -107,7 +107,7 @@ int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
|
|||
tr_torrent_t * tor = io->tor;
|
||||
tr_info_t * inf = &io->tor->info;
|
||||
uint64_t offset;
|
||||
int i;
|
||||
int i, hashFailed;
|
||||
uint8_t hash[SHA_DIGEST_LENGTH];
|
||||
uint8_t * pieceBuf;
|
||||
int pieceSize;
|
||||
|
@ -147,7 +147,8 @@ int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
|
|||
SHA1( pieceBuf, pieceSize, hash );
|
||||
free( pieceBuf );
|
||||
|
||||
if( memcmp( hash, &inf->pieces[20*index], SHA_DIGEST_LENGTH ) )
|
||||
hashFailed = memcmp( hash, &inf->pieces[20*index], SHA_DIGEST_LENGTH );
|
||||
if( hashFailed )
|
||||
{
|
||||
tr_inf( "Piece %d (slot %d): hash FAILED", index,
|
||||
io->pieceSlot[index] );
|
||||
|
@ -165,6 +166,12 @@ int tr_ioWrite( tr_io_t * io, int index, int begin, int length,
|
|||
tr_cpPieceAdd( tor->completion, index );
|
||||
}
|
||||
|
||||
/* Assign blame or credit to peers */
|
||||
for( i = 0; i < tor->peerCount; i++ )
|
||||
{
|
||||
tr_peerBlame( tor, tor->peers[i], index, !hashFailed );
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -58,8 +58,17 @@ struct tr_peer_s
|
|||
|
||||
uint8_t id[20];
|
||||
|
||||
/* The pieces that the peer has */
|
||||
uint8_t * bitfield;
|
||||
|
||||
int goodPcs;
|
||||
int badPcs;
|
||||
int banned;
|
||||
/* The pieces that the peer is contributing to */
|
||||
uint8_t * blamefield;
|
||||
/* The bad pieces that the peer has contributed to */
|
||||
uint8_t * banfield;
|
||||
|
||||
uint8_t * buf;
|
||||
int size;
|
||||
int pos;
|
||||
|
@ -164,6 +173,14 @@ void tr_peerDestroy( tr_fd_t * fdlimit, tr_peer_t * peer )
|
|||
{
|
||||
free( peer->bitfield );
|
||||
}
|
||||
if( peer->blamefield )
|
||||
{
|
||||
free( peer->blamefield );
|
||||
}
|
||||
if( peer->banfield )
|
||||
{
|
||||
free( peer->banfield );
|
||||
}
|
||||
if( peer->buf )
|
||||
{
|
||||
free( peer->buf );
|
||||
|
@ -409,7 +426,7 @@ writeEnd:
|
|||
continue;
|
||||
}
|
||||
|
||||
if( peer->amInterested && !peer->peerChoking )
|
||||
if( peer->amInterested && !peer->peerChoking && !peer->banned )
|
||||
{
|
||||
int block;
|
||||
while( peer->inRequestCount < OUR_REQUEST_COUNT )
|
||||
|
@ -512,3 +529,53 @@ int tr_peerIsOptimistic( tr_peer_t * peer )
|
|||
{
|
||||
return peer->optimistic;
|
||||
}
|
||||
|
||||
static inline int peerIsBad( tr_peer_t * peer )
|
||||
{
|
||||
if( peer->goodPcs >= 5 &&
|
||||
peer->badPcs >= ( peer->goodPcs * 3 ) )
|
||||
{
|
||||
/* need poor success rate if we've successfully downloaded before */
|
||||
return 1;
|
||||
}
|
||||
else if( peer->goodPcs < 5 &&
|
||||
peer->badPcs >= ( 10 + peer->goodPcs ) )
|
||||
{
|
||||
/* need 10 more bad pieces than good before we discard peer */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tr_peerBlame( tr_torrent_t * tor, tr_peer_t * peer,
|
||||
int piece, int success )
|
||||
{
|
||||
if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( success )
|
||||
{
|
||||
peer->goodPcs++;
|
||||
}
|
||||
else
|
||||
{
|
||||
peer->badPcs++;
|
||||
|
||||
if( !peer->banfield )
|
||||
{
|
||||
peer->banfield = calloc( ( tor->info.pieceCount + 7 ) / 8, 1 );
|
||||
}
|
||||
tr_bitfieldAdd( peer->banfield, piece );
|
||||
|
||||
if( peerIsBad( peer ) )
|
||||
{
|
||||
/* Full ban */
|
||||
peer_dbg( "banned (%d / %d)", peer->goodPcs, peer->badPcs );
|
||||
peer->banned = 1;
|
||||
peer->peerInterested = 0;
|
||||
}
|
||||
}
|
||||
tr_bitfieldRem( peer->blamefield, piece );
|
||||
}
|
||||
|
|
|
@ -47,5 +47,7 @@ void tr_peerUnchoke ( tr_peer_t * );
|
|||
uint64_t tr_peerLastChoke ( tr_peer_t * );
|
||||
void tr_peerSetOptimistic ( tr_peer_t *, int );
|
||||
int tr_peerIsOptimistic ( tr_peer_t * );
|
||||
void tr_peerBlame ( tr_torrent_t *, tr_peer_t *,
|
||||
int piece, int success );
|
||||
|
||||
#endif
|
||||
|
|
|
@ -280,6 +280,13 @@ static inline int parsePiece( tr_torrent_t * tor, tr_peer_t * peer,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* set blame/credit for this piece */
|
||||
if( !peer->blamefield )
|
||||
{
|
||||
peer->blamefield = calloc( ( tor->info.pieceCount + 7 ) / 8, 1 );
|
||||
}
|
||||
tr_bitfieldAdd( peer->blamefield, index );
|
||||
|
||||
tr_cpBlockAdd( tor->completion, block );
|
||||
tr_ioWrite( tor->io, index, begin, len - 9, &p[8] );
|
||||
tr_cpDownloaderRem( tor->completion, block );
|
||||
|
@ -449,6 +456,13 @@ static inline int parseBuf( tr_torrent_t * tor, tr_peer_t * peer )
|
|||
uint8_t * p = peer->buf;
|
||||
uint8_t * end = &p[peer->pos];
|
||||
|
||||
if( peer->banned )
|
||||
{
|
||||
/* Don't even parse, we only stay connected */
|
||||
peer->pos = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
while( peer->pos >= 4 )
|
||||
{
|
||||
if( peer->status & PEER_STATUS_HANDSHAKE )
|
||||
|
|
|
@ -267,6 +267,11 @@ static inline int chooseBlock( tr_torrent_t * tor, tr_peer_t * peer )
|
|||
/* The peer doesn't have this piece */
|
||||
continue;
|
||||
}
|
||||
if( peer->banfield && tr_bitfieldHas( peer->banfield, i ) )
|
||||
{
|
||||
/* The peer is banned for this piece */
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We are interested in this piece, remember it */
|
||||
if( missingBlocks < minMissing )
|
||||
|
@ -347,6 +352,11 @@ static inline int chooseBlock( tr_torrent_t * tor, tr_peer_t * peer )
|
|||
/* The peer doesn't have this piece */
|
||||
continue;
|
||||
}
|
||||
if( peer->banfield && tr_bitfieldHas( peer->banfield, i ) )
|
||||
{
|
||||
/* The peer is banned for this piece */
|
||||
continue;
|
||||
}
|
||||
if( tr_cpPieceIsComplete( tor->completion, i ) )
|
||||
{
|
||||
/* We already have it */
|
||||
|
|
Loading…
Reference in New Issue