From 75ffe999d47d41b39b01ed2f091f414a9dd8bb4c Mon Sep 17 00:00:00 2001
From: Jordan Lee <jordan@transmissionbt.com>
Date: Sat, 22 Jan 2011 17:45:54 +0000
Subject: [PATCH] (trunk libT) #3933 "announcer.c peer parsing could be
 simpler" -- fixed.

Remove redundant code by using tr_peerMgrCompactToPex() and tr_peerMgrCompact6ToPex() to parse compact ipv4 and ipv6 peer lists. Simplify the old-style benc peer list parsing and fix a bug that returned too few bytes in the old-style peer array.
---
 libtransmission/announcer.c | 164 +++++++++++++-----------------------
 libtransmission/announcer.h |   6 +-
 libtransmission/torrent.c   |  14 ++-
 3 files changed, 70 insertions(+), 114 deletions(-)

diff --git a/libtransmission/announcer.c b/libtransmission/announcer.c
index f784ca1a4..fa8a63468 100644
--- a/libtransmission/announcer.c
+++ b/libtransmission/announcer.c
@@ -21,6 +21,7 @@
 #include "announcer.h"
 #include "crypto.h"
 #include "net.h"
+#include "peer-mgr.h" /* tr_peerMgrCompactToPex() */
 #include "ptrarray.h"
 #include "session.h"
 #include "tr-dht.h"
@@ -631,87 +632,82 @@ getSeedProbability( int seeds, int leechers )
     return -1; /* unknown */
 }
 
-static int
-publishNewPeers( tr_tier * tier, int seeds, int leechers,
-                 const void * compact, int compactLen )
+static void
+publishPeersPex( tr_tier * tier, int seeds, int leechers,
+                 const tr_pex * pex, int n )
 {
     tr_tracker_event e = emptyEvent;
 
     e.messageType = TR_TRACKER_PEERS;
     e.seedProbability = getSeedProbability( seeds, leechers );
-    e.compact = compact;
-    e.compactLen = compactLen;
+    e.pex = pex;
+    e.pexCount = n;
 
     if( tier->tor->tiers->callback != NULL )
         tier->tor->tiers->callback( tier->tor, &e, NULL );
-
-    return compactLen / 6;
 }
 
