Changeset 10500


Ignore:
Timestamp:
Apr 20, 2010, 9:54:03 PM (8 years ago)
Author:
charles
Message:

(trunk libT) #3159 "better decision-making when choosing which peers to initiate new connections with" -- experimental commit

Location:
trunk/libtransmission
Files:
12 edited

Legend:

Unmodified
Added
Removed
  • trunk/libtransmission/announcer.c

    r10390 r10500  
    597597
    598598static int
    599 publishNewPeers( tr_tier * tier, tr_bool allAreSeeds,
     599publishNewPeers( tr_tier * tier, int seeds, int leechers,
    600600                 const void * compact, int compactLen )
    601601{
     
    603603
    604604    e.messageType = TR_TRACKER_PEERS;
    605     e.allAreSeeds = allAreSeeds;
     605    e.seedProbability = seeds+leechers ? (int)((100.0*seeds)/(seeds+leechers)) : -1;
    606606    e.compact = compact;
    607607    e.compactLen = compactLen;
    608608
    609     if( compactLen )
    610         tr_publisherPublish( &tier->tor->tiers->publisher, tier, &e );
     609    tr_publisherPublish( &tier->tor->tiers->publisher, tier, &e );
    611610
    612611    return compactLen / 6;
     
    614613
    615614static int
    616 publishNewPeersCompact( tr_tier * tier, tr_bool allAreSeeds,
     615publishNewPeersCompact( tr_tier * tier, int seeds, int leechers,
    617616                        const void * compact, int compactLen )
    618617{
     
    640639    }
    641640
    642     publishNewPeers( tier, allAreSeeds, array, arrayLen );
     641    publishNewPeers( tier, seeds, leechers, array, arrayLen );
    643642
    644643    tr_free( array );
     
    648647
    649648static int
    650 publishNewPeersCompact6( tr_tier * tier, tr_bool allAreSeeds,
     649publishNewPeersCompact6( tr_tier * tier, int seeds, int leechers,
    651650                         const void * compact, int compactLen )
    652651{
     
    672671        walk += sizeof( tr_address ) + 2;
    673672    }
    674     publishNewPeers( tier, allAreSeeds, array, arrayLen );
     673
     674    publishNewPeers( tier, seeds, leechers, array, arrayLen );
    675675    tr_free( array );
    676676
     
    12021202    {
    12031203        int peerCount = 0;
    1204         int incomplete = -1;
    12051204        size_t rawlen;
    12061205        int64_t i;
     
    12461245        }
    12471246
    1248         if( tr_bencDictFindInt( &benc, "complete", &i ) )
    1249         {
     1247        if( !tr_bencDictFindInt( &benc, "complete", &i ) )
     1248            tier->currentTracker->seederCount = 0;
     1249        else {
    12501250            ++scrapeFields;
    12511251            tier->currentTracker->seederCount = i;
    12521252        }
    12531253
    1254         if( tr_bencDictFindInt( &benc, "incomplete", &i ) )
    1255         {
     1254        if( !tr_bencDictFindInt( &benc, "incomplete", &i ) )
     1255            tier->currentTracker->leecherCount = 0;
     1256        else {
    12561257            ++scrapeFields;
    1257             tier->currentTracker->leecherCount = incomplete = i;
     1258            tier->currentTracker->leecherCount = i;
    12581259        }
    12591260
     
    12671268        {
    12681269            /* "compact" extension */
    1269             const int allAreSeeds = incomplete == 0;
    1270             peerCount += publishNewPeersCompact( tier, allAreSeeds, raw, rawlen );
     1270            const int seeders = tier->currentTracker->seederCount;
     1271            const int leechers = tier->currentTracker->leecherCount;
     1272            peerCount += publishNewPeersCompact( tier, seeders, leechers, raw, rawlen );
    12711273            gotPeers = TRUE;
    12721274        }
     
    12741276        {
    12751277            /* original version of peers */
    1276             const tr_bool allAreSeeds = incomplete == 0;
     1278            const int seeders = tier->currentTracker->seederCount;
     1279            const int leechers = tier->currentTracker->leecherCount;
    12771280            size_t byteCount = 0;
    12781281            uint8_t * array = parseOldPeers( tmp, &byteCount );
    1279             peerCount += publishNewPeers( tier, allAreSeeds, array, byteCount );
     1282            peerCount += publishNewPeers( tier, seeders, leechers, array, byteCount );
    12801283            gotPeers = TRUE;
    12811284            tr_free( array );
     
    12851288        {
    12861289            /* "compact" extension */
    1287             const tr_bool allAreSeeds = incomplete == 0;
    1288             peerCount += publishNewPeersCompact6( tier, allAreSeeds, raw, rawlen );
     1290            const int seeders = tier->currentTracker->seederCount;
     1291            const int leechers = tier->currentTracker->leecherCount;
     1292            peerCount += publishNewPeersCompact6( tier, seeders, leechers, raw, rawlen );
    12891293            gotPeers = TRUE;
    12901294        }
  • trunk/libtransmission/announcer.h

    r10238 r10500  
    4949    const uint8_t *  compact;
    5050    int              compactLen;
    51     int              allAreSeeds;
     51
     52    /* [0...100] for probability a peer is a seed.  calculated by the leecher/seeder ratio */
     53    int8_t           seedProbability;
    5254}
    5355tr_tracker_event;
  • trunk/libtransmission/handshake.c

    r10302 r10500  
    102102struct tr_handshake
    103103{
     104    tr_bool               haveReadAnythingFromPeer;
    104105    tr_bool               havePeerID;
    105106    tr_bool               haveSentBitTorrentHandshake;
     
    432433    }
    433434
     435    handshake->haveReadAnythingFromPeer = TRUE;
     436
    434437    /* compute the secret */
    435438    evbuffer_remove( inbuf, yb, KEY_LEN );
     
    613616    if( EVBUFFER_LENGTH( inbuf ) < INCOMING_HANDSHAKE_LEN )
    614617        return READ_LATER;
     618
     619    handshake->haveReadAnythingFromPeer = TRUE;
    615620
    616621    pstrlen = EVBUFFER_DATA( inbuf )[0]; /* peek, don't read.  We may be
     
    11011106    const int success = ( *handshake->doneCB )( handshake,
    11021107                                                handshake->io,
     1108                                                handshake->haveReadAnythingFromPeer,
    11031109                                                isConnected,
    11041110                                                peer_id,
  • trunk/libtransmission/handshake.h

    r9868 r10500  
    3333typedef tr_bool ( *handshakeDoneCB )( struct tr_handshake * handshake,
    3434                                      struct tr_peerIo *    io,
     35                                      tr_bool               readAnythingFromPeer,
    3536                                      tr_bool               isConnected,
    3637                                      const uint8_t *       peerId,
  • trunk/libtransmission/peer-common.h

    r9890 r10500  
    6262    TR_PEER_PEER_GOT_DATA,
    6363    TR_PEER_PEER_PROGRESS,
    64     TR_PEER_ERROR,
    65     TR_PEER_UPLOAD_ONLY
     64    TR_PEER_ERROR
    6665}
    6766PeerEventType;
     
    7675    int              err;          /* errno for GOT_ERROR */
    7776    tr_bool          wasPieceData; /* for GOT_DATA */
    78     tr_bool          uploadOnly;   /* for UPLOAD_ONLY */
    7977    tr_port          port;         /* for GOT_PORT */
    8078}
  • trunk/libtransmission/peer-mgr.c

    r10483 r10500  
    6565    MAX_CONNECTIONS_PER_SECOND = 12,
    6666
     67    MAX_CONNECTIONS_PER_PULSE = (int)(MAX_CONNECTIONS_PER_SECOND * (RECONNECT_PERIOD_MSEC/1000.0)),
     68
    6769    /* number of bad pieces a peer is allowed to send before we ban them */
    6870    MAX_BAD_PIECES_PER_PEER = 5,
     
    112114struct peer_atom
    113115{
    114     tr_peer   * peer;        /* will be NULL if not connected */
    115116    uint8_t     from;
    116     uint8_t     flags;       /* these match the added_f flags */
    117     uint8_t     myflags;     /* flags that aren't defined in added_f */
    118     uint8_t     uploadOnly;  /* UPLOAD_ONLY_ */
     117    uint8_t     flags;              /* these match the added_f flags */
     118    uint8_t     myflags;            /* flags that aren't defined in added_f */
     119    uint8_t     uploadOnly;         /* UPLOAD_ONLY_ */
     120    int8_t      seedProbability;    /* how likely is this to be a seed... [0..100] or -1 for unknown */
     121
    119122    tr_port     port;
    120123    uint16_t    numFails;
    121     tr_address  addr;
    122     time_t      time;        /* when the peer's connection status last changed */
     124    time_t      time;               /* when the peer's connection status last changed */
    123125    time_t      piece_data_time;
     126
     127    time_t      lastConnectionAttemptAt;
     128    time_t      lastConnectionAt;
    124129
    125130    /* similar to a TTL field, but less rigid --
    126131     * if the swarm is small, the atom will be kept past this date. */
    127132    time_t      shelf_date;
     133    tr_peer   * peer;               /* will be NULL if not connected */
     134    tr_address  addr;
    128135};
    129136
     
    197204    struct event  * bandwidthTimer;
    198205    struct event  * rechokeTimer;
    199     struct event  * reconnectTimer;
    200206    struct event  * refillUpkeepTimer;
    201207    struct event  * atomTimer;
     
    501507    deleteTimer( &m->bandwidthTimer );
    502508    deleteTimer( &m->rechokeTimer );
    503     deleteTimer( &m->reconnectTimer );
    504509    deleteTimer( &m->refillUpkeepTimer );
    505510}
     
    542547***/
    543548
     549static void
     550atomSetSeedProbability( struct peer_atom * atom, int seedProbability )
     551{
     552    assert( atom != NULL );
     553    assert( -1<=seedProbability && seedProbability<=100 );
     554
     555    atom->seedProbability = seedProbability;
     556
     557    if( seedProbability == 100 )
     558        atom->flags |= ADDED_F_SEED_FLAG;
     559    else if( seedProbability != -1 )
     560        atom->flags &= ~ADDED_F_SEED_FLAG;
     561}
     562
     563static void
     564atomSetSeed( struct peer_atom * atom )
     565{
     566    atomSetSeedProbability( atom, 100 );
     567}
     568
     569static tr_bool
     570atomIsSeed( const struct peer_atom * atom )
     571{
     572    return atom->seedProbability == 100;
     573}
     574
    544575tr_bool
    545576tr_peerMgrPeerIsSeed( const tr_torrent  * tor,
     
    551582
    552583    if( atom )
    553         isSeed = ( atom->flags & ADDED_F_SEED_FLAG ) != 0;
     584        isSeed = atomIsSeed( atom );
    554585
    555586    return isSeed;
     
    12791310    switch( e->eventType )
    12801311    {
    1281         case TR_PEER_UPLOAD_ONLY:
    1282             /* update our atom */
    1283             if( peer ) {
    1284                 if( e->uploadOnly ) {
    1285                     peer->atom->uploadOnly = UPLOAD_ONLY_YES;
    1286                     peer->atom->flags |= ADDED_F_SEED_FLAG;
    1287                 } else {
    1288                     peer->atom->uploadOnly = UPLOAD_ONLY_NO;
    1289                     peer->atom->flags &= ~ADDED_F_SEED_FLAG;
    1290                 }
    1291             }
    1292             break;
    1293 
    12941312        case TR_PEER_PEER_GOT_DATA:
    12951313        {
     
    13681386                struct peer_atom * atom = peer->atom;
    13691387                if( e->progress >= 1.0 ) {
    1370                     tordbg( t, "marking peer %s as a seed",
    1371                             tr_atomAddrStr( atom ) );
    1372                     atom->flags |= ADDED_F_SEED_FLAG;
     1388                    tordbg( t, "marking peer %s as a seed", tr_atomAddrStr( atom ) );
     1389                    atomSetSeed( atom );
    13731390                }
    13741391            }
     
    14961513}
    14971514
    1498 
    14991515static void
    15001516ensureAtomExists( Torrent           * t,
     
    15021518                  const tr_port       port,
    15031519                  const uint8_t       flags,
     1520                  const int8_t        seedProbability,
    15041521                  const uint8_t       from )
    15051522{
     1523    struct peer_atom * a;
     1524
    15061525    assert( tr_isAddress( addr ) );
    15071526    assert( from < TR_PEER_FROM__MAX );
    15081527
    1509     if( getExistingAtom( t, addr ) == NULL )
    1510     {
    1511         struct peer_atom * a;
     1528    a = getExistingAtom( t, addr );
     1529
     1530    if( a == NULL )
     1531    {
    15121532        const int jitter = tr_cryptoWeakRandInt( 60*10 );
    1513 
    15141533        a = tr_new0( struct peer_atom, 1 );
    15151534        a->addr = *addr;
     
    15181537        a->from = from;
    15191538        a->shelf_date = tr_time( ) + getDefaultShelfLife( from ) + jitter;
     1539        atomSetSeedProbability( a, seedProbability );
    15201540        tr_ptrArrayInsertSorted( &t->pool, a, compareAtomsByAddress );
    15211541
    15221542        tordbg( t, "got a new atom: %s", tr_atomAddrStr( a ) );
     1543    }
     1544    else if( a->seedProbability == -1 )
     1545    {
     1546        atomSetSeedProbability( a, seedProbability );
    15231547    }
    15241548}
     
    15401564myHandshakeDoneCB( tr_handshake  * handshake,
    15411565                   tr_peerIo     * io,
     1566                   tr_bool         readAnythingFromPeer,
    15421567                   tr_bool         isConnected,
    15431568                   const uint8_t * peer_id,
     
    15821607            struct peer_atom * atom = getExistingAtom( t, addr );
    15831608            if( atom )
     1609            {
    15841610                ++atom->numFails;
     1611
     1612                if( !readAnythingFromPeer )
     1613                {
     1614                    tordbg( t, "marking peer %s as unreachable... numFails is %d", tr_atomAddrStr( atom ), (int)atom->numFails );
     1615                    atom->myflags |= MYFLAG_UNREACHABLE;
     1616                }
     1617            }
    15851618        }
    15861619    }
     
    15891622        struct peer_atom * atom;
    15901623
    1591         ensureAtomExists( t, addr, port, 0, TR_PEER_FROM_INCOMING );
     1624        ensureAtomExists( t, addr, port, 0, -1, TR_PEER_FROM_INCOMING );
    15921625        atom = getExistingAtom( t, addr );
    15931626        atom->time = tr_time( );
    15941627        atom->piece_data_time = 0;
     1628        atom->lastConnectionAt = tr_time( );
     1629        atom->myflags &= ~MYFLAG_UNREACHABLE;
    15951630
    15961631        if( atom->myflags & MYFLAG_BANNED )
     
    16901725
    16911726void
    1692 tr_peerMgrAddPex( tr_torrent   *  tor,
    1693                   uint8_t         from,
    1694                   const tr_pex *  pex )
     1727tr_peerMgrAddPex( tr_torrent * tor, uint8_t from,
     1728                  const tr_pex * pex, int8_t seedProbability )
    16951729{
    16961730    if( tr_isPex( pex ) ) /* safeguard against corrupt data */
     
    17011735        if( !tr_sessionIsAddressBlocked( t->manager->session, &pex->addr ) )
    17021736            if( tr_isValidPeerAddress( &pex->addr, pex->port ) )
    1703                 ensureAtomExists( t, &pex->addr, pex->port, pex->flags, from );
     1737                ensureAtomExists( t, &pex->addr, pex->port, pex->flags, seedProbability, from );
    17041738
    17051739        managerUnlock( t->manager );
    17061740    }
     1741}
     1742
     1743void
     1744tr_peerMgrMarkAllAsSeeds( tr_torrent * tor )
     1745{
     1746    Torrent * t = tor->torrentPeers;
     1747    const int n = tr_ptrArraySize( &t->pool );
     1748    struct peer_atom ** it = (struct peer_atom**) tr_ptrArrayBase( &t->pool );
     1749    struct peer_atom ** end = it + n;
     1750
     1751    while( it != end )
     1752        atomSetSeed( *it++ );
    17071753}
    17081754
     
    19672013        m->rechokeTimer = createTimer( RECHOKE_PERIOD_MSEC, rechokePulse, m );
    19682014
    1969     if( m->reconnectTimer == NULL )
    1970         m->reconnectTimer = createTimer( RECONNECT_PERIOD_MSEC, reconnectPulse, m );
    1971 
    1972     if( m->refillUpkeepTimer == NULL )
     2015   if( m->refillUpkeepTimer == NULL )
    19732016        m->refillUpkeepTimer = createTimer( REFILL_UPKEEP_PERIOD_MSEC, refillUpkeep, m );
    19742017}
     
    21542197            ++*setmePeersGettingFromUs;
    21552198
    2156         if( atom->flags & ADDED_F_SEED_FLAG )
     2199        if( atomIsSeed( atom ) )
    21572200            ++*setmeSeedsConnected;
    21582201    }
     
    26592702    if( tr_torrentIsSeed( tor ) )
    26602703    {
    2661         int peerHasEverything;
    2662         if( atom->flags & ADDED_F_SEED_FLAG )
    2663             peerHasEverything = TRUE;
    2664         else if( peer->progress < tr_cpPercentDone( &tor->completion ) )
    2665             peerHasEverything = FALSE;
    2666         else {
     2704        tr_bool peerHasEverything;
     2705
     2706        if( atom->seedProbability != -1 )
     2707        {
     2708            peerHasEverything = atomIsSeed( atom );
     2709        }
     2710        else
     2711        {
    26672712            tr_bitfield * tmp = tr_bitfieldDup( tr_cpPieceBitfield( &tor->completion ) );
    26682713            tr_bitsetDifference( tmp, &peer->have );
     
    27252770
    27262771static int
    2727 compareCandidates( const void * va, const void * vb )
    2728 {
    2729     const struct peer_atom * a = *(const struct peer_atom**) va;
    2730     const struct peer_atom * b = *(const struct peer_atom**) vb;
    2731 
    2732     /* <Charles> Here we would probably want to try reconnecting to
    2733      * peers that had most recently given us data. Lots of users have
    2734      * trouble with resets due to their routers and/or ISPs. This way we
    2735      * can quickly recover from an unwanted reset. So we sort
    2736      * piece_data_time in descending order.
    2737      */
    2738 
    2739     if( a->piece_data_time != b->piece_data_time )
    2740         return a->piece_data_time < b->piece_data_time ? 1 : -1;
    2741 
    2742     if( a->numFails != b->numFails )
    2743         return a->numFails < b->numFails ? -1 : 1;
    2744 
    2745     if( a->time != b->time )
    2746         return a->time < b->time ? -1 : 1;
    2747 
    2748     /* In order to avoid fragmenting the swarm, peers from trackers and
    2749      * from the DHT should be preferred to peers from PEX. */
    2750     if( a->from != b->from )
    2751         return a->from < b->from ? -1 : 1;
    2752 
    2753     return 0;
    2754 }
    2755 
    2756 static int
    27572772getReconnectIntervalSecs( const struct peer_atom * atom, const time_t now )
    27582773{
     
    27812796    }
    27822797
     2798    /* penalize peers that were unreachable the last time we tried */
     2799    if( atom->myflags & MYFLAG_UNREACHABLE )
     2800        sec += sec;
     2801
     2802    dbgmsg( "reconnect interval for %s is %d seconds", tr_atomAddrStr( atom ), sec );
    27832803    return sec;
    2784 }
    2785 
    2786 static struct peer_atom **
    2787 getPeerCandidates( Torrent * t, const time_t now, int * setmeSize )
    2788 {
    2789     int                 i, atomCount, retCount;
    2790     struct peer_atom ** atoms;
    2791     struct peer_atom ** ret;
    2792     const int           seed = tr_torrentIsSeed( t->tor );
    2793 
    2794     assert( torrentIsLocked( t ) );
    2795 
    2796     atoms = (struct peer_atom**) tr_ptrArrayPeek( &t->pool, &atomCount );
    2797     ret = tr_new( struct peer_atom*, atomCount );
    2798     for( i = retCount = 0; i < atomCount; ++i )
    2799     {
    2800         int                interval;
    2801         struct peer_atom * atom = atoms[i];
    2802 
    2803         /* peer fed us too much bad data ... we only keep it around
    2804          * now to weed it out in case someone sends it to us via pex */
    2805         if( atom->myflags & MYFLAG_BANNED )
    2806             continue;
    2807 
    2808         /* peer was unconnectable before, so we're not going to keep trying.
    2809          * this is needs a separate flag from `banned', since if they try
    2810          * to connect to us later, we'll let them in */
    2811         if( atom->myflags & MYFLAG_UNREACHABLE )
    2812             continue;
    2813 
    2814         /* no need to connect if we're both seeds... */
    2815         if( seed && ( ( atom->flags & ADDED_F_SEED_FLAG ) ||
    2816                       ( atom->uploadOnly == UPLOAD_ONLY_YES ) ) )
    2817             continue;
    2818 
    2819         /* don't reconnect too often */
    2820         interval = getReconnectIntervalSecs( atom, now );
    2821         if( ( now - atom->time ) < interval )
    2822         {
    2823             tordbg( t, "RECONNECT peer %d (%s) is in its grace period of %d seconds..",
    2824                     i, tr_atomAddrStr( atom ), interval );
    2825             continue;
    2826         }
    2827 
    2828         /* Don't connect to peers in our blocklist */
    2829         if( tr_sessionIsAddressBlocked( t->manager->session, &atom->addr ) )
    2830             continue;
    2831 
    2832         /* we don't need two connections to the same peer... */
    2833         if( peerIsInUse( t, atom ) )
    2834             continue;
    2835 
    2836         ret[retCount++] = atom;
    2837     }
    2838 
    2839     if( retCount != 0 )
    2840         qsort( ret, retCount, sizeof( struct peer_atom* ), compareCandidates );
    2841     *setmeSize = retCount;
    2842     return ret;
    28432804}
    28442805
     
    28562817       so reset their `numFails' weight to zero.  otherwise we connected
    28572818       to them fruitlessly, so mark it as another fail */
    2858     if( atom->piece_data_time )
     2819    if( atom->piece_data_time ) {
     2820        tordbg( t, "resetting atom %s numFails to 0", tr_atomAddrStr(atom) );
    28592821        atom->numFails = 0;
    2860     else
     2822    } else {
    28612823        ++atom->numFails;
     2824        tordbg( t, "incremented atom %s numFails to %d", tr_atomAddrStr(atom), (int)atom->numFails );
     2825    }
    28622826
    28632827    tordbg( t, "removing bad peer %s", tr_peerIoGetAddrStr( peer->io ) );
     
    28652829}
    28662830
    2867 /* Make a lot of slots available to newly-running torrents...
    2868  * once they reach steady state, they shouldn't need as many */
    2869 static int
    2870 maxNewPeersPerPulse( const Torrent * t )
    2871 {
    2872     double runTime;
    2873     const tr_torrent * tor = t->tor;
    2874 
    2875     assert( tr_isTorrent( tor ) );
    2876 
    2877     runTime = difftime( tr_time( ), tor->startDate );
    2878     if( runTime > 480 ) return 1;
    2879     if( runTime > 240 ) return 2;
    2880     if( runTime > 120 ) return 3;
    2881     return 4;
    2882 }
    2883 
    2884 static void
    2885 reconnectTorrent( Torrent * t )
    2886 {
    2887     static time_t prevTime = 0;
    2888     static int    newConnectionsThisSecond = 0;
     2831static void
     2832closeBadPeers( Torrent * t )
     2833{
    28892834    const time_t  now = tr_time( );
    2890 
    2891     if( prevTime != now )
    2892     {
    2893         prevTime = now;
    2894         newConnectionsThisSecond = 0;
    2895     }
    28962835
    28972836    if( !t->isRunning )
     
    29032842        int i;
    29042843        int mustCloseCount;
    2905         int maxCandidates;
    29062844        struct tr_peer ** mustClose;
    2907         const int maxPerPulse = maxNewPeersPerPulse( t );
    29082845
    29092846        /* disconnect the really bad peers */
     
    29122849            closePeer( t, mustClose[i] );
    29132850        tr_free( mustClose );
    2914 
    2915         /* decide how many peers can we try to add in this pass */
    2916         maxCandidates = maxPerPulse;
    2917         if( tr_announcerHasBacklog( t->manager->session->announcer ) )
    2918             maxCandidates /= 2;
    2919         maxCandidates = MIN( maxCandidates, getMaxPeerCount( t->tor ) - getPeerCount( t ) );
    2920         maxCandidates = MIN( maxCandidates, MAX_CONNECTIONS_PER_SECOND - newConnectionsThisSecond );
    2921 
    2922         /* select the best candidates, if they are requested */
    2923         if( maxCandidates == 0 )
    2924         {
    2925             tordbg( t, "reconnect pulse for [%s]: %d must-close connections, "
    2926                        "NO connection candidates needed, %d atoms, "
    2927                        "max per pulse is %d",
    2928                        t->tor->info.name, mustCloseCount,
    2929                        tr_ptrArraySize( &t->pool ),
    2930                        maxPerPulse );
    2931 
    2932             tordbg( t, "maxCandidates is %d, maxPerPulse is %d, "
    2933                        "getPeerCount(t) is %d, getMaxPeerCount(t) is %d, "
    2934                        "newConnectionsThisSecond is %d, MAX_CONNECTIONS_PER_SECOND is %d",
    2935                        maxCandidates, maxPerPulse,
    2936                        getPeerCount( t ), getMaxPeerCount( t->tor ),
    2937                        newConnectionsThisSecond, MAX_CONNECTIONS_PER_SECOND );
    2938         }
    2939         else
    2940         {
    2941             int canCloseCount = 0;
    2942             int candidateCount;
    2943             struct peer_atom ** candidates;
    2944 
    2945             candidates = getPeerCandidates( t, now, &candidateCount );
    2946             maxCandidates = MIN( maxCandidates, candidateCount );
    2947 
    2948             /* maybe disconnect some lesser peers, if we have candidates to replace them with */
    2949             if( maxCandidates != 0 )
    2950             {
    2951                 struct tr_peer ** canClose = getPeersToClose( t, TR_CAN_CLOSE, now, &canCloseCount );
    2952                 for( i=0; ( i<canCloseCount ) && ( i<maxCandidates ); ++i )
    2953                    closePeer( t, canClose[i] );
    2954                 tr_free( canClose );
    2955             }
    2956 
    2957             tordbg( t, "reconnect pulse for [%s]: %d must-close connections, "
    2958                        "%d can-close connections, %d connection candidates, "
    2959                        "%d atoms, max per pulse is %d",
    2960                        t->tor->info.name, mustCloseCount,
    2961                        canCloseCount, candidateCount,
    2962                        tr_ptrArraySize( &t->pool ), maxPerPulse );
    2963 
    2964             tordbg( t, "candidateCount is %d, maxPerPulse is %d,"
    2965                        " getPeerCount(t) is %d, getMaxPeerCount(t) is %d, "
    2966                        "newConnectionsThisSecond is %d, MAX_CONNECTIONS_PER_SECOND is %d",
    2967                        candidateCount, maxPerPulse,
    2968                        getPeerCount( t ), getMaxPeerCount( t->tor ),
    2969                        newConnectionsThisSecond, MAX_CONNECTIONS_PER_SECOND );
    2970 
    2971             /* add some new ones */
    2972             for( i=0; i<maxCandidates; ++i )
    2973             {
    2974                 tr_peerMgr        * mgr = t->manager;
    2975                 struct peer_atom  * atom = candidates[i];
    2976                 tr_peerIo         * io;
    2977 
    2978                 tordbg( t, "Starting an OUTGOING connection with %s",
    2979                         tr_atomAddrStr( atom ) );
    2980 
    2981                 io = tr_peerIoNewOutgoing( mgr->session,
    2982                                            mgr->session->bandwidth,
    2983                                            &atom->addr,
    2984                                            atom->port,
    2985                                            t->tor->info.hash,
    2986                                            t->tor->completeness == TR_SEED );
    2987 
    2988                 if( io == NULL )
    2989                 {
    2990                     tordbg( t, "peerIo not created; marking peer %s as unreachable",
    2991                             tr_atomAddrStr( atom ) );
    2992                     atom->myflags |= MYFLAG_UNREACHABLE;
    2993                 }
    2994                 else
    2995                 {
    2996                     tr_handshake * handshake = tr_handshakeNew( io,
    2997                                                                 mgr->session->encryptionMode,
    2998                                                                 myHandshakeDoneCB,
    2999                                                                 mgr );
    3000 
    3001                     assert( tr_peerIoGetTorrentHash( io ) );
    3002 
    3003                     tr_peerIoUnref( io ); /* balanced by the implicit ref in tr_peerIoNewOutgoing() */
    3004 
    3005                     ++newConnectionsThisSecond;
    3006 
    3007                     tr_ptrArrayInsertSorted( &t->outgoingHandshakes, handshake,
    3008                                              handshakeCompare );
    3009                 }
    3010 
    3011                 atom->time = now;
    3012             }
    3013             tr_free( candidates );
    3014         }
    30152851    }
    30162852}
     
    31683004}
    31693005
    3170 struct reconnectTorrentStruct
    3171 {
    3172     tr_torrent * torrent;
    3173     int salt;
    3174 };
    3175 
    3176 static int
    3177 compareReconnectTorrents( const void * va, const void * vb )
    3178 {
    3179     int ai, bi;
    3180     const struct reconnectTorrentStruct * a = va;
    3181     const struct reconnectTorrentStruct * b = vb;
    3182 
    3183     /* primary key: higher priority goes first */
    3184     ai = tr_torrentGetPriority( a->torrent );
    3185     bi = tr_torrentGetPriority( b->torrent );
    3186     if( ai != bi )
    3187         return ai > bi ? -1 : 1;
    3188 
    3189     /* secondary key: since users tend to stare at the screens
    3190      * watching their downloads' progress, give downloads a
    3191      * first shot at attempting outbound peer connections. */
    3192     ai = tr_torrentIsSeed( a->torrent );
    3193     bi = tr_torrentIsSeed( b->torrent );
    3194     if( ai != bi )
    3195         return bi ? -1 : 1;
    3196 
    3197     /* tertiary key: random */
    3198     if( a->salt != b->salt )
    3199         return a->salt - b->salt;
    3200 
    3201     return 0;
    3202 }
     3006static void makeNewPeerConnections( tr_peerMgr * mgr, const int max );
    32033007
    32043008static void
     
    32073011    tr_torrent * tor;
    32083012    tr_peerMgr * mgr = vmgr;
    3209     struct reconnectTorrentStruct * torrents;
    3210     int torrentCount;
    3211     int i;
    3212     uint64_t now;
    3213     managerLock( mgr );
    3214 
    3215     now = tr_date( );
     3013    const uint64_t now = tr_date( );
    32163014
    32173015    /**
     
    32283026    enforceSessionPeerLimit( mgr->session, now );
    32293027
    3230     /**
    3231     ***  try to make new peer connections
    3232     **/
    3233 
    3234     torrentCount = 0;
    3235     torrents = tr_new( struct reconnectTorrentStruct,
    3236                        mgr->session->torrentCount );
    3237     while(( tor = tr_torrentNext( mgr->session, tor ))) {
    3238         if( tor->isRunning ) {
    3239             struct reconnectTorrentStruct * r = torrents + torrentCount++;
    3240             r->torrent = tor;
    3241             r->salt = tr_cryptoWeakRandInt( 1024 );
    3242         }
    3243     }
    3244     qsort( torrents,
    3245            torrentCount, sizeof( struct reconnectTorrentStruct ),
    3246            compareReconnectTorrents );
    3247     for( i=0; i<torrentCount; ++i )
    3248         reconnectTorrent( torrents[i].torrent->torrentPeers );
    3249 
    3250 
    3251     /* cleanup */
    3252     tr_free( torrents );
    3253     tr_timerAddMsec( mgr->reconnectTimer, RECONNECT_PERIOD_MSEC );
    3254     managerUnlock( mgr );
     3028    /* remove crappy peers */
     3029    tor = NULL;
     3030    while(( tor = tr_torrentNext( mgr->session, tor )))
     3031        closeBadPeers( tor->torrentPeers );
     3032
     3033    /* try to make new peer connections */
     3034    makeNewPeerConnections( mgr, MAX_CONNECTIONS_PER_PULSE );
    32553035}
    32563036
     
    33123092        if( tor->isRunning && ( tor->error == TR_STAT_LOCAL_ERROR ))
    33133093            tr_torrentStop( tor );
     3094
     3095    reconnectPulse( 0, 0, mgr );
    33143096
    33153097    tr_timerAddMsec( mgr->bandwidthTimer, BANDWIDTH_PERIOD_MSEC );
     
    34333215    managerUnlock( mgr );
    34343216}
     3217
     3218/***
     3219****
     3220****
     3221****
     3222***/
     3223
     3224static inline tr_bool
     3225isBandwidthMaxedOut( const tr_bandwidth * b,
     3226                     const uint64_t now_msec, tr_direction dir )
     3227{
     3228    if( !tr_bandwidthIsLimited( b, dir ) )
     3229        return FALSE;
     3230    else {
     3231        const double got = tr_bandwidthGetPieceSpeed( b, now_msec, dir );
     3232        const double want = tr_bandwidthGetDesiredSpeed( b, dir );
     3233        return got >= want;
     3234    }
     3235}
     3236
     3237/* is this atom someone that we'd want to initiate a connection to? */
     3238static tr_bool
     3239isPeerCandidate( const tr_torrent * tor, const struct peer_atom * atom, const time_t now )
     3240{
     3241    /* not if we've already got a connection to them... */
     3242    if( peerIsInUse( tor->torrentPeers, atom ) )
     3243        return FALSE;
     3244
     3245    /* not if they're banned... */
     3246    if( atom->myflags & MYFLAG_BANNED )
     3247        return FALSE;
     3248
     3249    /* not if we just tried them already */
     3250    if( ( now - atom->time ) < getReconnectIntervalSecs( atom, now ) )
     3251        return FALSE;
     3252
     3253    /* not if we're both seeds */
     3254    if( tr_torrentIsSeed( tor ) )
     3255        if( atomIsSeed( atom ) || ( atom->uploadOnly == UPLOAD_ONLY_YES ) )
     3256            return FALSE;
     3257 
     3258    /* not if they're blocklisted */
     3259    /* FIXME: maybe we should remove this atom altogether? */
     3260    if( tr_sessionIsAddressBlocked( tor->session, &atom->addr ) )
     3261        return FALSE;
     3262
     3263    return TRUE;
     3264}
     3265
     3266struct peer_candidate
     3267{
     3268    int salt;
     3269    tr_torrent * tor;
     3270    struct peer_atom * atom;
     3271};
     3272
     3273static int
     3274compareSeedProbabilities( int a, int b )
     3275{
     3276    /* 1. smaller numbers are better
     3277       2. prefer leechers to unknown
     3278       3. prefer unknown to seeds (FIXME: this is a simplistic test) */
     3279    if( a == 100 ) a = 101;
     3280    if( b == 100 ) b = 101;
     3281    if( a == -1 ) a = 100;
     3282    if( b == -1 ) b = 100;
     3283    return a - b;
     3284}
     3285
     3286static tr_bool
     3287torrentWasRecentlyStarted( const tr_torrent * tor )
     3288{
     3289    return difftime( tr_time( ), tor->startDate ) < 120;
     3290}
     3291
     3292/* sort an array of peer candidates */
     3293static int
     3294comparePeerCandidates( const void * va, const void * vb )
     3295{
     3296    int i, ai, bi;
     3297    tr_bool af, bf;
     3298    const struct peer_candidate * a = va;
     3299    const struct peer_candidate * b = vb;
     3300
     3301    /* prefer peers we've connected to, or never tried, over peers we failed to connect to. */
     3302    af = a->atom->lastConnectionAt < a->atom->lastConnectionAttemptAt;
     3303    bf = b->atom->lastConnectionAt < b->atom->lastConnectionAttemptAt;
     3304    if( af != bf )
     3305        return af ? 1 : -1;
     3306
     3307    /* prefer the one we attempted least recently (to cycle through all peers) */
     3308    if( a->atom->lastConnectionAttemptAt != b->atom->lastConnectionAttemptAt )
     3309        return a->atom->lastConnectionAttemptAt < b->atom->lastConnectionAttemptAt ? -1 : 1;
     3310
     3311    /* prefer peers belonging to a torrent of a higher priority */
     3312    ai = tr_torrentGetPriority( a->tor );
     3313    bi = tr_torrentGetPriority( b->tor );
     3314    if( ai != bi )
     3315        return ai > bi ? -1 : 1;
     3316
     3317    /* prefer recently-started torrents */
     3318    af = torrentWasRecentlyStarted( a->tor );
     3319    bf = torrentWasRecentlyStarted( a->tor );
     3320    if( af != bf )
     3321        return af ? -1 : 1;
     3322
     3323    /* prefer peers that we might have a chance of uploading to */
     3324    if(( i = compareSeedProbabilities( a->atom->seedProbability, b->atom->seedProbability )))
     3325        return i;
     3326
     3327    /* salt */
     3328    return a->salt - b->salt;
     3329}
     3330
     3331/** @return an array of all the atoms we might want to connect to */
     3332static struct peer_candidate*
     3333getPeerCandidates( tr_session * session, int * candidateCount )
     3334{
     3335    int n;
     3336    tr_torrent * tor;
     3337    struct peer_candidate * candidates;
     3338    struct peer_candidate * walk;
     3339    const time_t now = tr_time( );
     3340    const uint64_t now_msec = tr_date( );
     3341
     3342    /* don't start any new handshakes if we're full up */
     3343    n = 0;
     3344    tor= NULL;
     3345    while(( tor = tr_torrentNext( session, tor )))
     3346        n += tr_ptrArraySize( &tor->torrentPeers->peers );
     3347    if( tr_sessionGetPeerLimit( session ) <= n ) {
     3348        *candidateCount = 0;
     3349        return NULL;
     3350    }
     3351
     3352    /* allocate an array of candidates */
     3353    n = 0;
     3354    tor= NULL;
     3355    while(( tor = tr_torrentNext( session, tor )))
     3356        n += tr_ptrArraySize( &tor->torrentPeers->pool );
     3357    walk = candidates = tr_new( struct peer_candidate, n );
     3358
     3359    /* populate the candidate array */
     3360    tor = NULL;
     3361    while(( tor = tr_torrentNext( session, tor )))
     3362    {
     3363        int i, nAtoms;
     3364        struct peer_atom ** atoms;
     3365
     3366        if( !tor->torrentPeers->isRunning )
     3367            continue;
     3368
     3369        /* if we've already got enough peers in this torrent... */
     3370        if( tr_torrentGetPeerLimit( tor ) <= tr_ptrArraySize( &tor->torrentPeers->peers ) )
     3371            continue;
     3372
     3373        /* if we've already got enough speed in this torrent... */
     3374        if( tr_torrentIsSeed( tor ) && isBandwidthMaxedOut( tor->bandwidth, now_msec, TR_UP ) )
     3375            continue;
     3376
     3377        atoms = (struct peer_atom**) tr_ptrArrayPeek( &tor->torrentPeers->pool, &nAtoms );
     3378        for( i=0; i<nAtoms; ++i )
     3379        {
     3380            struct peer_atom * atom = atoms[i];
     3381
     3382            if( isPeerCandidate( tor, atom, now ) )
     3383            {
     3384                walk->tor = tor;
     3385                walk->atom = atom;
     3386                walk->salt = tr_cryptoWeakRandInt( 4096 );
     3387                ++walk;
     3388            }
     3389        }
     3390    }
     3391
     3392    *candidateCount = walk - candidates;
     3393    if( *candidateCount > 1 )
     3394        qsort( candidates, *candidateCount, sizeof( struct peer_candidate ), comparePeerCandidates );
     3395    return candidates;
     3396}
     3397
     3398static void
     3399initiateConnection( tr_peerMgr * mgr, Torrent * t, struct peer_atom * atom )
     3400{
     3401    tr_peerIo * io;
     3402    const time_t now = tr_time( );
     3403
     3404    tordbg( t, "Starting an OUTGOING connection with %s", tr_atomAddrStr( atom ) );
     3405
     3406    io = tr_peerIoNewOutgoing( mgr->session,
     3407                               mgr->session->bandwidth,
     3408                               &atom->addr,
     3409                               atom->port,
     3410                               t->tor->info.hash,
     3411                               t->tor->completeness == TR_SEED );
     3412
     3413    if( io == NULL )
     3414    {
     3415        tordbg( t, "peerIo not created; marking peer %s as unreachable",
     3416                tr_atomAddrStr( atom ) );
     3417        atom->myflags |= MYFLAG_UNREACHABLE;
     3418        atom->numFails++;
     3419    }
     3420    else
     3421    {
     3422        tr_handshake * handshake = tr_handshakeNew( io,
     3423                                                    mgr->session->encryptionMode,
     3424                                                    myHandshakeDoneCB,
     3425                                                    mgr );
     3426
     3427        assert( tr_peerIoGetTorrentHash( io ) );
     3428
     3429        tr_peerIoUnref( io ); /* balanced by the implicit ref in tr_peerIoNewOutgoing() */
     3430
     3431        tr_ptrArrayInsertSorted( &t->outgoingHandshakes, handshake,
     3432                                 handshakeCompare );
     3433    }
     3434
     3435    atom->lastConnectionAttemptAt = now;
     3436    atom->time = now;
     3437}
     3438
     3439static void
     3440initiateCandidateConnection( tr_peerMgr * mgr, struct peer_candidate * c )
     3441{
     3442#if 0
     3443    fprintf( stderr, "Starting an OUTGOING connection with %s - [%s] seedProbability==%d; %s, %s\n",
     3444             tr_atomAddrStr( c->atom ),
     3445             tr_torrentName( c->tor ),
     3446             (int)c->atom->seedProbability,
     3447             tr_torrentIsPrivate( c->tor ) ? "private" : "public",
     3448             tr_torrentIsSeed( c->tor ) ? "seed" : "downloader" );
     3449#endif
     3450
     3451    initiateConnection( mgr, c->tor->torrentPeers, c->atom );
     3452}
     3453
     3454static void
     3455makeNewPeerConnections( struct tr_peerMgr * mgr, const int max )
     3456{
     3457    int i, n;
     3458    struct peer_candidate * candidates;
     3459
     3460    candidates = getPeerCandidates( mgr->session, &n );
     3461
     3462    for( i=0; i<n && i<max; ++i )
     3463        initiateCandidateConnection( mgr, &candidates[i] );
     3464
     3465    tr_free( candidates );
     3466}
  • trunk/libtransmission/peer-mgr.h

    r10332 r10500  
    173173                               size_t      * setme_pex_count );
    174174
     175/**
     176 * @param seedProbability [0..100] for likelihood that the peer is a seed; -1 for unknown
     177 */
    175178void tr_peerMgrAddPex( tr_torrent     * tor,
    176179                       uint8_t          from,
    177                        const tr_pex   * pex );
     180                       const tr_pex   * pex,
     181                       int8_t           seedProbability );
     182
     183void tr_peerMgrMarkAllAsSeeds( tr_torrent * tor );
    178184
    179185void tr_peerMgrSetBlame( tr_torrent        * tor,
  • trunk/libtransmission/peer-msgs.c

    r10347 r10500  
    465465**/
    466466
    467 static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0, 0 };
     467static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
    468468
    469469static void
     
    482482    e.eventType = TR_PEER_ERROR;
    483483    e.err = err;
    484     publish( msgs, &e );
    485 }
    486 
    487 static void
    488 fireUploadOnly( tr_peermsgs * msgs, tr_bool uploadOnly )
    489 {
    490     tr_peer_event e = blankEvent;
    491     e.eventType = TR_PEER_UPLOAD_ONLY;
    492     e.uploadOnly = uploadOnly;
    493484    publish( msgs, &e );
    494485}
     
    890881    size_t addr_len;
    891882    tr_pex pex;
     883    int8_t seedProbability = -1;
    892884
    893885    memset( &pex, 0, sizeof( tr_pex ) );
     
    935927
    936928    /* look for upload_only (BEP 21) */
    937     if( tr_bencDictFindInt( &val, "upload_only", &i ) ) {
    938         fireUploadOnly( msgs, i!=0 );
    939         if( i )
    940             pex.flags |= ADDED_F_SEED_FLAG;
    941     }
     929    if( tr_bencDictFindInt( &val, "upload_only", &i ) )
     930        seedProbability = i==0 ? 0 : 100;
    942931
    943932    /* get peer's listening port */
     
    954943        pex.addr.type = TR_AF_INET;
    955944        memcpy( &pex.addr.addr.addr4, addr, 4 );
    956         tr_peerMgrAddPex( msgs->torrent, TR_PEER_FROM_LTEP, &pex );
     945        tr_peerMgrAddPex( msgs->torrent, TR_PEER_FROM_LTEP, &pex, seedProbability );
    957946    }
    958947
     
    963952        pex.addr.type = TR_AF_INET6;
    964953        memcpy( &pex.addr.addr.addr6, addr, 16 );
    965         tr_peerMgrAddPex( msgs->torrent, TR_PEER_FROM_LTEP, &pex );
     954        tr_peerMgrAddPex( msgs->torrent, TR_PEER_FROM_LTEP, &pex, seedProbability );
    966955    }
    967956
     
    10791068            n = MIN( n, MAX_PEX_PEER_COUNT );
    10801069            for( i=0; i<n; ++i )
    1081                 tr_peerMgrAddPex( tor, TR_PEER_FROM_PEX, pex + i );
     1070            {
     1071                int seedProbability = -1;
     1072                if( added_f_len < n ) seedProbability = ( added_f[i] & ADDED_F_SEED_FLAG ) ? 100 : 0;
     1073                tr_peerMgrAddPex( tor, TR_PEER_FROM_PEX, pex+i, seedProbability );
     1074            }
    10821075
    10831076            tr_free( pex );
     
    10961089            n = MIN( n, MAX_PEX_PEER_COUNT );
    10971090            for( i=0; i<n; ++i )
    1098                 tr_peerMgrAddPex( tor, TR_PEER_FROM_PEX, pex + i );
     1091            {
     1092                int seedProbability = -1;
     1093                if( added_f_len < n ) seedProbability = ( added_f[i] & ADDED_F_SEED_FLAG ) ? 100 : 0;
     1094                tr_peerMgrAddPex( tor, TR_PEER_FROM_PEX, pex+i, seedProbability );
     1095            }
    10991096
    11001097            tr_free( pex );
  • trunk/libtransmission/resume.c

    r10414 r10500  
    117117        if( tr_isPex( &pex ) )
    118118        {
    119             tr_peerMgrAddPex( tor, TR_PEER_FROM_RESUME, &pex );
     119            tr_peerMgrAddPex( tor, TR_PEER_FROM_RESUME, &pex, -1 );
    120120            ++numAdded;
    121121        }
  • trunk/libtransmission/torrent.c

    r10496 r10500  
    355355                   void * user_data )
    356356{
    357     tr_torrent *       tor = user_data;
     357    tr_torrent * tor = user_data;
    358358    tr_tracker_event * event = vevent;
    359359
     
    362362        case TR_TRACKER_PEERS:
    363363        {
    364             size_t   i, n;
     364            size_t i, n;
     365            const int seedProbability = event->seedProbability;
     366            const tr_bool allAreSeeds = seedProbability == 100;
    365367            tr_pex * pex = tr_peerMgrArrayToPex( event->compact,
    366368                                                 event->compactLen, &n );
    367              if( event->allAreSeeds )
     369             if( allAreSeeds )
    368370                tr_tordbg( tor, "Got %d seeds from tracker", (int)n );
    369371            else
     
    371373
    372374            for( i = 0; i < n; ++i )
    373             {
    374                 if( event->allAreSeeds )
    375                     pex[i].flags |= ADDED_F_SEED_FLAG;
    376                 tr_peerMgrAddPex( tor, TR_PEER_FROM_TRACKER, pex + i );
    377             }
     375                tr_peerMgrAddPex( tor, TR_PEER_FROM_TRACKER, pex+i, seedProbability );
     376
     377            if( allAreSeeds && tr_torrentIsPrivate( tor ) )
     378                tr_peerMgrMarkAllAsSeeds( tor );
    378379
    379380            tr_free( pex );
  • trunk/libtransmission/tr-dht.c

    r10428 r10500  
    614614                pex = tr_peerMgrCompact6ToPex(data, data_len, NULL, 0, &n);
    615615            for( i=0; i<n; ++i )
    616                 tr_peerMgrAddPex( tor, TR_PEER_FROM_DHT, pex+i );
     616                tr_peerMgrAddPex( tor, TR_PEER_FROM_DHT, pex+i, -1 );
    617617            tr_free(pex);
    618618            tr_tordbg(tor, "Learned %d%s peers from DHT",
  • trunk/libtransmission/webseed.c

    r10031 r10500  
    5050***/
    5151
    52 static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0, 0 };
     52static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
    5353
    5454static void
Note: See TracChangeset for help on using the changeset viewer.