return crypto->torrentHashIsSet ? 1 : 0;
}
-int tr_cryptoRandInt( int sup )
+int
+tr_cryptoRandInt( int sup )
{
int r;
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 )
{
RAND_pseudo_bytes ( buf, len );
/** Returns a random number in the range of [0...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 */
void tr_cryptoRandBuf ( unsigned char *buf, size_t len );
***
**/
-/* 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
managerLock( const struct tr_peerMgr * manager )
{
setme->piece = piece;
setme->priority = inf->pieces[piece].priority;
setme->peerCount = 0;
- setme->random = tr_stupidRandInt( INT_MAX );
+ setme->random = tr_cryptoWeakRandInt( INT_MAX );
for( k=0; k<peerCount; ++k ) {
const tr_peer * peer = peers[k];
* get a chance at the first blocks in the queue */
if( 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( ret, tmp+i, sizeof(tr_peer*) * (retCount-i) );
memcpy( ret+(retCount-i), tmp, sizeof(tr_peer*) * i );
if(( n = tr_ptrArraySize( randPool )))
{
- c = tr_ptrArrayNth( randPool, tr_stupidRandInt( n ));
+ c = tr_ptrArrayNth( randPool, tr_cryptoWeakRandInt( n ));
c->doUnchoke = 1;
t->optimistic = c->peer;
}
sendBitfield( tr_peermsgs * msgs )
{
struct evbuffer * out = msgs->outMessages;
- const tr_piece_index_t pieceCount = msgs->torrent->info.pieceCount;
tr_bitfield * field;
tr_piece_index_t lazyPieces[LAZY_PIECE_COUNT];
- int i;
- int lazyCount = 0;
+ size_t i;
+ size_t lazyCount = 0;
field = tr_bitfieldDup( tr_cpPieceBitfield( msgs->torrent->completion ) );
if( tr_sessionIsLazyBitfieldEnabled( msgs->session ) )
{
- const int maxLazyCount = MIN( LAZY_PIECE_COUNT, pieceCount );
-
- while( lazyCount < maxLazyCount )
+ /** 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 );
+
+ /* 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 );
- if( !tr_bitfieldHas( field, pos ) ) /* already removed it */
- continue;
- dbgmsg( msgs, "lazy bitfield #%d: piece %d of %d",
- (int)(lazyCount+1), (int)pos, (int)pieceCount );
- tr_bitfieldRem( field, pos );
- lazyPieces[lazyCount++] = pos;
+ const int pos = tr_cryptoWeakRandInt( poolSize );
+ const tr_piece_index_t piece = pool[pos];
+ tr_bitfieldRem( field, piece );
+ lazyPieces[lazyCount++] = piece;
+ pool[pos] = pool[--poolSize];
}
+
+ /* cleanup */
+ tr_free( pool );
}
tr_peerIoWriteUint32( msgs->io, out, sizeof(uint8_t) + field->byteCount );