-static int
-publishNewPeersCompact( tr_tier * tier, int seeds, int leechers,
+static size_t
+publishPeersCompact( tr_tier * tier, int seeds, int leechers,
                         const void * compact, int compactLen )
 {
-    int i;
-    const uint8_t *compactWalk;
-    uint8_t *array, *walk;
-    const int peerCount = compactLen / 6;
-    const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
-    tr_address addr;
-    tr_port port;
-
-    addr.type = TR_AF_INET;
-    memset( &addr.addr, 0, sizeof( addr.addr ) );
-    array = tr_new( uint8_t, arrayLen );
-    for ( i=0, walk=array, compactWalk=compact ; i<peerCount ; ++i )
-    {
-        memcpy( &addr.addr.addr4, compactWalk, 4 );
-        memcpy( &port, compactWalk + 4, 2 );
-
-        memcpy( walk, &addr, sizeof( addr ) );
-        memcpy( walk + sizeof( addr ), &port, 2 );
-
-        walk += sizeof( tr_address ) + 2;
-        compactWalk += 6;
-    }
-
-    publishNewPeers( tier, seeds, leechers, array, arrayLen );
+    size_t n = 0;
+    tr_pex * pex = tr_peerMgrCompactToPex( compact, compactLen, NULL, 0, &n );
+    publishPeersPex( tier, seeds, leechers, pex, n );
+    dbgmsg( tier, "got IPv4 list of %zu peers", n );
+    tr_free( pex );
+    return n;
+}    
 
-    tr_free( array );
-
-    return peerCount;
+static size_t
+publishPeersCompact6( tr_tier * tier, int seeds, int leechers,
+                         const void * compact, int compactLen )
+{
+    size_t n = 0;
+    tr_pex * pex = tr_peerMgrCompact6ToPex( compact, compactLen, NULL, 0, &n );
+    dbgmsg( tier, "got IPv6 list of %zu peers", n );
+    publishPeersPex( tier, seeds, leechers, pex, n );
+    tr_free( pex );
+    return n;
 }
 
-static int
-publishNewPeersCompact6( tr_tier * tier, int seeds, int leechers,
-                         const void * compact, int compactLen )
+static size_t
+publishPeersDict( tr_tier * tier, int seeds, int leechers, tr_benc * peerList )
 {
-    int i;
-    const uint8_t *compactWalk;
-    uint8_t *array, *walk;
-    const int peerCount = compactLen / 18;
-    const int arrayLen = peerCount * ( sizeof( tr_address ) + 2 );
-    tr_address addr;
-    tr_port port;
-
-    addr.type = TR_AF_INET6;
-    memset( &addr.addr, 0, sizeof( addr.addr ) );
-    array = tr_new( uint8_t, arrayLen );
-    for ( i = 0, walk = array, compactWalk = compact ; i < peerCount ; ++i )
+    size_t i;
+    size_t n;
+    const size_t len = tr_bencListSize( peerList );
+    tr_pex * pex = tr_new0( tr_pex, len );
+
+    for( i=n=0; i<len; ++i )
     {
-        memcpy( &addr.addr.addr6, compactWalk, 16 );
-        memcpy( &port, compactWalk + 16, 2 );
-        compactWalk += 18;
+        int64_t port;
+        const char * ip;
+        tr_address addr;
+        tr_benc * peer = tr_bencListChild( peerList, i );
 
-        memcpy( walk, &addr, sizeof( addr ) );
-        memcpy( walk + sizeof( addr ), &port, 2 );
-        walk += sizeof( tr_address ) + 2;
-    }
+        if( peer == NULL )
+            continue;
+        if( !tr_bencDictFindStr( peer, "ip", &ip ) )
+            continue;
+        if( tr_pton( ip, &addr ) == NULL )
+            continue;
+        if( !tr_bencDictFindInt( peer, "port", &port ) )
+            continue;
+        if( ( port < 0 ) || ( port > USHRT_MAX ) )
+            continue;
+        if( !tr_isValidPeerAddress( &addr, port ) )
+            continue;
 
-    publishNewPeers( tier, seeds, leechers, array, arrayLen );
-    tr_free( array );
+        pex[n].addr = addr;
+        pex[n].port = htons( (uint16_t)port );
+        ++n;
+    }
 
-    return peerCount;
+    dbgmsg( tier, "got benc list of %zu peers", n );
+    publishPeersPex( tier, seeds, leechers, pex, n );
+    tr_free( pex );
+    return n;
 }
 
 static char*
@@ -1163,43 +1159,6 @@ compareTiers( const void * va, const void * vb )
     return ret;
 }
 
