Changeset 3242


Ignore:
Timestamp:
Sep 30, 2007, 11:55:49 PM (14 years ago)
Author:
charles
Message:

experimental better peer management.

Location:
trunk/libtransmission
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/handshake.c

    r3234 r3242  
    160160        const char * addr = tr_peerIoGetAddrStr( handshake->io );
    161161        struct evbuffer * buf = evbuffer_new( );
    162         evbuffer_add_printf( buf, "[%s:%d] %s (%p) ", file, line, addr, handshake );
     162        evbuffer_add_printf( buf, "[%s:%d] %s (%p) ", file, line, addr, handshake->io );
    163163        va_start( args, fmt );
    164164        evbuffer_add_vprintf( buf, fmt, args );
  • trunk/libtransmission/peer-io.c

    r3227 r3242  
    107107
    108108static tr_peerIo*
    109 tr_peerIoNew( struct tr_handle  * handle,
    110               struct in_addr    * in_addr,
    111               uint16_t            port,
    112               const uint8_t     * torrentHash,
    113               int                 isIncoming,
    114               int                 socket )
     109tr_peerIoNew( struct tr_handle     * handle,
     110              const struct in_addr * in_addr,
     111              uint16_t               port,
     112              const uint8_t        * torrentHash,
     113              int                    isIncoming,
     114              int                    socket )
    115115{
    116116    tr_peerIo * c;
     
    134134
    135135tr_peerIo*
    136 tr_peerIoNewIncoming( struct tr_handle  * handle,
    137                       struct in_addr    * in_addr,
    138                       uint16_t            port,
    139                       int                 socket )
     136tr_peerIoNewIncoming( struct tr_handle      * handle,
     137                      const struct in_addr  * in_addr,
     138                      uint16_t                port,
     139                      int                     socket )
    140140{
    141141    assert( handle != NULL );
     
    149149
    150150tr_peerIo*
    151 tr_peerIoNewOutgoing( struct tr_handle  * handle,
    152                       struct in_addr    * in_addr,
    153                       int                 port,
    154                       const uint8_t     * torrentHash )
     151tr_peerIoNewOutgoing( struct tr_handle      * handle,
     152                      const struct in_addr  * in_addr,
     153                      int                     port,
     154                      const uint8_t         * torrentHash )
    155155{
    156156    assert( handle != NULL );
     
    205205
    206206const char*
     207tr_peerIoAddrStr( const struct in_addr * addr, uint16_t port )
     208{
     209    static char buf[512];
     210    snprintf( buf, sizeof(buf), "%s:%u", inet_ntoa( *addr ), (unsigned int)port );
     211    return buf;
     212}
     213
     214const char*
    207215tr_peerIoGetAddrStr( const tr_peerIo * io )
    208216{
    209     static char buf[512];
    210     assert( io != NULL );
    211     snprintf( buf, sizeof(buf), "%s:%u", inet_ntoa( io->in_addr ), (unsigned int)io->port );
    212     return buf;
     217    return tr_peerIoAddrStr( &io->in_addr, io->port );
    213218}
    214219
  • trunk/libtransmission/peer-io.h

    r3184 r3242  
    3131
    3232tr_peerIo*
    33       tr_peerIoNewOutgoing( struct tr_handle   * handle,
    34                             struct in_addr    * addr,
    35                             int                  port,
    36                             const  uint8_t     * torrentHash );
     33      tr_peerIoNewOutgoing( struct tr_handle     * handle,
     34                            const struct in_addr * addr,
     35                            int                    port,
     36                            const  uint8_t       * torrentHash );
    3737
    3838tr_peerIo*
    39       tr_peerIoNewIncoming( struct tr_handle   * handle,
    40                             struct in_addr    * addr,
    41                             uint16_t             port,
    42                             int                  socket );
     39      tr_peerIoNewIncoming( struct tr_handle     * handle,
     40                            const struct in_addr * addr,
     41                            uint16_t               port,
     42                            int                    socket );
    4343
    4444void  tr_peerIoFree      ( tr_peerIo  * io );
     
    6161***
    6262**/
     63
     64const char*
     65       tr_peerIoAddrStr( const struct in_addr * addr, uint16_t port );
    6366
    6467const char*
  • trunk/libtransmission/peer-mgr-private.h

    r3228 r3242  
    5454    time_t peerSentPieceDataAt;
    5555    time_t chokeChangedAt;
    56     time_t connectionChangedAt;
    5756
    5857    struct tr_peermsgs * msgs;
  • trunk/libtransmission/peer-mgr.c

    r3232 r3242  
    2929#include "platform.h"
    3030#include "ptrarray.h"
     31#include "ratecontrol.h"
    3132#include "trevent.h"
    3233#include "utils.h"
     
    5960    SNUBBED_SEC = 60,
    6061
    61     /* if our connection count for a torrent is <= N% of what we wanted,
    62      * start relaxing the rules that decide when to disconnect a peer */
    63     RELAX_RULES_PERCENTAGE = 25,
    64 
    65     /* if we're not relaxing the rules, disconnect a peer that hasn't
    66      * given us anything (or taken, if we're seeding) in this long */
    67     MIN_TRANSFER_IDLE = 90000,
    68 
    69     /* even if we're relaxing the rules, disconnect a peer that hasn't
    70      * given us anything (or taken, if we're seeding) in this long */
    71     MAX_TRANSFER_IDLE = 240000,
    72 
    7362    /* this is arbitrary and, hopefully, temporary until we come up
    7463     * with a better idea for managing the connection limits */
    7564    MAX_CONNECTED_PEERS_PER_TORRENT = 100,
    76 
    77     /* if we hang up on a peer for being worthless, don't try to
    78      * reconnect to it for this long. */
    79     MIN_HANGUP_PERIOD_SEC = 120
    8065};
    8166
     
    8469**/
    8570
     71/* We keep one of these for every peer we know about, whether
     72 * it's connected or not, so the struct must be small.
     73 * When our current connections underperform, we dip back
     74 * int this list for new ones. */
     75struct peer_atom
     76{   
     77    uint8_t from;
     78    uint8_t flags; /* these match the added_f flags */
     79    uint16_t port;
     80    struct in_addr addr;
     81    time_t time;
     82};
     83
    8684typedef struct
    8785{
    8886    uint8_t hash[SHA_DIGEST_LENGTH];
     87    tr_ptrArray * pool; /* struct peer_atom */
    8988    tr_ptrArray * peers; /* tr_peer */
    9089    tr_timer * reconnectTimer;
     
    141140}
    142141static int
    143 torrentIsLocked( Torrent * t )
     142torrentIsLocked( const Torrent * t )
    144143{
    145144    return t!=NULL && t->manager!=NULL && t->manager->lockThread!=0;
     
    151150
    152151static int
     152compareAddresses( const struct in_addr * a, const struct in_addr * b )
     153{
     154    return tr_compareUint32( a->s_addr, b->s_addr );
     155}
     156
     157static int
    153158handshakeCompareToAddr( const void * va, const void * vb )
    154159{
    155160    const tr_handshake * a = va;
    156     const struct in_addr * b = vb;
    157     return memcmp( tr_handshakeGetAddr( a, NULL ), b, sizeof( struct in_addr ) );
     161    return compareAddresses( tr_handshakeGetAddr( a, NULL ), vb );
    158162}
    159163
     
    172176}
    173177
     178static int
     179comparePeerAtomToAddress( const void * va, const void * vb )
     180{
     181    const struct peer_atom * a = va;
     182    return compareAddresses( &a->addr, vb );
     183}
     184
     185static int
     186comparePeerAtoms( const void * va, const void * vb )
     187{
     188    const struct peer_atom * b = vb;
     189    return comparePeerAtomToAddress( va, &b->addr );
     190}
     191
    174192/**
    175193***
     
    205223    const tr_peer * a = (const tr_peer *) va;
    206224    const tr_peer * b = (const tr_peer *) vb;
    207     return memcmp( &a->in_addr, &b->in_addr, sizeof(struct in_addr) );
     225    return compareAddresses( &a->in_addr, &b->in_addr );
    208226}
    209227
     
    212230{
    213231    const tr_peer * a = (const tr_peer *) va;
    214     const struct in_addr * b = (const struct in_addr *) vb;
    215     return memcmp( &a->in_addr, b, sizeof(struct in_addr) );
     232    return compareAddresses( &a->in_addr, vb );
    216233}
    217234
     
    227244}
    228245
     246static struct peer_atom*
     247getExistingAtom( const Torrent * t, const struct in_addr * addr )
     248{
     249    assert( torrentIsLocked( t ) );
     250    return tr_ptrArrayFindSorted( t->pool, addr, comparePeerAtomToAddress );
     251}
     252
     253static int
     254peerIsKnown( const Torrent * t, const struct in_addr * addr )
     255{
     256    return getExistingAtom( t, addr ) != NULL;
     257}
     258
     259static int
     260peerIsInUse( const Torrent * t, const struct in_addr * addr )
     261{
     262    assert( torrentIsLocked ( t ) );
     263
     264    return ( getExistingPeer( (Torrent*)t, addr ) != NULL )
     265        || ( getExistingHandshake( ((Torrent*)t)->manager, addr ) != NULL );
     266}
     267
    229268static tr_peer*
    230 getPeer( Torrent * torrent, const struct in_addr * in_addr, int * isNew )
     269getPeer( Torrent * torrent, const struct in_addr * in_addr )
    231270{
    232271    tr_peer * peer;
     
    235274
    236275    peer = getExistingPeer( torrent, in_addr );
    237 
    238     if( isNew )
    239         *isNew = peer == NULL;
    240276
    241277    if( peer == NULL )
     
    283319
    284320static void
     321removePeer( Torrent * t, tr_peer * peer )
     322{
     323    tr_peer * removed;
     324    struct peer_atom * atom;
     325
     326    assert( torrentIsLocked( t ) );
     327
     328    atom = getExistingAtom( t, &peer->in_addr );
     329    assert( atom != NULL );
     330    atom->time = time( NULL );
     331
     332    removed = tr_ptrArrayRemoveSorted  ( t->peers, peer, peerCompare );
     333    assert( removed == peer );
     334    freePeer( removed );
     335}
     336
     337static void
    285338freeTorrent( tr_peerMgr * manager, Torrent * t )
    286339{
    287     int i, size;
    288     tr_peer ** peers;
    289340    uint8_t hash[SHA_DIGEST_LENGTH];
    290341
     
    302353    tr_timerFree( &t->refillTimer );
    303354
    304     peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &size );
    305     for( i=0; i<size; ++i )
    306         freePeer( peers[i] );
    307 
    308355    tr_bitfieldFree( t->requested );
    309     tr_ptrArrayFree( t->peers );
     356    tr_ptrArrayFree( t->pool, (PtrArrayForeachFunc)tr_free );
     357    tr_ptrArrayFree( t->peers, (PtrArrayForeachFunc)freePeer );
    310358    tr_ptrArrayRemoveSorted( manager->torrents, t, torrentCompare );
    311359    tr_free( t );
     
    394442    managerLock( manager );
    395443
    396     while( !tr_ptrArrayEmpty( manager->handshakes ) )
    397         tr_handshakeAbort( (tr_handshake*)tr_ptrArrayNth( manager->handshakes, 0) );
    398     tr_ptrArrayFree( manager->handshakes );
    399 
    400     while( !tr_ptrArrayEmpty( manager->torrents ) )
    401         freeTorrent( manager, (Torrent*)tr_ptrArrayNth( manager->torrents, 0) );
    402     tr_ptrArrayFree( manager->torrents );
     444    tr_ptrArrayFree( manager->handshakes, (PtrArrayForeachFunc)tr_handshakeAbort );
     445    tr_ptrArrayFree( manager->torrents, (PtrArrayForeachFunc)freeTorrent );
    403446
    404447    managerUnlock( manager );
     
    874917    else /* looking good */
    875918    {
    876         tr_peer * peer = getPeer( t, in_addr, NULL );
     919        tr_peer * peer = getPeer( t, in_addr );
    877920        if( peer->msgs != NULL ) { /* we already have this peer */
    878921            tr_peerIoFree( io );
     
    885928            peer->client = peer_id ? tr_clientForId( peer_id ) : NULL;
    886929            peer->msgsTag = tr_peerMsgsSubscribe( peer->msgs, msgsCallbackFunc, t );
    887             peer->connectionChangedAt = time( NULL );
    888930            rechokeSoon( t );
    889931        }
     
    926968
    927969    managerUnlock( manager );
     970}
     971
     972static void
     973maybeAddNewAtom( Torrent * t, const struct in_addr * addr, uint16_t port, uint8_t flags, uint8_t from )
     974{
     975    if( !peerIsKnown( t, addr ) )
     976    {
     977        struct peer_atom * a = tr_new( struct peer_atom, 1 );
     978        a->addr = *addr;
     979        a->port = port;
     980        a->flags = flags;
     981        a->from = from;
     982        a->time = 0;
     983fprintf( stderr, "torrent [%s] getting a new atom: %s\n", t->tor->info.name, tr_peerIoAddrStr(&a->addr,a->port) );
     984        tr_ptrArrayInsertSorted( t->pool, a, comparePeerAtoms );
     985    }
    928986}
    929987
     
    941999
    9421000    t = getExistingTorrent( manager, torrentHash );
    943     end = pex + pexCount;
    944     while( pex != end )
    945     {
    946         int isNew;
    947         tr_peer * peer = getPeer( t, &pex->in_addr, &isNew );
    948         if( isNew ) {
    949             peer->port = pex->port;
    950             peer->from = from;
    951         }
    952         ++pex;
    953     }
     1001    for( end=pex+pexCount; pex!=end; ++pex )
     1002        maybeAddNewAtom( t, &pex->in_addr, pex->port, pex->flags, from );
    9541003    reconnectSoon( t );
    9551004
     
    9731022    for( i=0; t!=NULL && i<peerCount; ++i )
    9741023    {
    975         int isNew;
    976         tr_peer * peer;
    9771024        struct in_addr addr;
    9781025        uint16_t port;
    9791026        memcpy( &addr, walk, 4 ); walk += 4;
    9801027        memcpy( &port, walk, 2 ); walk += 2;
    981         peer = getPeer( t, &addr, &isNew );
    982         if( isNew ) {
    983             peer->port = port;
    984             peer->from = from;
    985         }
     1028        maybeAddNewAtom( t, &addr, port, 0, from );
    9861029    }
    9871030    reconnectSoon( t );
     
    11321175    t->manager = manager;
    11331176    t->tor = tor;
     1177    t->pool = tr_ptrArrayNew( );
    11341178    t->peers = tr_ptrArrayNew( );
    11351179    t->requested = tr_bitfieldNew( tor->blockCount );
     
    14381482}
    14391483
    1440 /**
    1441 ***
    1442 **/
    1443 
    1444 static int
    1445 shouldPeerBeDisconnected( Torrent * t, tr_peer * peer, int peerCount, int isSeeding )
    1446 {
     1484/***
     1485****
     1486****
     1487****
     1488***/
     1489
     1490struct tr_connection
     1491{
     1492    tr_peer * peer;
     1493    double throughput;
     1494};
     1495
     1496#define LAISSEZ_FAIRE_PERIOD_SECS 60
     1497
     1498static int
     1499compareConnections( const void * va, const void * vb )
     1500{
     1501    const struct tr_connection * a = va;
     1502    const struct tr_connection * b = vb;
     1503    if( a->throughput < b->throughput ) return -1;
     1504    if( a->throughput > b->throughput ) return 1;
     1505    return 0;
     1506}
     1507
     1508static struct tr_connection *
     1509getWeakConnections( Torrent * t, int * setmeSize )
     1510{
     1511    int i, insize, outsize;
     1512    const int seeding = tr_cpGetStatus( t->tor->completion ) != TR_CP_INCOMPLETE;
     1513    tr_peer ** peers = (tr_peer**) tr_ptrArrayPeek( t->peers, &insize );
     1514    struct tr_connection * ret = tr_new( struct tr_connection, insize );
    14471515    const time_t now = time( NULL );
    1448     int relaxStrictnessIfFewerThanN;
    1449     double strictness;
    14501516
    14511517    assert( torrentIsLocked( t ) );
    1452     assert( peer != NULL );
    1453 
    1454     if( peer->io == NULL ) /* not connected */
    1455         return FALSE;
    1456 
    1457     if( !t->isRunning ) /* the torrent is stopped... nobody should be connected */
    1458         return TRUE;
    1459 
    1460     /* not enough peers to go around... might as well keep this one;
    1461      * they might unchoke us or give us a pex or something */
    1462     if( peerCount < MAX_CONNECTED_PEERS_PER_TORRENT )
    1463         return FALSE;
    1464 
    1465     /* when deciding whether or not to keep a peer, judge its responsiveness
    1466        on a sliding scale that's based on how many other peers are available */
    1467     relaxStrictnessIfFewerThanN =
    1468         (int)(((MAX_CONNECTED_PEERS_PER_TORRENT * RELAX_RULES_PERCENTAGE) / 100.0) + 0.5);
    1469 
    1470     /* if we have >= relaxIfFewerThan, strictness is 100%.
    1471        if we have zero connections, strictness is 0% */
    1472     if( peerCount >= relaxStrictnessIfFewerThanN )
    1473         strictness = 1.0;
    1474     else
    1475         strictness = peerCount / (double)relaxStrictnessIfFewerThanN;
    1476 
    1477     /* test: has it been too long since we exchanged piece data? */
    1478     if( ( now - peer->connectionChangedAt ) >= MAX_TRANSFER_IDLE ) {
    1479         const uint64_t lo = MIN_TRANSFER_IDLE;
    1480         const uint64_t hi = MAX_TRANSFER_IDLE;
    1481         const uint64_t limit = lo + ((hi-lo) * strictness);
    1482         const uint64_t interval = now - (isSeeding ? peer->clientSentPieceDataAt : peer->peerSentPieceDataAt);
    1483         if( interval > limit )
    1484             return TRUE;
    1485     }
    1486 
    1487     /* FIXME: SWE had other tests too... */
    1488 
    1489     return FALSE;
    1490 }
    1491 
    1492 static int
    1493 comparePeerByConnectionDate( const void * va, const void * vb )
    1494 {
    1495     const tr_peer * a = *(const tr_peer**) va;
    1496     const tr_peer * b = *(const tr_peer**) vb;
    1497     return tr_compareUint64( a->connectionChangedAt, b->connectionChangedAt );
    1498 }
    1499 
    1500 static int
    1501 reconnectPulse( void * vt UNUSED )
    1502 {
    1503     int i, size, liveCount;
    1504     Torrent * t = vt;
    1505     tr_peer ** peers;
    1506     int isSeeding;
    1507 
    1508     torrentLock( t );
    1509 
    1510     peers = (tr_peer**) tr_ptrArrayPeek( t->peers, &size );
    1511     isSeeding = tr_cpGetStatus( t->tor->completion ) != TR_CP_INCOMPLETE;
    1512 
    1513     /* how many connections do we have? */
    1514     for( i=liveCount=0; i<size; ++i )
    1515         if( peers[i]->msgs != NULL )
    1516             ++liveCount;
    1517 
    1518     /* destroy and/or disconnect from some peers */
    1519     for( i=0; i<size; )
     1518
     1519    for( i=outsize=0; i<insize; ++i )
    15201520    {
    15211521        tr_peer * peer = peers[i];
    1522 
    1523         if( peer->doPurge ) {
    1524             tr_ptrArrayErase( t->peers, i, i+1 );
    1525             freePeer( peer );
    1526             --size;
    1527             --liveCount;
     1522        const struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
     1523        const double throughput = seeding ? tr_peerIoGetRateToPeer( peer->io )
     1524                                          : tr_peerIoGetRateToClient( peer->io );
     1525
     1526        if( ( now - atom->time ) < LAISSEZ_FAIRE_PERIOD_SECS )
     1527            continue;
     1528
     1529        if( throughput >= 2 )
     1530            continue;
     1531
     1532        ret[outsize].peer = peer;
     1533        ret[outsize].throughput = throughput;
     1534        ++outsize;
     1535    }
     1536
     1537    qsort( ret, outsize, sizeof(struct tr_connection), compareConnections );
     1538    *setmeSize = outsize;
     1539    return ret;
     1540}
     1541
     1542static int
     1543compareAtomByTime( const void * va, const void * vb )
     1544{
     1545    const struct peer_atom * a = * (const struct peer_atom**) va;
     1546    const struct peer_atom * b = * (const struct peer_atom**) vb;
     1547    if( a->time < b->time ) return -1;
     1548    if( a->time > b->time ) return 1;
     1549    return 0;
     1550}
     1551
     1552static struct peer_atom **
     1553getPeerCandidates( Torrent * t, int * setmeSize )
     1554{
     1555    int i, insize, outsize;
     1556    struct peer_atom ** atoms;
     1557    struct peer_atom ** ret;
     1558    const time_t now = time( NULL );
     1559    const int seed = tr_cpGetStatus( t->tor->completion ) != TR_CP_INCOMPLETE;
     1560
     1561    assert( torrentIsLocked( t ) );
     1562
     1563    atoms = (struct peer_atom**) tr_ptrArrayPeek( t->pool, &insize );
     1564    ret = tr_new( struct peer_atom*, insize );
     1565    for( i=outsize=0; i<insize; ++i )
     1566    {
     1567        struct peer_atom * atom = atoms[i];
     1568
     1569        /* we don't need two connections to the same peer... */
     1570        if( peerIsInUse( t, &atom->addr ) ) {
     1571            fprintf( stderr, "RECONNECT peer %d (%s) is in use...\n", i, tr_peerIoAddrStr(&atom->addr,atom->port) );
    15281572            continue;
    15291573        }
    15301574
    1531         if( shouldPeerBeDisconnected( t, peer, liveCount, isSeeding ) ) {
    1532             disconnectPeer( peer );
    1533             --liveCount;
     1575        /* no need to connect if we're both seeds... */
     1576        if( seed && ( atom->flags & 2 ) ) {
     1577            fprintf( stderr, "RECONNECT peer %d (%s) is a seed and so are we...\n", i, tr_peerIoAddrStr(&atom->addr,atom->port) );
     1578            continue;
    15341579        }
    15351580
    1536         ++i;
    1537     }
    1538 
    1539     /* maybe connect to some new peers */
    1540     if( t->isRunning && (liveCount<MAX_CONNECTED_PEERS_PER_TORRENT) )
    1541     {
    1542         int poolSize;
    1543         int left = MAX_CONNECTED_PEERS_PER_TORRENT - liveCount;
    1544         tr_peer ** pool;
    1545         tr_peerMgr * manager = t->manager;
    1546         const time_t now = time( NULL );
    1547 
    1548         /* make a list of peers we know about but aren't connected to */
    1549         poolSize = 0;
    1550         pool = tr_new0( tr_peer*, size );
    1551         for( i=0; i<size; ++i ) {
    1552             tr_peer * peer = peers[i];
    1553             if( peer->msgs == NULL )
    1554                 pool[poolSize++] = peer;
     1581        /* if we used this peer recently, give someone else a turn */
     1582        if( ( now - atom->time ) <  LAISSEZ_FAIRE_PERIOD_SECS ) {
     1583            fprintf( stderr, "RECONNECT peer %d (%s) is in its grace period...\n", i, tr_peerIoAddrStr(&atom->addr,atom->port) );
     1584            continue;
    15551585        }
    15561586
    1557         /* sort them s.t. the ones we've already tried are at the last of the list */
    1558         qsort( pool, poolSize, sizeof(tr_peer*), comparePeerByConnectionDate );
    1559 
    1560         /* make some connections */
    1561         for( i=0; i<poolSize && left>0; ++i )
    1562         {
    1563             tr_peer * peer = pool[i];
    1564             tr_peerIo * io;
    1565 
    1566             if( ( now - peer->connectionChangedAt ) < MIN_HANGUP_PERIOD_SEC )
    1567                 break;
    1568 
    1569             /* already have a handshake pending */
    1570             if( getExistingHandshake( manager, &peer->in_addr ) != NULL )
    1571                 continue;
    1572 
    1573             /* initiate a connection to the peer */
    1574             io = tr_peerIoNewOutgoing( manager->handle, &peer->in_addr, peer->port, t->hash );
    1575             /*fprintf( stderr, "[%s] connecting to potential peer %s\n", t->tor->info.name, tr_peerIoGetAddrStr(io) );*/
    1576             peer->connectionChangedAt = time( NULL );
    1577             initiateHandshake( manager, io );
    1578             --left;
    1579         }
    1580 
    1581         tr_free( pool );
    1582     }
    1583 
     1587        ret[outsize++] = atom;
     1588    }
     1589
     1590    qsort( ret, outsize, sizeof(struct peer_atom*), compareAtomByTime );
     1591    *setmeSize = outsize;
     1592    return ret;
     1593}
     1594
     1595static int
     1596reconnectPulse( void * vtorrent )
     1597{
     1598    Torrent * t = vtorrent;
     1599    struct peer_atom ** candidates;
     1600    struct tr_connection * connections;
     1601    int i, nCandidates, nConnections, nCull, nAdd;
     1602
     1603    torrentLock( t );
     1604
     1605    connections = getWeakConnections( t, &nConnections );
     1606    candidates = getPeerCandidates( t, &nCandidates );
     1607
     1608    /* figure out how many peers to disconnect */
     1609    nCull = nConnections-4;
     1610
     1611fprintf( stderr, "RECONNECT pulse for [%s]: %d connections, %d candidates, %d atoms, %d cull\n", t->tor->info.name, nConnections, nCandidates, tr_ptrArraySize(t->pool), nCull );
     1612
     1613for( i=0; i<nConnections; ++i )
     1614fprintf( stderr, "connection #%d: %s @ %.2f\n", i+1, tr_peerIoAddrStr( &connections[i].peer->in_addr, connections[i].peer->port ), connections[i].throughput );
     1615
     1616    /* disconnect some peers */
     1617    for( i=0; i<nCull && i<nConnections; ++i ) {
     1618        const double throughput = connections[i].throughput;
     1619        tr_peer * peer = connections[i].peer;
     1620        fprintf( stderr, "RECONNECT culling peer %s, whose throughput was %f\n", tr_peerIoAddrStr(&peer->in_addr, peer->port), throughput );
     1621        removePeer( t, peer );
     1622    }
     1623
     1624    /* add some new ones */
     1625    nAdd = MAX_CONNECTED_PEERS_PER_TORRENT - nConnections;
     1626    for( i=0; i<nAdd && i<nCandidates; ++i ) {
     1627        struct peer_atom * atom = candidates[i];
     1628        tr_peerIo * io = tr_peerIoNewOutgoing( t->manager->handle, &atom->addr, atom->port, t->hash );
     1629fprintf( stderr, "RECONNECT adding an outgoing connection...\n" );
     1630        initiateHandshake( t->manager, io );
     1631        atom->time = time( NULL );
     1632    }
     1633
     1634    /* cleanup */
     1635    tr_free( connections );
     1636    tr_free( candidates );
    15841637    torrentUnlock( t );
    15851638    return TRUE;
  • trunk/libtransmission/peer-msgs.c

    r3234 r3242  
    155155        const char * addr = tr_peerIoGetAddrStr( msgs->io );
    156156        struct evbuffer * buf = evbuffer_new( );
    157         evbuffer_add_printf( buf, "[%s:%d] %s (%p) ", file, line, addr, msgs );
     157        evbuffer_add_printf( buf, "[%s:%d] %s (%p) ", file, line, addr, msgs->io );
    158158        va_start( args, fmt );
    159159        evbuffer_add_vprintf( buf, fmt, args );
     
    243243}
    244244
     245/* "interested" means we'll ask for piece data from the peer if they unchoke us */
    245246static int
    246247isPeerInteresting( const tr_peermsgs * msgs )
    247248{
     249    int i;
     250    const tr_torrent * torrent;
     251    const tr_bitfield * bitfield;
    248252    const int clientIsSeed = tr_cpGetStatus( msgs->torrent->completion ) != TR_CP_INCOMPLETE;
    249     const int peerIsSeed = msgs->info->progress >= 1.0;
    250 
    251     if( peerIsSeed )
    252     {
    253         return !clientIsSeed;
    254     }
    255     else if( clientIsSeed )
    256     {
    257         return !peerIsSeed;
    258     }
    259     else /* we're both leeches... */
    260     {
    261         int i;
    262         const tr_torrent * torrent = msgs->torrent;
    263         const tr_bitfield * bitfield = tr_cpPieceBitfield( torrent->completion );
    264 
    265         if( !msgs->info->have ) /* We don't know what this peer has... what should this be? */
     253
     254    if( clientIsSeed )
     255        return FALSE;
     256
     257    torrent = msgs->torrent;
     258    bitfield = tr_cpPieceBitfield( torrent->completion );
     259
     260    if( !msgs->info->have ) /* We don't know what this peer has... what should this be? */
     261        return TRUE;
     262
     263    assert( bitfield->len == msgs->info->have->len );
     264    for( i=0; i<torrent->info.pieceCount; ++i )
     265        if( isPieceInteresting( msgs, i ) )
    266266            return TRUE;
    267267
    268         assert( bitfield->len == msgs->info->have->len );
    269         for( i=0; i<torrent->info.pieceCount; ++i )
    270             if( isPieceInteresting( msgs, i ) )
    271                 return TRUE;
    272 
    273         return FALSE;
    274     }
     268    return FALSE;
    275269}
    276270
     
    690684        parseLtepHandshake( msgs, msglen, inbuf );
    691685        sendLtepHandshake( msgs );
     686        sendPex( msgs );
    692687    }
    693688    else if( ltep_msgid == msgs->ut_pex_id )
     
    775770            assert( msglen == 0 );
    776771            msgs->info->peerIsInterested = 1;
     772            tr_peerMsgsSetChoke( msgs, 0 );
    777773            break;
    778774
     
    12371233    {
    12381234    }
     1235#if 0
    12391236    else if(( len = EVBUFFER_LENGTH( msgs->outBlock ) ))
    12401237    {
     
    12511248        }
    12521249    }
     1250#endif
    12531251    else if(( len = EVBUFFER_LENGTH( msgs->outMessages ) ))
    12541252    {
     
    12581256    else if(( msgs->peerAskedFor ))
    12591257    {
    1260         struct peer_request * req = tr_list_pop_front( &msgs->peerAskedFor );
    1261         uint8_t * tmp = tr_new( uint8_t, req->length );
    1262         const uint32_t msglen = sizeof(uint8_t) + 2*sizeof(uint32_t) + req->length;
    1263         assert( requestIsValid( msgs, req ) );
    1264         tr_ioRead( msgs->torrent, req->index, req->offset, req->length, tmp );
    1265         tr_peerIoWriteUint32( msgs->io, msgs->outBlock, msglen );
    1266         tr_peerIoWriteUint8 ( msgs->io, msgs->outBlock, BT_PIECE );
    1267         tr_peerIoWriteUint32( msgs->io, msgs->outBlock, req->index );
    1268         tr_peerIoWriteUint32( msgs->io, msgs->outBlock, req->offset );
    1269         tr_peerIoWriteBytes ( msgs->io, msgs->outBlock, tmp, req->length );
    1270         tr_free( tmp );
    1271         dbgmsg( msgs, "putting req into out queue: index %d, offset %d, length %d ... %d blocks left in our queue", (int)req->index, (int)req->offset, (int)req->length, tr_list_size(msgs->peerAskedFor) );
    1272         tr_free( req );
     1258        if( canUpload( msgs ) )
     1259        {
     1260            struct peer_request * req = tr_list_pop_front( &msgs->peerAskedFor );
     1261            uint8_t * tmp = tr_new( uint8_t, req->length );
     1262            const uint32_t msglen = sizeof(uint8_t) + 2*sizeof(uint32_t) + req->length;
     1263            struct evbuffer * out = evbuffer_new( );
     1264            assert( requestIsValid( msgs, req ) );
     1265
     1266            tr_peerIoWriteUint32( msgs->io, out, msglen );
     1267            tr_peerIoWriteUint8 ( msgs->io, out, BT_PIECE );
     1268            tr_peerIoWriteUint32( msgs->io, out, req->index );
     1269            tr_peerIoWriteUint32( msgs->io, out, req->offset );
     1270            tr_peerIoWriteBuf( msgs->io, out );
     1271
     1272            tr_ioRead( msgs->torrent, req->index, req->offset, req->length, tmp );
     1273            tr_peerIoWrite( msgs->io, tmp, req->length );
     1274            peerGotBytes( msgs, req->length );
     1275
     1276            dbgmsg( msgs, "putting req into out queue: index %d, offset %d, length %d ... %d blocks left in our queue", (int)req->index, (int)req->offset, (int)req->length, tr_list_size(msgs->peerAskedFor) );
     1277
     1278            tr_free( req );
     1279            tr_free( tmp );
     1280            evbuffer_free( out );
     1281        }
    12731282    }
    12741283    else if( ( now - msgs->clientSentAnythingAt ) > KEEPALIVE_INTERVAL_SECS )
     
    13091318/* some peers give us error messages if we send
    13101319   more than this many peers in a single pex message */
    1311 #define MAX_PEX_DIFFS 50
     1320#define MAX_PEX_DIFFS 200
    13121321
    13131322typedef struct
  • trunk/libtransmission/ptrarray.c

    r3221 r3242  
    4141
    4242void
    43 tr_ptrArrayFree( tr_ptrArray * t )
    44 {
     43tr_ptrArrayForeach( tr_ptrArray * t, PtrArrayForeachFunc func )
     44{
     45    int i;
     46
    4547    assert( t != NULL );
    4648    assert( t->items != NULL );
     49    assert( func != NULL );
     50
     51    for( i=0; i<t->n_items; ++i )
     52        func( t->items[i] );
     53}
     54
     55void
     56tr_ptrArrayFree( tr_ptrArray * t, PtrArrayForeachFunc func )
     57{
     58    assert( t != NULL );
     59    assert( t->items != NULL );
     60
     61    if( func != NULL )
     62        tr_ptrArrayForeach( t, func );
    4763
    4864    tr_free( t->items );
  • trunk/libtransmission/ptrarray.h

    r3105 r3242  
    1919typedef struct tr_ptrArray tr_ptrArray;
    2020
     21typedef void (*PtrArrayForeachFunc)(void *);
     22
    2123tr_ptrArray * tr_ptrArrayNew     ( void );
    22 
    23 void    tr_ptrArrayFree          ( tr_ptrArray* );
     24void    tr_ptrArrayForeach       ( tr_ptrArray*, PtrArrayForeachFunc func );
     25void    tr_ptrArrayFree          ( tr_ptrArray*, PtrArrayForeachFunc func );
    2426void*   tr_ptrArrayNth           ( tr_ptrArray*, int n );
    2527void**  tr_ptrArrayPeek          ( tr_ptrArray*, int * size );
  • trunk/libtransmission/tracker.c

    r3235 r3242  
    386386            evhttp_connection_free( t->connection );
    387387
    388         tr_ptrArrayFree( t->torrents );
    389         tr_ptrArrayFree( t->scrapeQueue );
    390         tr_ptrArrayFree( t->scraping );
     388        tr_ptrArrayFree( t->torrents, NULL );
     389        tr_ptrArrayFree( t->scrapeQueue, NULL );
     390        tr_ptrArrayFree( t->scraping, NULL );
    391391
    392392        for( i=0; i<t->addressCount; ++i )
Note: See TracChangeset for help on using the changeset viewer.