]> granicus.if.org Git - transmission/commitdiff
(libT) maybe fix the hangs reported by users in the recent nightlies.
authorCharles Kerr <charles@transmissionbt.com>
Wed, 27 Aug 2008 18:50:21 +0000 (18:50 +0000)
committerCharles Kerr <charles@transmissionbt.com>
Wed, 27 Aug 2008 18:50:21 +0000 (18:50 +0000)
libtransmission/crypto.c
libtransmission/crypto.h
libtransmission/peer-mgr.c
libtransmission/peer-msgs.c

index 603b38a9ae1d78d63ba417e71451c1ae40b70d27..95a4ae5d4f289480da545a7d31b54924700eed0f 100644 (file)
@@ -268,7 +268,8 @@ tr_cryptoHasTorrentHash( const tr_crypto * crypto )
     return crypto->torrentHashIsSet ? 1 : 0;
 }
 
-int tr_cryptoRandInt( int sup )
+int
+tr_cryptoRandInt( int sup )
 {
     int r;
 
@@ -277,6 +278,21 @@ int tr_cryptoRandInt( int sup )
     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 );
index b6abda651588220488c747a97d43a4e877365b18..727feda06f3011aee2a6df1351b608842196bb17 100644 (file)
@@ -79,6 +79,12 @@ void  tr_sha1              ( uint8_t     * setme,
 /** 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 );
 
index 80b0c0fcabdcdebba6bd28570f9df32d0766f411..01325d9725d1137bf50750822b060a62a7d993f0 100644 (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
 managerLock( const struct tr_peerMgr * manager )
 {
@@ -626,7 +605,7 @@ getPreferredPieces( Torrent     * t,
             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];
@@ -667,7 +646,7 @@ getPeersUploadingToClient( Torrent * t, int * setmeCount )
      * 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 );
@@ -1663,7 +1642,7 @@ rechoke( Torrent * t )
 
         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;
         }
index 6af9c465667fa1b193ab9545d9e3aebcba1bbe7c..36343b9f821a8b4a0323e8806814f5f6921a3ef3 100644 (file)
@@ -1766,28 +1766,38 @@ static void
 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 );