(libT) maybe fix the hangs reported by users in the recent nightlies.

This commit is contained in:
Charles Kerr 2008-08-27 18:50:21 +00:00
parent 9d35118808
commit 64e08510f0
4 changed files with 48 additions and 37 deletions

View File

@ -268,7 +268,8 @@ tr_cryptoHasTorrentHash( const tr_crypto * crypto )
return crypto->torrentHashIsSet ? 1 : 0; return crypto->torrentHashIsSet ? 1 : 0;
} }
int tr_cryptoRandInt( int sup ) int
tr_cryptoRandInt( int sup )
{ {
int r; int r;
@ -277,6 +278,21 @@ int tr_cryptoRandInt( int sup )
return ((int) (sup * (abs(r) / (INT_MAX + 1.0)))); return ((int) (sup * (abs(r) / (INT_MAX + 1.0))));
} }
int
tr_cryptoWeakRandInt( int sup )
{
static int init = 0;
assert( sup > 0 );
if( !init )
{
srand( tr_date( ) );
init = 1;
}
return rand() % sup;
}
void tr_cryptoRandBuf ( unsigned char *buf, size_t len ) void tr_cryptoRandBuf ( unsigned char *buf, size_t len )
{ {
RAND_pseudo_bytes ( buf, len ); RAND_pseudo_bytes ( buf, len );

View File

@ -79,6 +79,12 @@ void tr_sha1 ( uint8_t * setme,
/** Returns a random number in the range of [0...n) */ /** Returns a random number in the range of [0...n) */
int tr_cryptoRandInt ( int n ); int tr_cryptoRandInt ( int n );
/** Returns a vaguely random number in the range of [0...n).
This is faster -- BUT WEAKER -- than tr_cryptoRandInt()
and should only be used when tr_cryptoRandInt() is too
slow, and NEVER in sensitive cases */
int tr_cryptoWeakRandInt( int n );
/** Fills a buffer with random bytes */ /** Fills a buffer with random bytes */
void tr_cryptoRandBuf ( unsigned char *buf, size_t len ); void tr_cryptoRandBuf ( unsigned char *buf, size_t len );

View File

@ -130,27 +130,6 @@ struct tr_peerMgr
*** ***
**/ **/
/* The following is not a very high quality random number generator. It
* is mainly used as a simple stupid random number generator inside some
* functions below. Please don't use it for anything else unless you
* know what you're doing. Use tr_cryptoRandInt() instead.
*/
static int
tr_stupidRandInt( int sup )
{
static int init = 0;
assert( sup > 0 );
if( !init )
{
srand( tr_date() );
init = 1;
}
return rand() % sup;
}
static void static void
managerLock( const struct tr_peerMgr * manager ) managerLock( const struct tr_peerMgr * manager )
{ {
@ -626,7 +605,7 @@ getPreferredPieces( Torrent * t,
setme->piece = piece; setme->piece = piece;
setme->priority = inf->pieces[piece].priority; setme->priority = inf->pieces[piece].priority;
setme->peerCount = 0; setme->peerCount = 0;
setme->random = tr_stupidRandInt( INT_MAX ); setme->random = tr_cryptoWeakRandInt( INT_MAX );
for( k=0; k<peerCount; ++k ) { for( k=0; k<peerCount; ++k ) {
const tr_peer * peer = peers[k]; const tr_peer * peer = peers[k];
@ -667,7 +646,7 @@ getPeersUploadingToClient( Torrent * t, int * setmeCount )
* get a chance at the first blocks in the queue */ * get a chance at the first blocks in the queue */
if( retCount ) { if( retCount ) {
tr_peer ** tmp = tr_new( tr_peer*, retCount ); tr_peer ** tmp = tr_new( tr_peer*, retCount );
i = tr_stupidRandInt( retCount ); i = tr_cryptoWeakRandInt( retCount );
memcpy( tmp, ret, sizeof(tr_peer*) * retCount ); memcpy( tmp, ret, sizeof(tr_peer*) * retCount );
memcpy( ret, tmp+i, sizeof(tr_peer*) * (retCount-i) ); memcpy( ret, tmp+i, sizeof(tr_peer*) * (retCount-i) );
memcpy( ret+(retCount-i), tmp, sizeof(tr_peer*) * i ); memcpy( ret+(retCount-i), tmp, sizeof(tr_peer*) * i );
@ -1663,7 +1642,7 @@ rechoke( Torrent * t )
if(( n = tr_ptrArraySize( randPool ))) if(( n = tr_ptrArraySize( randPool )))
{ {
c = tr_ptrArrayNth( randPool, tr_stupidRandInt( n )); c = tr_ptrArrayNth( randPool, tr_cryptoWeakRandInt( n ));
c->doUnchoke = 1; c->doUnchoke = 1;
t->optimistic = c->peer; t->optimistic = c->peer;
} }

View File

@ -1766,28 +1766,38 @@ static void
sendBitfield( tr_peermsgs * msgs ) sendBitfield( tr_peermsgs * msgs )
{ {
struct evbuffer * out = msgs->outMessages; struct evbuffer * out = msgs->outMessages;
const tr_piece_index_t pieceCount = msgs->torrent->info.pieceCount;
tr_bitfield * field; tr_bitfield * field;
tr_piece_index_t lazyPieces[LAZY_PIECE_COUNT]; tr_piece_index_t lazyPieces[LAZY_PIECE_COUNT];
int i; size_t i;
int lazyCount = 0; size_t lazyCount = 0;
field = tr_bitfieldDup( tr_cpPieceBitfield( msgs->torrent->completion ) ); field = tr_bitfieldDup( tr_cpPieceBitfield( msgs->torrent->completion ) );
if( tr_sessionIsLazyBitfieldEnabled( msgs->session ) ) if( tr_sessionIsLazyBitfieldEnabled( msgs->session ) )
{ {
const int maxLazyCount = MIN( LAZY_PIECE_COUNT, pieceCount ); /** Lazy bitfields aren't a high priority or secure, so I'm opting for
speed over a truly random sample -- let's limit the pool size to
the first 1000 pieces so large torrents don't bog things down */
size_t poolSize = MIN( msgs->torrent->info.pieceCount, 1000 );
tr_piece_index_t * pool = tr_new( tr_piece_index_t, poolSize );
while( lazyCount < maxLazyCount ) /* build the pool */
for( i=0; i<poolSize; ++i )
pool[i] = i;
poolSize = i;
/* pull random piece indices from the pool */
while( ( poolSize > 0 ) && ( lazyCount < LAZY_PIECE_COUNT ) )
{ {
const size_t pos = tr_cryptoRandInt ( pieceCount ); const int pos = tr_cryptoWeakRandInt( poolSize );
if( !tr_bitfieldHas( field, pos ) ) /* already removed it */ const tr_piece_index_t piece = pool[pos];
continue; tr_bitfieldRem( field, piece );
dbgmsg( msgs, "lazy bitfield #%d: piece %d of %d", lazyPieces[lazyCount++] = piece;
(int)(lazyCount+1), (int)pos, (int)pieceCount ); pool[pos] = pool[--poolSize];
tr_bitfieldRem( field, pos );
lazyPieces[lazyCount++] = pos;
} }
/* cleanup */
tr_free( pool );
} }
tr_peerIoWriteUint32( msgs->io, out, sizeof(uint8_t) + field->byteCount ); tr_peerIoWriteUint32( msgs->io, out, sizeof(uint8_t) + field->byteCount );