Changeset 11897


Ignore:
Timestamp:
Feb 17, 2011, 5:14:53 AM (11 years ago)
Author:
jordan
Message:

(trunk libT) #3767 "rarest first policy" -- fixed.

This commit, started by a patch from athy, implements a rarest first policy when deciding which pieces to request from peers. It keeps a count of how many peers have each piece, and updates the count when getting bitfields, have, have all, and have none messages, as well as decrementing the counts when peers disconnect.

This running total is generated only for downloading torrents. Seeds don't have this overhead.

Location:
trunk/libtransmission
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/peer-common.h

    r11709 r11897  
    2828
    2929#include "transmission.h"
     30
     31struct tr_bitfield;
    3032
    3133enum
     
    6567    TR_PEER_CLIENT_GOT_PORT,
    6668    TR_PEER_CLIENT_GOT_REJ,
     69    TR_PEER_CLIENT_GOT_BITFIELD,
     70    TR_PEER_CLIENT_GOT_HAVE,
     71    TR_PEER_CLIENT_GOT_HAVE_ALL,
     72    TR_PEER_CLIENT_GOT_HAVE_NONE,
    6773    TR_PEER_PEER_GOT_DATA,
    6874    TR_PEER_PEER_PROGRESS,
     
    7379typedef struct
    7480{
    75     PeerEventType    eventType;
    76     uint32_t         pieceIndex;   /* for GOT_BLOCK, CANCEL, ALLOWED, SUGGEST */
    77     uint32_t         offset;       /* for GOT_BLOCK */
    78     uint32_t         length;       /* for GOT_BLOCK + GOT_DATA */
    79     float            progress;     /* for PEER_PROGRESS */
    80     int              err;          /* errno for GOT_ERROR */
    81     tr_bool          wasPieceData; /* for GOT_DATA */
    82     tr_port          port;         /* for GOT_PORT */
     81    PeerEventType         eventType;
     82
     83    uint32_t              pieceIndex;   /* for GOT_BLOCK, GOT_HAVE, CANCEL, ALLOWED, SUGGEST */
     84    struct tr_bitfield  * bitfield;     /* for GOT_BITFIELD */
     85    uint32_t              offset;       /* for GOT_BLOCK */
     86    uint32_t              length;       /* for GOT_BLOCK + GOT_DATA */
     87    float                 progress;     /* for PEER_PROGRESS */
     88    int                   err;          /* errno for GOT_ERROR */
     89    tr_bool               wasPieceData; /* for GOT_DATA */
     90    tr_port               port;         /* for GOT_PORT */
    8391}
    8492tr_peer_event;
     93
     94extern const tr_peer_event TR_PEER_EVENT_INIT;
    8595
    8696struct tr_peer;
  • trunk/libtransmission/peer-mgr.c

    r11892 r11897  
    9999};
    100100
     101const tr_peer_event TR_PEER_EVENT_INIT = { 0, 0, NULL, 0, 0, 0.0f, 0, FALSE, 0 };
    101102
    102103/**
     
    178179};
    179180
     181enum piece_sort_state
     182{
     183    PIECES_UNSORTED,
     184    PIECES_SORTED_BY_INDEX,
     185    PIECES_SORTED_BY_WEIGHT
     186};
     187
    180188/** @brief Opaque, per-torrent data structure for peer connection information */
    181189typedef struct tr_torrent_peers
     
    201209    struct weighted_piece    * pieces;
    202210    int                        pieceCount;
     211    enum piece_sort_state      pieceSortState;
     212
     213    /* An array of pieceCount items stating how many peers have each piece.
     214       This is used to help us for downloading pieces "rarest first."
     215       This may be NULL if we don't have metainfo yet, or if we're not
     216       downloading and don't care about rarity */
     217    uint16_t                 * pieceReplication;
     218    size_t                     pieceReplicationSize;
    203219
    204220    int                        interestedCount;
     
    425441}
    426442
    427 static void
    428 removePeer( Torrent * t, tr_peer * peer )
    429 {
    430     tr_peer * removed;
    431     struct peer_atom * atom = peer->atom;
    432 
    433     assert( torrentIsLocked( t ) );
    434     assert( atom );
    435 
    436     atom->time = tr_time( );
    437 
    438     removed = tr_ptrArrayRemoveSorted( &t->peers, peer, peerCompare );
    439     assert( removed == peer );
    440     peerDestructor( t, removed );
    441 }
    442 
    443 static void
    444 removeAllPeers( Torrent * t )
    445 {
    446     while( !tr_ptrArrayEmpty( &t->peers ) )
    447         removePeer( t, tr_ptrArrayNth( &t->peers, 0 ) );
     443static tr_bool
     444replicationExists( const Torrent * t )
     445{
     446    return t->pieceReplication != NULL;
     447}
     448
     449static void
     450replicationFree( Torrent * t )
     451{
     452    tr_free( t->pieceReplication );
     453    t->pieceReplication = NULL;
     454    t->pieceReplicationSize = 0;
     455}
     456
     457static void
     458replicationNew( Torrent * t )
     459{
     460    tr_piece_index_t piece_i;
     461    const tr_piece_index_t piece_count = t->tor->info.pieceCount;
     462    tr_peer ** peers = (tr_peer**) tr_ptrArrayBase( &t->peers );
     463    const int peer_count = tr_ptrArraySize( &t->peers );
     464
     465    assert( !replicationExists( t ) );
     466
     467    t->pieceReplicationSize = piece_count;
     468    t->pieceReplication = tr_new0( uint16_t, piece_count );
     469
     470    for( piece_i=0; piece_i<piece_count; ++piece_i )
     471    {
     472        int peer_i;
     473        uint16_t r = 0;
     474
     475        for( peer_i=0; peer_i<peer_count; ++peer_i )
     476            if( tr_bitsetHasFast( &peers[peer_i]->have, piece_i ) )
     477                ++r;
     478
     479        t->pieceReplication[piece_i] = r;
     480    }
    448481}
    449482
     
    463496    tr_ptrArrayDestruct( &t->outgoingHandshakes, NULL );
    464497    tr_ptrArrayDestruct( &t->peers, NULL );
     498
     499    replicationFree( t );
    465500
    466501    tr_free( t->requests );
     
    785820}
    786821
    787 /**
    788 *** struct weighted_piece
    789 **/
    790 
    791 enum
    792 {
    793     PIECES_UNSORTED,
    794     PIECES_SORTED_BY_INDEX,
    795     PIECES_SORTED_BY_WEIGHT
    796 };
     822static int
     823countActiveWebseeds( const Torrent * t )
     824{
     825    int activeCount = 0;
     826    const tr_webseed ** w = (const tr_webseed **) tr_ptrArrayBase( &t->webseeds );
     827    const tr_webseed ** const wend = w + tr_ptrArraySize( &t->webseeds );
     828
     829    for( ; w!=wend; ++w )
     830        if( tr_webseedIsActive( *w ) )
     831            ++activeCount;
     832
     833    return activeCount;
     834}
     835
     836static void
     837updateEndgame( Torrent * t )
     838{
     839    const tr_torrent * tor = t->tor;
     840    const tr_block_index_t missing = tr_cpBlocksMissing( &tor->completion );
     841
     842    assert( t->requestCount >= 0 );
     843
     844    if( (tr_block_index_t) t->requestCount < missing )
     845    {
     846        /* not in endgame */
     847        t->endgame = 0;
     848    }
     849    else if( !t->endgame ) /* only recalculate when endgame first begins */
     850    {
     851        int numDownloading = 0;
     852        const tr_peer ** p = (const tr_peer **) tr_ptrArrayBase( &t->peers );
     853        const tr_peer ** const pend = p + tr_ptrArraySize( &t->peers );
     854
     855        /* add the active bittorrent peers... */
     856        for( ; p!=pend; ++p )
     857            if( (*p)->pendingReqsToPeer > 0 )
     858                ++numDownloading;
     859
     860        /* add the active webseeds... */
     861        numDownloading += countActiveWebseeds( t );
     862
     863        /* average number of pending requests per downloading peer */
     864        t->endgame = t->requestCount / MAX( numDownloading, 1 );
     865    }
     866}
     867
     868
     869/****
     870*****
     871*****  Piece List Manipulation / Accessors
     872*****
     873****/
     874
     875static inline void
     876invalidatePieceSorting( Torrent * t )
     877{
     878    t->pieceSortState = PIECES_UNSORTED;
     879}
    797880
    798881const tr_torrent * weightTorrent;
     882
     883const uint16_t * weightReplication;
     884
     885static void
     886setComparePieceByWeightTorrent( Torrent * t )
     887{
     888    if( !replicationExists( t ) )
     889        replicationNew( t );
     890
     891    weightTorrent = t->tor;
     892    weightReplication = t->pieceReplication;
     893}
    799894
    800895/* we try to create a "weight" s.t. high-priority pieces come before others,
     
    807902    int ia, ib, missing, pending;
    808903    const tr_torrent * tor = weightTorrent;
     904    const uint16_t * rep = weightReplication;
    809905
    810906    /* primary key: weight */
     
    824920    if( ia < ib ) return 1;
    825921
    826     /* tertiary key: random */
     922    /* tertiary key: rarest first. */
     923    ia = rep[a->index];
     924    ib = rep[b->index];
     925    if( ia < ib ) return -1;
     926    if( ia > ib ) return 1;
     927
     928    /* quaternary key: random */
    827929    if( a->salt < b->salt ) return -1;
    828930    if( a->salt > b->salt ) return 1;
     
    843945
    844946static void
    845 pieceListSort( Torrent * t, int mode )
    846 {
    847     assert( mode==PIECES_SORTED_BY_INDEX
    848          || mode==PIECES_SORTED_BY_WEIGHT );
    849 
    850     weightTorrent = t->tor;
    851 
    852     if( mode == PIECES_SORTED_BY_WEIGHT )
     947pieceListSort( Torrent * t, enum piece_sort_state state )
     948{
     949    assert( state==PIECES_SORTED_BY_INDEX
     950         || state==PIECES_SORTED_BY_WEIGHT );
     951
     952
     953    if( state == PIECES_SORTED_BY_WEIGHT )
     954    {
     955        setComparePieceByWeightTorrent( t );
    853956        qsort( t->pieces, t->pieceCount, sizeof( struct weighted_piece ), comparePieceByWeight );
     957    }
    854958    else
    855959        qsort( t->pieces, t->pieceCount, sizeof( struct weighted_piece ), comparePieceByIndex );
    856 }
    857 
    858 static int
    859 countActiveWebseeds( const Torrent * t )
    860 {
    861     int activeCount = 0;
    862     const tr_webseed ** w = (const tr_webseed **) tr_ptrArrayBase( &t->webseeds );
    863     const tr_webseed ** const wend = w + tr_ptrArraySize( &t->webseeds );
    864 
    865     for( ; w!=wend; ++w )
    866         if( tr_webseedIsActive( *w ) )
    867             ++activeCount;
    868 
    869     return activeCount;
    870 }
    871 
    872 static void
    873 updateEndgame( Torrent * t )
    874 {
    875     const tr_torrent * tor = t->tor;
    876     const tr_block_index_t missing = tr_cpBlocksMissing( &tor->completion );
    877 
    878     assert( t->requestCount >= 0 );
    879 
    880     if( (tr_block_index_t) t->requestCount < missing )
    881     {
    882         /* not in endgame */
    883         t->endgame = 0;
    884     }
    885     else if( !t->endgame ) /* only recalculate when endgame first begins */
    886     {
    887         int numDownloading = 0;
    888         const tr_peer ** p = (const tr_peer **) tr_ptrArrayBase( &t->peers );
    889         const tr_peer ** const pend = p + tr_ptrArraySize( &t->peers );
    890 
    891         /* add the active bittorrent peers... */
    892         for( ; p!=pend; ++p )
    893             if( (*p)->pendingReqsToPeer > 0 )
    894                 ++numDownloading;
    895 
    896         /* add the active webseeds... */
    897         numDownloading += countActiveWebseeds( t );
    898 
    899         /* average number of pending requests per downloading peer */
    900         t->endgame = t->requestCount / MAX( numDownloading, 1 );
    901     }
     960
     961    t->pieceSortState = state;
    902962}
    903963
    904964/**
    905  * This function is useful for sanity checking,
    906  * but is too expensive even for nightly builds...
     965 * These functions are useful for testing, but too expensive for nightly builds.
    907966 * let's leave it disabled but add an easy hook to compile it back in
    908967 */
    909968#if 0
     969#define assertWeightedPiecesAreSorted(t)
     970#define assertReplicationCountIsExact(t)
     971#else
    910972static void
    911973assertWeightedPiecesAreSorted( Torrent * t )
     
    914976    {
    915977        int i;
    916         weightTorrent = t->tor;
     978        setComparePieceByWeightTorrent( t );
    917979        for( i=0; i<t->pieceCount-1; ++i )
    918980            assert( comparePieceByWeight( &t->pieces[i], &t->pieces[i+1] ) <= 0 );
    919981    }
    920982}
    921 #else
    922 #define assertWeightedPiecesAreSorted(t)
     983static void
     984assertReplicationCountIsExact( Torrent * t )
     985{
     986    /* This assert might fail due to errors of implementations in other
     987     * clients. It happens when receiving duplicate bitfields/HaveAll/HaveNone
     988     * from a client. If a such a behavior is noticed,
     989     * a bug report should be filled to the faulty client. */
     990
     991    size_t piece_i;
     992    const uint16_t * rep = t->pieceReplication;
     993    const size_t piece_count = t->pieceReplicationSize;
     994    const tr_peer ** peers = (const tr_peer**) tr_ptrArrayBase( &t->peers );
     995    const int peer_count = tr_ptrArraySize( &t->peers );
     996
     997    assert( piece_count == t->tor->info.pieceCount );
     998
     999    for( piece_i=0; piece_i<piece_count; ++piece_i )
     1000    {
     1001        int peer_i;
     1002        uint16_t r = 0;
     1003
     1004        for( peer_i=0; peer_i<peer_count; ++peer_i )
     1005            if( tr_bitsetHasFast( &peers[peer_i]->have, piece_i ) )
     1006                ++r;
     1007
     1008        assert( rep[piece_i] == r );
     1009    }
     1010}
    9231011#endif
    9241012
     
    9381026pieceListRebuild( Torrent * t )
    9391027{
    940     assertWeightedPiecesAreSorted( t );
    9411028
    9421029    if( !tr_torrentIsSeed( t->tor ) )
     
    10031090    struct weighted_piece * p;
    10041091
    1005     assertWeightedPiecesAreSorted( t );
    1006 
    10071092    if(( p = pieceListLookup( t, piece )))
    10081093    {
     
    10201105        }
    10211106    }
    1022 
    1023     assertWeightedPiecesAreSorted( t );
    10241107}
    10251108
     
    10351118    /* is the torrent already sorted? */
    10361119    pos = p - t->pieces;
    1037     weightTorrent = t->tor;
     1120    setComparePieceByWeightTorrent( t );
    10381121    if( isSorted && ( pos > 0 ) && ( comparePieceByWeight( p-1, p ) > 0 ) )
    10391122        isSorted = FALSE;
     
    10411124        isSorted = FALSE;
    10421125
     1126    if( t->pieceSortState != PIECES_SORTED_BY_WEIGHT )
     1127    {
     1128       pieceListSort( t, PIECES_SORTED_BY_WEIGHT);
     1129       isSorted = TRUE;
     1130    }
     1131
    10431132    /* if it's not sorted, move it around */
    10441133    if( !isSorted )
     
    10721161    const tr_piece_index_t index = tr_torBlockPiece( t->tor, block );
    10731162
    1074     assertWeightedPiecesAreSorted( t );
    1075 
    10761163    if( ((p = pieceListLookup( t, index ))) && ( p->requestCount > 0 ) )
    10771164    {
     
    10791166        pieceListResortPiece( t, p );
    10801167    }
    1081 
    1082     assertWeightedPiecesAreSorted( t );
     1168}
     1169
     1170
     1171/****
     1172*****
     1173*****  Replication count ( for rarest first policy )
     1174*****
     1175****/
     1176
     1177/**
     1178 * Increase the replication count of this piece and sort it if the
     1179 * piece list is already sorted
     1180 */
     1181static void
     1182tr_incrReplicationOfPiece( Torrent * t, const size_t index )
     1183{
     1184    assert( replicationExists( t ) );
     1185    assert( t->pieceReplicationSize == t->tor->info.pieceCount );
     1186
     1187    /* One more replication of this piece is present in the swarm */
     1188    ++t->pieceReplication[index];
     1189
     1190    /* we only resort the piece if the list is already sorted */
     1191    if( t->pieceSortState == PIECES_SORTED_BY_WEIGHT )
     1192        pieceListResortPiece( t, pieceListLookup( t, index ) );
     1193}
     1194
     1195/**
     1196 * Increases the replication count of pieces present in the bitfield
     1197 */
     1198static void
     1199tr_incrReplicationFromBitfield( Torrent * t, const tr_bitfield * b )
     1200{
     1201    size_t i;
     1202    uint16_t * rep = t->pieceReplication;
     1203    const size_t n = t->tor->info.pieceCount;
     1204
     1205    assert( replicationExists( t ) );
     1206    assert( n == t->pieceReplicationSize );
     1207    assert( tr_bitfieldTestFast( b, n-1 ) );
     1208
     1209    if( tr_bitfieldTestFast( b, n-1 ) )
     1210        for( i=0; i<n; ++i )
     1211            if( tr_bitfieldHasFast( b, i ) )
     1212                ++rep[i];
     1213
     1214    if( t->pieceSortState == PIECES_SORTED_BY_WEIGHT )
     1215        invalidatePieceSorting( t );
     1216}
     1217
     1218/**
     1219 * Increase the replication count of every piece
     1220 */
     1221static void
     1222tr_incrReplication( Torrent * t )
     1223{
     1224    int i;
     1225    const int n = t->pieceReplicationSize;
     1226
     1227    assert( replicationExists( t ) );
     1228    assert( t->pieceReplicationSize == t->tor->info.pieceCount );
     1229
     1230    for( i=0; i<n; ++i )
     1231        ++t->pieceReplication[i];
     1232}
     1233
     1234/**
     1235 * Decrease the replication count of pieces present in the bitset.
     1236 */
     1237static void
     1238tr_decrReplicationFromBitset( Torrent * t, const tr_bitset * bitset )
     1239{
     1240    int i;
     1241    const int n = t->pieceReplicationSize;
     1242
     1243    assert( replicationExists( t ) );
     1244    assert( t->pieceReplicationSize == t->tor->info.pieceCount );
     1245
     1246    if( bitset->haveAll )
     1247    {
     1248        for( i=0; i<n; ++i )
     1249            --t->pieceReplication[i];
     1250    }
     1251    else if ( !bitset->haveNone )
     1252    {
     1253        const tr_bitfield * const b = &bitset->bitfield;
     1254
     1255        if( tr_bitfieldTestFast( b, n-1 ) )
     1256            for( i=0; i<n; ++i )
     1257                if( tr_bitfieldHasFast( b, i ) )
     1258                    --t->pieceReplication[i];
     1259
     1260        if( t->pieceSortState == PIECES_SORTED_BY_WEIGHT )
     1261            invalidatePieceSorting( t );
     1262    }
    10831263}
    10841264
     
    11171297    got = 0;
    11181298    t = tor->torrentPeers;
    1119     assertWeightedPiecesAreSorted( t );
    11201299
    11211300    /* prep the pieces list */
    11221301    if( t->pieces == NULL )
    11231302        pieceListRebuild( t );
     1303
     1304    if( t->pieceSortState != PIECES_SORTED_BY_WEIGHT )
     1305        pieceListSort( t, PIECES_SORTED_BY_WEIGHT );
     1306
     1307    assertReplicationCountIsExact( t );
     1308    assertWeightedPiecesAreSorted( t );
    11241309
    11251310    updateEndgame( t );
     
    11901375        if ( i == t->pieceCount ) --i;
    11911376
    1192         weightTorrent = t->tor;
     1377        setComparePieceByWeightTorrent( t );
    11931378        while( --i >= 0 )
    11941379        {
     
    14201605        }
    14211606
     1607        case TR_PEER_CLIENT_GOT_HAVE:
     1608            if( replicationExists( t ) ) {
     1609                tr_incrReplicationOfPiece( t, e->pieceIndex );
     1610                assertReplicationCountIsExact( t );
     1611            }
     1612            break;
     1613
     1614        case TR_PEER_CLIENT_GOT_HAVE_ALL:
     1615            if( replicationExists( t ) ) {
     1616                tr_incrReplication( t );
     1617                assertReplicationCountIsExact( t );
     1618            }
     1619            break;
     1620
     1621        case TR_PEER_CLIENT_GOT_HAVE_NONE:
     1622            /* noop */
     1623            break;
     1624
     1625        case TR_PEER_CLIENT_GOT_BITFIELD:
     1626            assert( e->bitfield != NULL );
     1627            if( replicationExists( t ) ) {
     1628                tr_incrReplicationFromBitfield( t, e->bitfield );
     1629                assertReplicationCountIsExact( t );
     1630            }
     1631            break;
     1632
    14221633        case TR_PEER_CLIENT_GOT_REJ:
    14231634            removeRequestFromTables( t, _tr_block( t->tor, e->pieceIndex, e->offset ), peer );
     
    21422353    t->isRunning = TRUE;
    21432354    t->maxPeers = t->tor->maxConnectedPeers;
     2355    t->pieceSortState = PIECES_UNSORTED;
    21442356
    21452357    rechokePulse( 0, 0, t->manager );
     
    21522364
    21532365    t->isRunning = FALSE;
     2366
     2367    replicationFree( t );
     2368    invalidatePieceSorting( t );
    21542369
    21552370    /* disconnect the peers. */
     
    29733188
    29743189static void
     3190removePeer( Torrent * t, tr_peer * peer )
     3191{
     3192    tr_peer * removed;
     3193    struct peer_atom * atom = peer->atom;
     3194
     3195    assert( torrentIsLocked( t ) );
     3196    assert( atom );
     3197
     3198    atom->time = tr_time( );
     3199
     3200    removed = tr_ptrArrayRemoveSorted( &t->peers, peer, peerCompare );
     3201
     3202    if( replicationExists( t ) )
     3203        tr_decrReplicationFromBitset( t, &peer->have );
     3204
     3205    assert( removed == peer );
     3206    peerDestructor( t, removed );
     3207}
     3208
     3209static void
    29753210closePeer( Torrent * t, tr_peer * peer )
    29763211{
     
    29953230    tordbg( t, "removing bad peer %s", tr_peerIoGetAddrStr( peer->io ) );
    29963231    removePeer( t, peer );
     3232}
     3233
     3234static void
     3235removeAllPeers( Torrent * t )
     3236{
     3237    while( !tr_ptrArrayEmpty( &t->peers ) )
     3238        removePeer( t, tr_ptrArrayNth( &t->peers, 0 ) );
    29973239}
    29983240
  • trunk/libtransmission/peer-msgs.c

    r11800 r11897  
    172172struct tr_peermsgs
    173173{
     174    tr_bool         got_a_bitfield_or_have_all_or_have_none;
    174175    tr_bool         peerSupportsPex;
    175176    tr_bool         peerSupportsMetadataXfer;
     
    452453**/
    453454
    454 static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
    455 
    456455static void
    457456publish( tr_peermsgs * msgs, tr_peer_event * e )
     
    467466fireError( tr_peermsgs * msgs, int err )
    468467{
    469     tr_peer_event e = blankEvent;
     468    tr_peer_event e = TR_PEER_EVENT_INIT;
    470469    e.eventType = TR_PEER_ERROR;
    471470    e.err = err;
     
    476475firePeerProgress( tr_peermsgs * msgs )
    477476{
    478     tr_peer_event e = blankEvent;
     477    tr_peer_event e = TR_PEER_EVENT_INIT;
    479478    e.eventType = TR_PEER_PEER_PROGRESS;
    480479    e.progress = msgs->peer->progress;
     
    485484fireGotBlock( tr_peermsgs * msgs, const struct peer_request * req )
    486485{
    487     tr_peer_event e = blankEvent;
     486    tr_peer_event e = TR_PEER_EVENT_INIT;
    488487    e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
    489488    e.pieceIndex = req->index;
     
    496495fireGotRej( tr_peermsgs * msgs, const struct peer_request * req )
    497496{
    498     tr_peer_event e = blankEvent;
     497    tr_peer_event e = TR_PEER_EVENT_INIT;
    499498    e.eventType = TR_PEER_CLIENT_GOT_REJ;
    500499    e.pieceIndex = req->index;
     
    507506fireGotChoke( tr_peermsgs * msgs )
    508507{
    509     tr_peer_event e = blankEvent;
     508    tr_peer_event e = TR_PEER_EVENT_INIT;
    510509    e.eventType = TR_PEER_CLIENT_GOT_CHOKE;
     510    publish( msgs, &e );
     511}
     512
     513static void
     514fireClientGotHaveAll( tr_peermsgs * msgs )
     515{
     516    tr_peer_event e = TR_PEER_EVENT_INIT;
     517    e.eventType = TR_PEER_CLIENT_GOT_HAVE_ALL;
     518    publish( msgs, &e );
     519}
     520
     521static void
     522fireClientGotHaveNone( tr_peermsgs * msgs )
     523{
     524    tr_peer_event e = TR_PEER_EVENT_INIT;
     525    e.eventType = TR_PEER_CLIENT_GOT_HAVE_NONE;
    511526    publish( msgs, &e );
    512527}
     
    517532                   int           wasPieceData )
    518533{
    519     tr_peer_event e = blankEvent;
     534    tr_peer_event e = TR_PEER_EVENT_INIT;
    520535
    521536    e.length = length;
     
    528543fireClientGotSuggest( tr_peermsgs * msgs, uint32_t pieceIndex )
    529544{
    530     tr_peer_event e = blankEvent;
     545    tr_peer_event e = TR_PEER_EVENT_INIT;
    531546    e.eventType = TR_PEER_CLIENT_GOT_SUGGEST;
    532547    e.pieceIndex = pieceIndex;
     
    537552fireClientGotPort( tr_peermsgs * msgs, tr_port port )
    538553{
    539     tr_peer_event e = blankEvent;
     554    tr_peer_event e = TR_PEER_EVENT_INIT;
    540555    e.eventType = TR_PEER_CLIENT_GOT_PORT;
    541556    e.port = port;
     
    546561fireClientGotAllowedFast( tr_peermsgs * msgs, uint32_t pieceIndex )
    547562{
    548     tr_peer_event e = blankEvent;
     563    tr_peer_event e = TR_PEER_EVENT_INIT;
    549564    e.eventType = TR_PEER_CLIENT_GOT_ALLOWED_FAST;
    550565    e.pieceIndex = pieceIndex;
     
    553568
    554569static void
     570fireClientGotBitfield( tr_peermsgs * msgs, tr_bitfield * bitfield )
     571{
     572    tr_peer_event e = TR_PEER_EVENT_INIT;
     573    e.eventType = TR_PEER_CLIENT_GOT_BITFIELD;
     574    e.bitfield = bitfield;
     575    publish( msgs, &e );
     576}
     577
     578static void
     579fireClientGotHave( tr_peermsgs * msgs, tr_piece_index_t index )
     580{
     581    tr_peer_event e = TR_PEER_EVENT_INIT;
     582    e.eventType = TR_PEER_CLIENT_GOT_HAVE;
     583    e.pieceIndex = index;
     584    publish( msgs, &e );
     585}
     586
     587static void
    555588firePeerGotData( tr_peermsgs  * msgs,
    556589                 uint32_t       length,
    557590                 int            wasPieceData )
    558591{
    559     tr_peer_event e = blankEvent;
     592    tr_peer_event e = TR_PEER_EVENT_INIT;
    560593
    561594    e.length = length;
     
    14111444                return READ_ERR;
    14121445            }
    1413             if( tr_bitsetAdd( &msgs->peer->have, ui32 ) )
    1414             {
    1415                 fireError( msgs, ERANGE );
    1416                 return READ_ERR;
    1417             }
     1446
     1447            /* a peer can send the same HAVE message twice... */
     1448            if( !tr_bitsetHas( &msgs->peer->have, ui32 ) )
     1449                if( !tr_bitsetAdd( &msgs->peer->have, ui32 ) )
     1450                    fireClientGotHave( msgs, ui32 );
    14181451            updatePeerProgress( msgs );
    14191452            break;
     
    14231456                                  ? msgs->torrent->info.pieceCount
    14241457                                  : msglen * 8;
     1458assert( !msgs->got_a_bitfield_or_have_all_or_have_none );
     1459msgs->got_a_bitfield_or_have_all_or_have_none = TRUE;
    14251460            dbgmsg( msgs, "got a bitfield" );
    14261461            tr_bitsetReserve( &msgs->peer->have, bitCount );
    14271462            tr_peerIoReadBytes( msgs->peer->io, inbuf,
    14281463                                msgs->peer->have.bitfield.bits, msglen );
     1464            fireClientGotBitfield( msgs, &msgs->peer->have.bitfield );
    14291465            updatePeerProgress( msgs );
    14301466            break;
     
    15021538            dbgmsg( msgs, "Got a BT_FEXT_HAVE_ALL" );
    15031539            if( fext ) {
     1540assert( !msgs->got_a_bitfield_or_have_all_or_have_none );
     1541msgs->got_a_bitfield_or_have_all_or_have_none = TRUE;
    15041542                tr_bitsetSetHaveAll( &msgs->peer->have );
     1543                fireClientGotHaveAll( msgs );
    15051544                updatePeerProgress( msgs );
    15061545            } else {
     
    15131552            dbgmsg( msgs, "Got a BT_FEXT_HAVE_NONE" );
    15141553            if( fext ) {
     1554assert( !msgs->got_a_bitfield_or_have_all_or_have_none );
     1555msgs->got_a_bitfield_or_have_all_or_have_none = TRUE;
    15151556                tr_bitsetSetHaveNone( &msgs->peer->have );
     1557                fireClientGotHaveNone( msgs );
    15161558                updatePeerProgress( msgs );
    15171559            } else {
  • trunk/libtransmission/webseed.c

    r11896 r11897  
    7878***/
    7979
    80 static const tr_peer_event blank_event = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
    81 
    8280static void
    8381publish( tr_webseed * w, tr_peer_event * e )
     
    9088fire_client_got_rej( tr_torrent * tor, tr_webseed * w, tr_block_index_t block )
    9189{
    92     tr_peer_event e = blank_event;
     90    tr_peer_event e = TR_PEER_EVENT_INIT;
    9391    e.eventType = TR_PEER_CLIENT_GOT_REJ;
    9492    e.pieceIndex = tr_torBlockPiece( tor, block );
     
    10199fire_client_got_block( tr_torrent * tor, tr_webseed * w, tr_block_index_t block )
    102100{
    103     tr_peer_event e = blank_event;
     101    tr_peer_event e = TR_PEER_EVENT_INIT;
    104102    e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
    105103    e.pieceIndex = tr_torBlockPiece( tor, block );
     
    112110fire_client_got_data( tr_webseed * w, uint32_t length )
    113111{
    114     tr_peer_event e = blank_event;
     112    tr_peer_event e = TR_PEER_EVENT_INIT;
    115113    e.eventType = TR_PEER_CLIENT_GOT_DATA;
    116114    e.length = length;
Note: See TracChangeset for help on using the changeset viewer.