-static uint8_t *
-parseOldPeers( tr_benc * bePeers, size_t * byteCount )
-{
-    int       i;
-    uint8_t * array, *walk;
-    const int peerCount = bePeers->val.l.count;
-
-    assert( tr_bencIsList( bePeers ) );
-
-    array = tr_new( uint8_t, peerCount * ( sizeof( tr_address ) + 2 ) );
-
-    for( i = 0, walk = array; i < peerCount; ++i )
-    {
-        const char * s;
-        int64_t      itmp;
-        tr_address   addr;
-        tr_port      port;
-        tr_benc    * peer = &bePeers->val.l.vals[i];
-
-        if( tr_bencDictFindStr( peer, "ip", &s ) )
-            if( tr_pton( s, &addr ) == NULL )
-                continue;
-
-        if( !tr_bencDictFindInt( peer, "port", &itmp )
-                || itmp < 0
-                || itmp > USHRT_MAX )
-            continue;
-
-        memcpy( walk, &addr, sizeof( tr_address ) );
-        port = htons( (uint16_t)itmp );
-        memcpy( walk + sizeof( tr_address ), &port, 2 );
-        walk += sizeof( tr_address ) + 2;
-    }
-
-    *byteCount = peerCount * sizeof( tr_address ) + 2;
-    return array;
-}
 
 static tr_bool
 parseAnnounceResponse( tr_tier     * tier,
@@ -1292,7 +1251,7 @@ parseAnnounceResponse( tr_tier     * tier,
             /* "compact" extension */
             const int seeders = tier->currentTracker->seederCount;
             const int leechers = tier->currentTracker->leecherCount;
-            peerCount += publishNewPeersCompact( tier, seeders, leechers, raw, rawlen );
+            peerCount += publishPeersCompact( tier, seeders, leechers, raw, rawlen );
             gotPeers = TRUE;
         }
         else if( tr_bencDictFindList( &benc, "peers", &tmp ) )
@@ -1300,11 +1259,8 @@ parseAnnounceResponse( tr_tier     * tier,
             /* original version of peers */
             const int seeders = tier->currentTracker->seederCount;
             const int leechers = tier->currentTracker->leecherCount;
-            size_t byteCount = 0;
-            uint8_t * array = parseOldPeers( tmp, &byteCount );
-            peerCount += publishNewPeers( tier, seeders, leechers, array, byteCount );
+            peerCount += publishPeersDict( tier, seeders, leechers, tmp );
             gotPeers = TRUE;
-            tr_free( array );
         }
 
         if( tr_bencDictFindRaw( &benc, "peers6", &raw, &rawlen ) )
@@ -1312,7 +1268,7 @@ parseAnnounceResponse( tr_tier     * tier,
             /* "compact" extension */
             const int seeders = tier->currentTracker->seederCount;
             const int leechers = tier->currentTracker->leecherCount;
-            peerCount += publishNewPeersCompact6( tier, seeders, leechers, raw, rawlen );
+            peerCount += publishPeersCompact6( tier, seeders, leechers, raw, rawlen );
             gotPeers = TRUE;
         }
 
diff --git a/libtransmission/announcer.h b/libtransmission/announcer.h
index a051d8bd3..54cc052e5 100644
--- a/libtransmission/announcer.h
+++ b/libtransmission/announcer.h
@@ -35,6 +35,8 @@ typedef enum
 }
 TrackerEventType;
 
+struct tr_pex;
+
 /** @brief Notification object to tell listeners about announce or scrape occurences */
 typedef struct
 {
@@ -46,8 +48,8 @@ typedef struct
     const char * tracker;
 
     /* for TR_TRACKER_PEERS */
-    const uint8_t *  compact;
-    int              compactLen;
+    const struct tr_pex * pex;
+    size_t pexCount;
 
     /* [0...100] for probability a peer is a seed. calculated by the leecher/seeder ratio */
     int8_t           seedProbability;
diff --git a/libtransmission/torrent.c b/libtransmission/torrent.c
index 53642ee06..10b07a6e3 100644
--- a/libtransmission/torrent.c
+++ b/libtransmission/torrent.c
@@ -493,23 +493,21 @@ onTrackerResponse( tr_torrent * tor, const tr_tracker_event * event, void * unus
     {
         case TR_TRACKER_PEERS:
         {
-            size_t i, n;
+            size_t i;
             const int8_t seedProbability = event->seedProbability;
             const tr_bool allAreSeeds = seedProbability == 100;
-            tr_pex * pex = tr_peerMgrArrayToPex( event->compact,
-                                                 event->compactLen, &n );
+
              if( allAreSeeds )
-                tr_tordbg( tor, "Got %d seeds from tracker", (int)n );
+                tr_tordbg( tor, "Got %zu seeds from tracker", event->pexCount );
             else
-                tr_tordbg( tor, "Got %d peers from tracker", (int)n );
+                tr_tordbg( tor, "Got %zu peers from tracker", event->pexCount );
 
-            for( i = 0; i < n; ++i )
-                tr_peerMgrAddPex( tor, TR_PEER_FROM_TRACKER, pex+i, seedProbability );
+            for( i = 0; i < event->pexCount; ++i )
+                tr_peerMgrAddPex( tor, TR_PEER_FROM_TRACKER, &event->pex[i], seedProbability );
 
             if( allAreSeeds && tr_torrentIsPrivate( tor ) )
                 tr_peerMgrMarkAllAsSeeds( tor );
 
-            tr_free( pex );
             break;
         }
 
-- 
2.40.0