Changeset 7455


Ignore:
Timestamp:
Dec 22, 2008, 12:51:14 AM (12 years ago)
Author:
charles
Message:

(1.4x libT) backport handshake, peer, bandwidth, peer-io to 1.4x.

Location:
branches/1.4x
Files:
1 added
1 deleted
24 edited

Legend:

Unmodified
Added
Removed
  • branches/1.4x/configure.ac

    r7378 r7455  
    44dnl         "0" for stable, supported releases
    55dnl these should be the only two lines you need to change
    6 m4_define([user_agent_prefix],1.41)
    7 m4_define([peer_id_prefix],-TR1410-)
     6m4_define([user_agent_prefix],[1.41b4])
     7m4_define([peer_id_prefix],[-TR141X-])
    88
    99AC_INIT([transmission],[user_agent_prefix],[http://trac.transmissionbt.com/newticket])
  • branches/1.4x/libtransmission/Makefile.am

    r7294 r7455  
    110110    clients-test \
    111111    json-test \
     112    peer-msgs-test \
    112113    rpc-test \
    113     test-fastset \
    114114    test-peer-id \
    115115    utils-test
     
    152152rpc_test_LDFLAGS = ${apps_ldflags}
    153153
    154 test_fastset_SOURCES = test-fastset.c
    155 test_fastset_LDADD = ${apps_ldadd}
    156 test_fastset_LDFLAGS = ${apps_ldflags}
     154peer_msgs_test_SOURCES = peer-msgs-test.c
     155peer_msgs_test_LDADD = ${apps_ldadd}
     156peer_msgs_test_LDFLAGS = ${apps_ldflags}
    157157
    158158test_peer_id_SOURCES = test-peer-id.c
  • branches/1.4x/libtransmission/bandwidth.c

    r7403 r7455  
    11/*
    2  * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2008 Charles Kerr <charles@transmissionbt.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    1919#include "bandwidth.h"
    2020#include "crypto.h"
    21 #include "iobuf.h"
     21#include "peer-io.h"
    2222#include "ptrarray.h"
    2323#include "utils.h"
     
    100100    tr_session * session;
    101101    tr_ptrArray * children; /* struct tr_bandwidth */
    102     tr_ptrArray * iobufs; /* struct tr_iobuf */
     102    tr_ptrArray * peers; /* tr_peerIo */
    103103};
    104104
     
    113113}
    114114
    115 static int
    116 isBandwidth( const tr_bandwidth * b )
     115tr_bool
     116tr_isBandwidth( const tr_bandwidth * b )
    117117{
    118118    return ( b != NULL ) && ( b->magicNumber == MAGIC_NUMBER );
    119 }
    120 
    121 static int
    122 isDirection( const tr_direction dir )
    123 {
    124     return ( dir == TR_UP ) || ( dir == TR_DOWN );
    125119}
    126120
     
    135129    b->session = session;
    136130    b->children = tr_ptrArrayNew( );
    137     b->iobufs = tr_ptrArrayNew( );
     131    b->peers = tr_ptrArrayNew( );
    138132    b->magicNumber = MAGIC_NUMBER;
    139     b->band[TR_UP].honorParentLimits = 1;
    140     b->band[TR_DOWN].honorParentLimits = 1;
     133    b->band[TR_UP].honorParentLimits = TRUE;
     134    b->band[TR_DOWN].honorParentLimits = TRUE;
    141135    tr_bandwidthSetParent( b, parent );
    142136    return b;
     
    146140tr_bandwidthFree( tr_bandwidth * b )
    147141{
    148     assert( isBandwidth( b ) );
     142    assert( tr_isBandwidth( b ) );
    149143
    150144    tr_bandwidthSetParent( b, NULL );
    151     tr_ptrArrayFree( b->iobufs, NULL );
     145    tr_ptrArrayFree( b->peers, NULL );
    152146    tr_ptrArrayFree( b->children, NULL );
    153147    b->magicNumber = 0xDEAD;
     
    163157                       tr_bandwidth  * parent )
    164158{
    165     assert( isBandwidth( b ) );
     159    assert( tr_isBandwidth( b ) );
    166160    assert( b != parent );
    167161
    168162    if( b->parent )
    169163    {
    170         assert( isBandwidth( b->parent ) );
     164        assert( tr_isBandwidth( b->parent ) );
    171165
    172166        tr_ptrArrayRemoveSorted( b->parent->children, b, comparePointers );
    173         b->parent= NULL;
     167        b->parent = NULL;
    174168    }
    175169
    176170    if( parent )
    177171    {
    178         assert( isBandwidth( parent ) );
     172        assert( tr_isBandwidth( parent ) );
    179173        assert( parent->parent != b );
    180174
     
    187181tr_bandwidthHonorParentLimits( tr_bandwidth  * b,
    188182                               tr_direction    dir,
    189                                int             honorParentLimits )
    190 {
    191     assert( isBandwidth( b ) );
    192     assert( isDirection( dir ) );
    193 
    194     b->band[dir].honorParentLimits = honorParentLimits != 0;
     183                               tr_bool         honorParentLimits )
     184{
     185    assert( tr_isBandwidth( b ) );
     186    assert( tr_isDirection( dir ) );
     187
     188    b->band[dir].honorParentLimits = honorParentLimits;
    195189}
    196190
     
    204198                             double          desiredSpeed )
    205199{
    206     assert( isBandwidth( b ) );
    207     assert( isDirection( dir ) );
     200    assert( tr_isBandwidth( b ) );
     201    assert( tr_isDirection( dir ) );
    208202
    209203    b->band[dir].desiredSpeed = desiredSpeed;
     
    214208                             tr_direction          dir )
    215209{
    216     assert( isBandwidth( b ) );
    217     assert( isDirection( dir ) );
     210    assert( tr_isBandwidth( b ) );
     211    assert( tr_isDirection( dir ) );
    218212
    219213    return b->band[dir].desiredSpeed;
     
    223217tr_bandwidthSetLimited( tr_bandwidth  * b,
    224218                        tr_direction    dir,
    225                         int             isLimited )
    226 {
    227     assert( isBandwidth( b ) );
    228     assert( isDirection( dir ) );
    229 
    230     b->band[dir].isLimited = isLimited != 0;
    231 }
    232 
    233 int
     219                        tr_bool         isLimited )
     220{
     221    assert( tr_isBandwidth( b ) );
     222    assert( tr_isDirection( dir ) );
     223
     224    b->band[dir].isLimited = isLimited;
     225}
     226
     227tr_bool
    234228tr_bandwidthIsLimited( const tr_bandwidth  * b,
    235229                       tr_direction          dir )
    236230{
    237     assert( isBandwidth( b ) );
    238     assert( isDirection( dir ) );
    239 
    240     return b->band[dir].isLimited != 0;
     231    assert( tr_isBandwidth( b ) );
     232    assert( tr_isDirection( dir ) );
     233
     234    return b->band[dir].isLimited;
    241235}
    242236
     
    250244                   tr_direction    dir,
    251245                   int             period_msec,
    252                    tr_ptrArray   * iobuf_pool )
    253 {
    254     assert( isBandwidth( b ) );
    255     assert( isDirection( dir ) );
    256 
     246                   tr_ptrArray   * peer_pool )
     247{
     248    assert( tr_isBandwidth( b ) );
     249    assert( tr_isDirection( dir ) );
     250
     251    /* set the available bandwidth */
    257252    if( b->band[dir].isLimited )
    258253    {
     
    269264    }
    270265
     266    /* traverse & repeat for the subtree */
    271267    {
    272268        int i;
    273         const int n = tr_ptrArraySize( b->iobufs );
     269        const int n = tr_ptrArraySize( b->peers );
    274270        for( i=0; i<n; ++i )
    275             tr_ptrArrayAppend( iobuf_pool, tr_ptrArrayNth( b->iobufs, i ) );
     271            tr_ptrArrayAppend( peer_pool, tr_ptrArrayNth( b->peers, i ) );
    276272    }
    277273
    278274#ifdef DEBUG_DIRECTION
    279275if( ( dir == DEBUG_DIRECTION ) && ( n > 1 ) )
    280 fprintf( stderr, "bandwidth %p has %d iobufs\n", b, n );
     276fprintf( stderr, "bandwidth %p has %d peers\n", b, n );
    281277#endif
    282278
     
    286282        struct tr_bandwidth ** children = (struct tr_bandwidth**) tr_ptrArrayPeek( b->children, &n );
    287283        for( i=0; i<n; ++i )
    288             allocateBandwidth( children[i], dir, period_msec, iobuf_pool );
     284            allocateBandwidth( children[i], dir, period_msec, peer_pool );
    289285    }
    290286}
     
    295291                      int             period_msec )
    296292{
    297     int n;
     293    int i, n, peerCount;
    298294    tr_ptrArray * tmp;
    299     struct tr_iobuf ** buffers;
    300     const size_t chunkSize = 1024; /* arbitrary */
    301 
     295    struct tr_peerIo ** peers;
     296
     297    /* allocateBandwidth() is a helper function with two purposes:
     298     * 1. allocate bandwidth to b and its subtree
     299     * 2. accumulate an array of all the peerIos from b and its subtree. */
    302300    tmp = tr_ptrArrayNew( );
    303301    allocateBandwidth( b, dir, period_msec, tmp );
    304     buffers = (struct tr_iobuf**) tr_ptrArrayPeek( tmp, &n );
    305 
    306     /* loop through all the peers, reading and writing in small chunks,
    307      * until we run out of bandwidth or peers. we do it this way to
    308      * prevent one peer from using up all the bandwidth */
    309     while( n > 0 )
    310     {
    311         int i;
    312         for( i=0; i<n; )
    313         {
    314             int byteCount;
    315             if( dir == TR_UP )
    316                 byteCount = tr_iobuf_flush_output_buffer( buffers[i], chunkSize );
    317             else
    318                 byteCount = tr_iobuf_tryread( buffers[i], chunkSize );
    319             if( byteCount == (int)chunkSize )
    320                 ++i;
    321             else
    322                 buffers[i] = buffers[--n];
     302    peers = (struct tr_peerIo**) tr_ptrArrayPeek( tmp, &peerCount );
     303
     304    /* Stop all peers from listening for the socket to be ready for IO.
     305     * See "Second phase of IO" lower in this function for more info. */
     306    for( i=0; i<peerCount; ++i )
     307        tr_peerIoSetEnabled( peers[i], dir, FALSE );
     308
     309    /* First phase of IO.  Tries to distribute bandwidth fairly to keep faster
     310     * peers from starving the others.  Loop through the peers, giving each a
     311     * small chunk of bandwidth.  Keep looping until we run out of bandwidth
     312     * or pweers that can use it */
     313    n = peerCount;
     314    i = n ? tr_cryptoWeakRandInt( n ) : 0; /* pick a random starting point */
     315    for( ; n>0; )
     316    {
     317        const int increment = n==1 ? 4096 : 1024;
     318        const int byteCount = tr_peerIoFlush( peers[i], dir, increment);
     319
     320        if( byteCount == increment )
     321            ++i;
     322        else {
     323            /* peer is done writing for now; move it to the end of the list */
     324            tr_peerIo * tmp = peers[i];
     325            peers[i] = peers[n-1];
     326            peers[n-1] = tmp;
     327            --n;
    323328        }
    324     }
     329
     330        assert( i <= n );
     331        if( i == n )
     332            i = 0;
     333    }
     334
     335    /* Second phase of IO.  To help us scale in high bandwidth situations,
     336     * enable on-demand IO for peers with bandwidth left to burn.
     337     * This on-demand IO is enabled until (1) the peer runs out of bandwidth,
     338     * or (2) the next tr_bandwidthAllocate() call, when we start over again. */
     339    for( i=0; i<peerCount; ++i )
     340        if( tr_peerIoHasBandwidthLeft( peers[i], dir ) )
     341            tr_peerIoSetEnabled( peers[i], dir, TRUE );
    325342
    326343    /* cleanup */
     
    333350
    334351void
    335 tr_bandwidthAddBuffer( tr_bandwidth        * b,
    336                        struct tr_iobuf     * iobuf )
    337 {
    338     assert( isBandwidth( b ) );
    339     assert( iobuf );
    340 
    341     tr_ptrArrayInsertSorted( b->iobufs, iobuf, comparePointers );
    342 }
    343 
    344 void
    345 tr_bandwidthRemoveBuffer( tr_bandwidth        * b,
    346                           struct tr_iobuf     * iobuf )
    347 {
    348     assert( isBandwidth( b ) );
    349     assert( iobuf );
    350 
    351     tr_ptrArrayRemoveSorted( b->iobufs, iobuf, comparePointers );
     352tr_bandwidthAddPeer( tr_bandwidth   * b,
     353                     tr_peerIo      * peerIo )
     354{
     355    assert( tr_isBandwidth( b ) );
     356    assert( tr_isPeerIo( peerIo ) );
     357
     358    tr_ptrArrayInsertSorted( b->peers, peerIo, comparePointers );
     359}
     360
     361void
     362tr_bandwidthRemovePeer( tr_bandwidth  * b,
     363                        tr_peerIo     * peerIo )
     364{
     365    assert( tr_isBandwidth( b ) );
     366    assert( tr_isPeerIo( peerIo ) );
     367
     368    tr_ptrArrayRemoveSorted( b->peers, peerIo, comparePointers );
    352369}
    353370
     
    361378                   size_t                byteCount )
    362379{
    363     assert( isBandwidth( b ) );
    364     assert( isDirection( dir ) );
     380    assert( tr_isBandwidth( b ) );
     381    assert( tr_isDirection( dir ) );
    365382
    366383    if( b )
     
    379396tr_bandwidthGetRawSpeed( const tr_bandwidth * b, tr_direction dir )
    380397{
    381     assert( isBandwidth( b ) );
    382     assert( isDirection( dir ) );
     398    assert( tr_isBandwidth( b ) );
     399    assert( tr_isDirection( dir ) );
    383400
    384401    return getSpeed( &b->band[dir].raw, HISTORY_MSEC );
     
    388405tr_bandwidthGetPieceSpeed( const tr_bandwidth * b, tr_direction dir )
    389406{
    390     assert( isBandwidth( b ) );
    391     assert( isDirection( dir ) );
     407    assert( tr_isBandwidth( b ) );
     408    assert( tr_isDirection( dir ) );
    392409
    393410    return getSpeed( &b->band[dir].piece, HISTORY_MSEC );
     
    398415                  tr_direction    dir,
    399416                  size_t          byteCount,
    400                   int             isPieceData )
     417                  tr_bool         isPieceData )
    401418{
    402419    struct tr_band * band;
    403420    size_t oldBytesLeft;
    404421
    405     assert( isBandwidth( b ) );
    406     assert( isDirection( dir ) );
     422    assert( tr_isBandwidth( b ) );
     423    assert( tr_isDirection( dir ) );
    407424
    408425    band = &b->band[dir];
  • branches/1.4x/libtransmission/bandwidth.h

    r7177 r7455  
    11/*
    2  * This file Copyright (C) 2008 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2008 Charles Kerr <charles@transmissionbt.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    5959 *   bandwidth they can safely use.
    6060 */
     61
    6162typedef struct tr_bandwidth tr_bandwidth;
     63
     64struct tr_peerIo;
    6265
    6366/**
     
    7275/** @brief destroy a tr_bandwidth object */
    7376void     tr_bandwidthFree             ( tr_bandwidth        * bandwidth );
     77
     78/** @brief test to see if the pointer refers to a live bandwidth object */
     79tr_bool  tr_isBandwidth               ( const tr_bandwidth  * bandwidth );
    7480
    7581/******
     
    98104void    tr_bandwidthSetLimited        ( tr_bandwidth        * bandwidth,
    99105                                        tr_direction          direction,
    100                                         int                   isLimited );
     106                                        tr_bool               isLimited );
    101107
    102108/**
    103109 * @return nonzero if this bandwidth throttles its iobufs' speeds
    104110 */
    105 int    tr_bandwidthIsLimited         ( const tr_bandwidth  * bandwidth,
     111tr_bool tr_bandwidthIsLimited         ( const tr_bandwidth  * bandwidth,
    106112                                        tr_direction          direction );
    107113
     
    143149                                        tr_direction          direction,
    144150                                        size_t                byteCount,
    145                                         int                   isPieceData );
     151                                        tr_bool               isPieceData );
    146152
    147153/******
     
    160166void    tr_bandwidthHonorParentLimits ( tr_bandwidth        * bandwidth,
    161167                                        tr_direction          direction,
    162                                         int                   isEnabled );
     168                                        tr_bool               isEnabled );
    163169
    164170/******
     
    167173
    168174/**
    169  * @brief add an iobuf to this bandwidth's list of iobufs.
     175 * @brief add a tr_peerIo to this bandwidth's list.
    170176 * They will be notified when more bandwidth is made available for them to consume.
    171177 */
    172 void    tr_bandwidthAddBuffer         ( tr_bandwidth        * bandwidth,
    173                                         struct tr_iobuf     * iobuf );
     178void    tr_bandwidthAddPeer           ( tr_bandwidth        * bandwidth,
     179                                        struct tr_peerIo    * peerIo );
    174180
    175181/**
    176182 * @brief remove an iobuf from this bandwidth's list of iobufs.
    177183 */
    178 void    tr_bandwidthRemoveBuffer      ( tr_bandwidth        * bandwidth,
    179                                         struct tr_iobuf     * iobuf );
     184void    tr_bandwidthRemovePeer        ( tr_bandwidth        * bandwidth,
     185                                        struct tr_peerIo    * peerIo );
    180186
    181187#endif
  • branches/1.4x/libtransmission/bencode-test.c

    r6842 r7455  
    397397    int i;
    398398
    399     if( ( i = testInt( ) ) )
     399    if(( i = testInt( )))
    400400        return i;
    401401
    402     if( ( i = testStr( ) ) )
     402    if(( i = testStr( )))
    403403        return i;
    404404
    405     if( ( i = testParse( ) ) )
     405    if(( i = testParse( )))
    406406        return i;
    407407
    408     if( ( i = testJSON( ) ) )
     408    if(( i = testJSON( )))
    409409        return i;
    410410
  • branches/1.4x/libtransmission/fastresume.c

    r6896 r7455  
    5555#include "completion.h"
    5656#include "fastresume.h"
     57#include "net.h"
    5758#include "peer-mgr.h"
    5859#include "platform.h"
  • branches/1.4x/libtransmission/handshake.c

    r7341 r7455  
    11/*
    2  * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@transmissionbt.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    2525#include "crypto.h"
    2626#include "handshake.h"
    27 #include "iobuf.h"
    2827#include "peer-io.h"
    2928#include "peer-mgr.h"
     
    3433/* enable LibTransmission extension protocol */
    3534#define ENABLE_LTEP * /
    36 
    37 /* enable fast peers extension protocol */
    38 /* #define ENABLE_FASTPEER */
     35/* fast extensions */
     36#define ENABLE_FAST * /
    3937
    4038/***
     
    7371#endif
    7472
    75 #ifdef ENABLE_FASTPEER
    76  #define HANDSHAKE_HAS_FASTEXT( bits ) ( ( ( bits )[7] & 0x04 ) ? 1 : 0 )
    77  #define HANDSHAKE_SET_FASTEXT( bits ) ( ( bits )[7] |= 0x04 )
    78 #else
    79  #define HANDSHAKE_HAS_FASTEXT( bits ) ( 0 )
    80  #define HANDSHAKE_SET_FASTEXT( bits ) ( (void)0 )
    81 #endif
     73#ifdef ENABLE_FAST 
     74 #define HANDSHAKE_HAS_FASTEXT( bits ) ( ( ( bits )[7] & 0x04 ) ? 1 : 0 ) 
     75 #define HANDSHAKE_SET_FASTEXT( bits ) ( ( bits )[7] |= 0x04 ) 
     76#else 
     77 #define HANDSHAKE_HAS_FASTEXT( bits ) ( 0 ) 
     78 #define HANDSHAKE_SET_FASTEXT( bits ) ( (void)0 ) 
     79#endif 
    8280
    8381/* http://www.azureuswiki.com/index.php/Extension_negotiation_protocol
     
    9492    tr_peerIo *           io;
    9593    tr_crypto *           crypto;
    96     struct tr_handle *    handle;
     94    tr_session *          session;
    9795    uint8_t               myPublicKey[KEY_LEN];
    9896    uint8_t               mySecret[KEY_LEN];
     
    208206    uint8_t          * walk = buf;
    209207    const uint8_t    * torrentHash = tr_cryptoGetTorrentHash( handshake->crypto );
    210     const tr_torrent * tor = tr_torrentFindFromHash( handshake->handle, torrentHash );
     208    const tr_torrent * tor = tr_torrentFindFromHash( handshake->session, torrentHash );
    211209    const uint8_t    * peer_id = tor && tor->peer_id ? tor->peer_id : tr_getPeerId( );
    212210
     
    250248    const uint8_t * peer_id;
    251249
    252     dbgmsg( handshake, "payload: need %d, got %d", (int)HANDSHAKE_SIZE,
    253            (int)EVBUFFER_LENGTH( inbuf ) );
     250    dbgmsg( handshake, "payload: need %d, got %zu",
     251            (int)HANDSHAKE_SIZE, EVBUFFER_LENGTH( inbuf ) );
    254252
    255253    if( EVBUFFER_LENGTH( inbuf ) < HANDSHAKE_SIZE )
     
    267265    tr_peerIoReadBytes( handshake->io, inbuf, hash, sizeof( hash ) );
    268266    assert( tr_peerIoHasTorrentHash( handshake->io ) );
    269     if( !tr_torrentExists( handshake->handle, hash )
     267    if( !tr_torrentExists( handshake->session, hash )
    270268      || memcmp( hash, tr_peerIoGetTorrentHash( handshake->io ),
    271269                 SHA_DIGEST_LENGTH ) )
     
    285283            handshake->peer_id );
    286284
    287     tor = tr_torrentFindFromHash( handshake->handle, hash );
     285    tor = tr_torrentFindFromHash( handshake->session, hash );
    288286    peer_id = tor && tor->peer_id ? tor->peer_id : tr_getPeerId( );
    289287    if( !memcmp( handshake->peer_id, peer_id, PEER_ID_LEN ) )
     
    297295    **/
    298296
    299     if( HANDSHAKE_HAS_LTEP( reserved ) )
    300     {
    301         tr_peerIoEnableLTEP( handshake->io, 1 );
    302         dbgmsg( handshake, "using ltep" );
    303     }
    304 
    305     if( HANDSHAKE_HAS_FASTEXT( reserved ) )
    306     {
    307         tr_peerIoEnableFEXT( handshake->io, 1 );
    308         dbgmsg( handshake, "using fext" );
    309     }
     297    tr_peerIoEnableLTEP( handshake->io, HANDSHAKE_HAS_LTEP( reserved ) );
     298
     299    tr_peerIoEnableFEXT( handshake->io, HANDSHAKE_HAS_FASTEXT( reserved ) );
    310300
    311301    return HANDSHAKE_OK;
     
    410400        return READ_LATER;
    411401
    412     isEncrypted = memcmp( EVBUFFER_DATA(
    413                               inbuf ), HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
     402    isEncrypted = memcmp( EVBUFFER_DATA( inbuf ), HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
    414403    if( isEncrypted )
    415404    {
     
    422411           ( isEncrypted ? "encrypted" : "plaintext" ) );
    423412
    424     tr_peerIoSetEncryption(
    425         handshake->io, isEncrypted ? PEER_ENCRYPTION_RC4
    426         : PEER_ENCRYPTION_NONE );
     413    tr_peerIoSetEncryption( handshake->io, isEncrypted ? PEER_ENCRYPTION_RC4
     414                                                       : PEER_ENCRYPTION_NONE );
    427415    if( !isEncrypted )
    428416    {
     
    454442        uint8_t buf[SHA_DIGEST_LENGTH];
    455443        tr_sha1( req2, "req2", 4,
    456                  tr_cryptoGetTorrentHash(
    457                      handshake->crypto ), SHA_DIGEST_LENGTH, NULL );
     444                 tr_cryptoGetTorrentHash( handshake->crypto ),
     445                 SHA_DIGEST_LENGTH, NULL );
    458446        tr_sha1( req3, "req3", 4, secret, KEY_LEN, NULL );
    459447        for( i = 0; i < SHA_DIGEST_LENGTH; ++i )
     
    576564    uint8_t *    tmp;
    577565
    578     dbgmsg( handshake, "pad d: need %d, got %d", (int)needlen,
    579            (int)EVBUFFER_LENGTH(
    580                inbuf ) );
     566    dbgmsg( handshake, "pad d: need %zu, got %zu",
     567            needlen, EVBUFFER_LENGTH( inbuf ) );
    581568    if( EVBUFFER_LENGTH( inbuf ) < needlen )
    582569        return READ_LATER;
     
    608595    uint8_t   hash[SHA_DIGEST_LENGTH];
    609596
    610     dbgmsg( handshake, "payload: need %d, got %d",
    611            (int)INCOMING_HANDSHAKE_LEN, (int)EVBUFFER_LENGTH(
    612                inbuf ) );
     597    dbgmsg( handshake, "payload: need %d, got %zu",
     598            (int)INCOMING_HANDSHAKE_LEN, EVBUFFER_LENGTH( inbuf ) );
    613599
    614600    if( EVBUFFER_LENGTH( inbuf ) < INCOMING_HANDSHAKE_LEN )
     
    667653
    668654    /**
    669     *** Extension negotiation
     655    *** Extensions
    670656    **/
    671657
    672     if( HANDSHAKE_HAS_LTEP( reserved ) )
    673     {
    674         tr_peerIoEnableLTEP( handshake->io, 1 );
    675         dbgmsg( handshake, "using ltep" );
    676     }
    677     if( HANDSHAKE_HAS_FASTEXT( reserved ) )
    678     {
    679         tr_peerIoEnableFEXT( handshake->io, 1 );
    680         dbgmsg( handshake, "using fext" );
    681     }
     658    tr_peerIoEnableLTEP( handshake->io, HANDSHAKE_HAS_LTEP( reserved ) );
     659
     660    tr_peerIoEnableFEXT( handshake->io, HANDSHAKE_HAS_FASTEXT( reserved ) );
    682661
    683662    /* torrent hash */
     
    685664    if( tr_peerIoIsIncoming( handshake->io ) )
    686665    {
    687         if( !tr_torrentExists( handshake->handle, hash ) )
     666        if( !tr_torrentExists( handshake->session, hash ) )
    688667        {
    689668            dbgmsg( handshake, "peer is trying to connect to us for a torrent we don't have." );
     
    737716
    738717    /* peer id */
    739     tr_peerIoReadBytes( handshake->io, inbuf, handshake->peer_id,
    740                         PEER_ID_LEN );
     718    tr_peerIoReadBytes( handshake->io, inbuf, handshake->peer_id, PEER_ID_LEN );
    741719    tr_peerIoSetPeersId( handshake->io, handshake->peer_id );
    742720    handshake->havePeerID = TRUE;
    743721    tr_clientForId( client, sizeof( client ), handshake->peer_id );
    744722    dbgmsg( handshake, "peer-id is [%s] ... isIncoming is %d", client,
    745            tr_peerIoIsIncoming(
    746                handshake->io ) );
     723            tr_peerIoIsIncoming( handshake->io ) );
    747724
    748725    /* if we've somehow connected to ourselves, don't keep the connection */
    749     tor = tr_torrentFindFromHash( handshake->handle, tr_peerIoGetTorrentHash( handshake->io ) );
     726    tor = tr_torrentFindFromHash( handshake->session, tr_peerIoGetTorrentHash( handshake->io ) );
    750727    peer_id = tor && tor->peer_id ? tor->peer_id : tr_getPeerId( );
    751728    peerIsGood = memcmp( handshake->peer_id, peer_id, PEER_ID_LEN ) != 0;
     
    763740    int            len;
    764741
    765     dbgmsg( handshake, "in readYa... need %d, have %d", (int)KEY_LEN,
    766            (int)EVBUFFER_LENGTH(
    767                inbuf ) );
     742    dbgmsg( handshake, "in readYa... need %d, have %zu",
     743            (int)KEY_LEN, EVBUFFER_LENGTH( inbuf ) );
    768744    if( EVBUFFER_LENGTH( inbuf ) < KEY_LEN )
    769745        return READ_LATER;
     
    796772    uint8_t * pch;
    797773
    798     dbgmsg(
    799          handshake,
    800         "looking to get past pad a... & resync on hash('req',S) ... have %d bytes",
    801         (int)EVBUFFER_LENGTH( inbuf ) );
     774    dbgmsg( handshake, "looking to get past pad a... & resync on hash('req',S) ... have %zu bytes",
     775            EVBUFFER_LENGTH( inbuf ) );
    802776    /**
    803777    *** Resynchronizing on HASH('req1',S)
     
    809783    if( pch == NULL )
    810784    {
    811         dbgmsg( handshake, "no luck so far.. draining %d bytes",
    812                (int)EVBUFFER_LENGTH(
    813                    inbuf ) );
     785        dbgmsg( handshake, "no luck so far.. draining %zu bytes",
     786                EVBUFFER_LENGTH( inbuf ) );
    814787        evbuffer_drain( inbuf, EVBUFFER_LENGTH( inbuf ) );
    815788        return READ_LATER;
     
    871844        obfuscatedTorrentHash[i] = req2[i] ^ req3[i];
    872845    if( ( tor =
    873              tr_torrentFindFromObfuscatedHash( handshake->handle,
     846             tr_torrentFindFromObfuscatedHash( handshake->session,
    874847                                               obfuscatedTorrentHash ) ) )
    875848    {
    876         dbgmsg(
    877             handshake,
    878             "got INCOMING connection's encrypted handshake for torrent [%s]",
    879             tor->info.name );
     849        dbgmsg( handshake, "got INCOMING connection's encrypted handshake for torrent [%s]",
     850                tor->info.name );
    880851        tr_peerIoSetTorrentHash( handshake->io, tor->info.hash );
    881852        if( !tr_torrentAllowsPex( tor )
    882           && tr_peerMgrPeerIsSeed( handshake->handle->peerMgr,
     853          && tr_peerMgrPeerIsSeed( handshake->session->peerMgr,
    883854                                  tor->info.hash,
    884855                                  tr_peerIoGetAddress( handshake->io, NULL ) ) )
     
    938909    uint32_t          crypto_select;
    939910
    940     dbgmsg( handshake, "reading IA... have %d, need %d",
    941             (int)EVBUFFER_LENGTH(
    942                 inbuf ), (int)needlen );
     911    dbgmsg( handshake, "reading IA... have %zu, need %zu",
     912            EVBUFFER_LENGTH( inbuf ), needlen );
    943913    if( EVBUFFER_LENGTH( inbuf ) < needlen )
    944914        return READ_LATER;
    945915
    946916    /**
    947     ***  B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload
    948     ***Stream)
     917    ***  B->A: ENCRYPT(VC, crypto_select, len(padD), padD), ENCRYPT2(Payload Stream)
    949918    **/
    950919
     
    975944
    976945    dbgmsg( handshake, "sending pad d" );
    977     /* ENCRYPT(VC, crypto_provide, len(PadC), PadC
     946    /* ENCRYPT(VC, crypto_provide, len(PadD), PadD
    978947     * PadD is reserved for future extensions to the handshake...
    979948     * standard practice at this time is for it to be zero-length */
     
    1013982    const size_t      needlen = HANDSHAKE_SIZE;
    1014983
    1015     dbgmsg( handshake, "reading payload stream... have %d, need %d",
    1016             (int)EVBUFFER_LENGTH( inbuf ), (int)needlen );
     984    dbgmsg( handshake, "reading payload stream... have %zu, need %zu",
     985            EVBUFFER_LENGTH( inbuf ), needlen );
    1017986    if( EVBUFFER_LENGTH( inbuf ) < needlen )
    1018987        return READ_LATER;
     
    10351004
    10361005static ReadState
    1037 canRead( struct tr_iobuf * iobuf, void * arg, size_t * piece )
    1038 {
    1039     tr_handshake *    handshake = arg;
    1040     struct evbuffer * inbuf = tr_iobuf_input( iobuf );
     1006canRead( struct tr_peerIo * io, void * arg, size_t * piece )
     1007{
     1008    tr_handshake    * handshake = arg;
     1009    struct evbuffer * inbuf = tr_peerIoGetReadBuffer( io );
    10411010    ReadState         ret;
    1042     int               readyForMore = TRUE;
     1011    tr_bool           readyForMore = TRUE;
    10431012
    10441013    /* no piece data in handshake */
     
    11221091}
    11231092
     1093void
     1094tr_handshakeFree( tr_handshake * handshake )
     1095{
     1096    if( handshake->io )
     1097        tr_peerIoFree( handshake->io );
     1098
     1099    tr_free( handshake );
     1100}
     1101
    11241102static int
    11251103tr_handshakeDone( tr_handshake * handshake,
    11261104                  int            isOK )
    11271105{
    1128     int success;
     1106    tr_bool success;
    11291107
    11301108    dbgmsg( handshake, "handshakeDone: %s", isOK ? "connected" : "aborting" );
     
    11331111    success = fireDoneFunc( handshake, isOK );
    11341112
    1135     tr_free( handshake );
    1136 
    11371113    return success ? READ_LATER : READ_ERR;
    11381114}
     
    11451121
    11461122static void
    1147 gotError( struct tr_iobuf  * iobuf UNUSED,
    1148           short              what,
    1149           void             * arg )
     1123gotError( tr_peerIo  * io UNUSED,
     1124          short        what,
     1125          void       * arg )
    11501126{
    11511127    tr_handshake * handshake = (tr_handshake *) arg;
     
    11941170    handshake->doneCB = doneCB;
    11951171    handshake->doneUserData = doneUserData;
    1196     handshake->handle = tr_peerIoGetSession( io );
    1197     tr_peerIoSetTimeoutSecs( io, 15 );
     1172    handshake->session = tr_peerIoGetSession( io );
    11981173
    11991174    tr_peerIoSetIOFuncs( handshake->io, canRead, NULL, gotError, handshake );
     
    12251200}
    12261201
    1227 const struct in_addr *
    1228 tr_handshakeGetAddr( const struct tr_handshake * handshake,
    1229                                                  uint16_t * port )
    1230 {
     1202struct tr_peerIo*
     1203tr_handshakeStealIO( tr_handshake * handshake )
     1204{
     1205    struct tr_peerIo * io;
     1206
    12311207    assert( handshake );
    12321208    assert( handshake->io );
    12331209
     1210    io = handshake->io;
     1211    handshake->io = NULL;
     1212    return io;
     1213}
     1214
     1215const tr_address *
     1216tr_handshakeGetAddr( const struct tr_handshake * handshake,
     1217                     tr_port                   * port )
     1218{
     1219    assert( handshake );
     1220    assert( handshake->io );
     1221
    12341222    return tr_peerIoGetAddress( handshake->io, port );
    12351223}
  • branches/1.4x/libtransmission/handshake.h

    r7175 r7455  
    11/*
    2  * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@transmissionbt.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    1919
    2020#include "transmission.h"
     21#include "net.h"
    2122
    22 struct in_addr;
    2323struct tr_peerIo;
    2424typedef struct tr_handshake tr_handshake;
    2525
    2626/* returns true on success, false on error */
    27 typedef int ( *handshakeDoneCB )( struct tr_handshake * handshake,
    28                                   struct tr_peerIo *    io,
    29                                   int                   isConnected,
    30                                   const uint8_t *       peerId,
    31                                   void *                userData );
     27typedef tr_bool ( *handshakeDoneCB )( struct tr_handshake * handshake,
     28                                      struct tr_peerIo *    io,
     29                                      int                   isConnected,
     30                                      const uint8_t *       peerId,
     31                                      void *                userData );
    3232
    3333tr_handshake *         tr_handshakeNew( struct tr_peerIo * io,
     
    3636                                        void *             doneUserData );
    3737
    38 const struct in_addr * tr_handshakeGetAddr(
    39     const struct tr_handshake * handshake,
    40                                 uint16_t
    41     *                           setme_port );
     38const tr_address *     tr_handshakeGetAddr( const struct tr_handshake  * handshake,
     39                                            tr_port                    * port );
     40
     41void                   tr_handshakeFree( tr_handshake * handshake );
    4242
    4343void                   tr_handshakeAbort( tr_handshake * handshake );
     
    4545struct tr_peerIo*      tr_handshakeGetIO( tr_handshake * handshake );
    4646
     47struct tr_peerIo*      tr_handshakeStealIO( tr_handshake * handshake );
     48
     49
    4750#endif
  • branches/1.4x/libtransmission/net.c

    r7176 r7455  
    6464}
    6565
     66tr_bool
     67tr_isAddress( const tr_address * a )
     68{
     69    return a != NULL; /* this is implemented better in 1.50 */
     70}
     71
     72
    6673/***********************************************************************
    6774 * DNS resolution
     
    243250}
    244251
     252int
     253tr_compareAddresses( const struct in_addr * a, const struct in_addr * b )
     254{
     255    if( a->s_addr != b->s_addr )
     256        return a->s_addr < b->s_addr ? -1 : 1;
     257
     258    return 0;
     259}
  • branches/1.4x/libtransmission/net.h

    r7176 r7455  
    6565struct tr_session;
    6666
     67typedef struct in_addr tr_address;
     68
     69tr_bool tr_isAddress( const tr_address * a );
     70
    6771/***********************************************************************
    6872 * DNS resolution
     
    9599                 int                    len );
    96100
     101int tr_compareAddresses( const struct in_addr * a,
     102                         const struct in_addr * b );
     103
    97104void tr_netInit( void );
    98105
  • branches/1.4x/libtransmission/peer-common.h

    r7176 r7455  
    2323
    2424#include "transmission.h"
    25 #include "publish.h"
    2625
    2726typedef enum
     
    4342    TR_PEER_CLIENT_GOT_BLOCK,
    4443    TR_PEER_CLIENT_GOT_DATA,
     44    TR_PEER_CLIENT_GOT_ALLOWED_FAST,
     45    TR_PEER_CLIENT_GOT_SUGGEST,
    4546    TR_PEER_PEER_GOT_DATA,
    4647    TR_PEER_PEER_PROGRESS,
    4748    TR_PEER_ERROR,
    4849    TR_PEER_CANCEL,
     50    TR_PEER_UPLOAD_ONLY,
    4951    TR_PEER_NEED_REQ
    5052}
     
    5456{
    5557    PeerEventType    eventType;
    56     uint32_t         pieceIndex;   /* for GOT_BLOCK, CANCEL */
     58    uint32_t         pieceIndex;   /* for GOT_BLOCK, CANCEL, ALLOWED, SUGGEST */
    5759    uint32_t         offset;       /* for GOT_BLOCK */
    5860    uint32_t         length;       /* for GOT_BLOCK + GOT_DATA */
    5961    float            progress;     /* for PEER_PROGRESS */
    6062    int              err;          /* errno for GOT_ERROR */
    61     int              wasPieceData; /* for GOT_DATA */
     63    tr_bool          wasPieceData; /* for GOT_DATA */
     64    tr_bool          uploadOnly;   /* for UPLOAD_ONLY */
    6265}
    6366tr_peer_event;
  • branches/1.4x/libtransmission/peer-io.c

    r7403 r7455  
    11/*
    2  * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@transmissionbt.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    2020 #include <winsock2.h>
    2121#else
    22  #include <netinet/in.h> /* struct in_addr */
    2322 #include <arpa/inet.h> /* inet_ntoa */
    2423#endif
     
    2928#include "bandwidth.h"
    3029#include "crypto.h"
    31 #include "iobuf.h"
    3230#include "list.h"
    3331#include "net.h"
     
    3735
    3836#define MAGIC_NUMBER 206745
    39 #define IO_TIMEOUT_SECS 8
    4037
    4138static size_t
     
    8178struct tr_peerIo
    8279{
    83     tr_bool                  isEncrypted;
    84     tr_bool                  isIncoming;
    85     tr_bool                  peerIdIsSet;
    86     tr_bool                  extendedProtocolSupported;
    87     tr_bool                  fastPeersSupported;
    88 
    89     int                      magicNumber;
    90 
    91     uint8_t                  encryptionMode;
    92     uint8_t                  timeout;
    93     uint16_t                 port;
    94     int                      socket;
    95 
    96     uint8_t                  peerId[20];
    97     time_t                   timeCreated;
    98 
    99     tr_session             * session;
    100 
    101     struct in_addr           in_addr;
    102     struct tr_iobuf        * iobuf;
    103     tr_list                * output_datatypes; /* struct tr_datatype */
    104 
    105     tr_can_read_cb           canRead;
    106     tr_did_write_cb          didWrite;
    107     tr_net_error_cb          gotError;
    108     void *                   userData;
    109 
    110     size_t                   bufferSize[2];
    111 
    112     tr_bandwidth           * bandwidth;
    113     tr_crypto              * crypto;
     80    tr_bool            isEncrypted;
     81    tr_bool            isIncoming;
     82    tr_bool            peerIdIsSet;
     83    tr_bool            extendedProtocolSupported;
     84    tr_bool            fastExtensionSupported;
     85
     86    int                magicNumber;
     87
     88    uint8_t            encryptionMode;
     89    tr_port            port;
     90    int                socket;
     91
     92    uint8_t            peerId[20];
     93    time_t             timeCreated;
     94
     95    tr_session       * session;
     96
     97    tr_address         addr;
     98    tr_list          * output_datatypes; /* struct tr_datatype */
     99
     100    tr_can_read_cb     canRead;
     101    tr_did_write_cb    didWrite;
     102    tr_net_error_cb    gotError;
     103    void *             userData;
     104
     105    size_t             bufferSize[2];
     106
     107    tr_bandwidth     * bandwidth;
     108    tr_crypto        * crypto;
     109
     110    struct evbuffer  * inbuf;
     111    struct evbuffer  * outbuf;
     112
     113    struct event       event_read;
     114    struct event       event_write;
    114115};
    115116
     
    119120
    120121static void
    121 didWriteWrapper( struct tr_iobuf  * iobuf,
    122                  size_t             bytes_transferred,
    123                  void             * vio )
    124 {
    125     tr_peerIo *  io = vio;
    126 
     122didWriteWrapper( tr_peerIo * io, size_t bytes_transferred )
     123{
    127124    while( bytes_transferred )
    128125    {
     
    144141            tr_free( tr_list_pop_front( &io->output_datatypes ) );
    145142    }
    146 
    147     if( EVBUFFER_LENGTH( tr_iobuf_output( iobuf ) ) )
    148         tr_iobuf_enable( io->iobuf, EV_WRITE );
    149143}
    150144
    151145static void
    152 canReadWrapper( struct tr_iobuf  * iobuf,
    153                 size_t             bytes_transferred UNUSED,
    154                 void              * vio )
    155 {
    156     int          done = 0;
    157     int          err = 0;
    158     tr_peerIo *  io = vio;
     146canReadWrapper( tr_peerIo * io )
     147{
     148    tr_bool done = 0;
     149    tr_bool err = 0;
    159150    tr_session * session = io->session;
    160151
     
    169160        {
    170161            size_t piece = 0;
    171             const size_t oldLen = EVBUFFER_LENGTH( tr_iobuf_input( iobuf ) );
    172             const int ret = io->canRead( iobuf, io->userData, &piece );
    173 
    174             if( ret != READ_ERR )
    175             {
    176                 const size_t used = oldLen - EVBUFFER_LENGTH( tr_iobuf_input( iobuf ) );
    177                 if( piece )
    178                     tr_bandwidthUsed( io->bandwidth, TR_DOWN, piece, TRUE );
    179                 if( used != piece )
    180                     tr_bandwidthUsed( io->bandwidth, TR_DOWN, used - piece, FALSE );
    181             }
     162            const size_t oldLen = EVBUFFER_LENGTH( io->inbuf );
     163            const int ret = io->canRead( io, io->userData, &piece );
     164
     165            const size_t used = oldLen - EVBUFFER_LENGTH( io->inbuf );
     166
     167            if( piece )
     168                tr_bandwidthUsed( io->bandwidth, TR_DOWN, piece, TRUE );
     169
     170            if( used != piece )
     171                tr_bandwidthUsed( io->bandwidth, TR_DOWN, used - piece, FALSE );
    182172
    183173            switch( ret )
    184174            {
    185175                case READ_NOW:
    186                     if( EVBUFFER_LENGTH( tr_iobuf_input( iobuf )))
     176                    if( EVBUFFER_LENGTH( io->inbuf ) )
    187177                        continue;
    188178                    done = 1;
     
    203193}
    204194
     195#define _isBool(b) (((b)==0 || (b)==1))
     196
     197tr_bool
     198tr_isPeerIo( const tr_peerIo * io )
     199{
     200    return ( io != NULL )
     201        && ( io->magicNumber == MAGIC_NUMBER )
     202        && ( _isBool( io->isEncrypted ) )
     203        && ( _isBool( io->isIncoming ) )
     204        && ( _isBool( io->peerIdIsSet ) )
     205        && ( _isBool( io->extendedProtocolSupported ) )
     206        && ( _isBool( io->fastExtensionSupported ) );
     207}
     208
    205209static void
    206 gotErrorWrapper( struct tr_iobuf  * iobuf,
    207                  short              what,
    208                  void             * userData )
    209 {
    210     tr_peerIo * c = userData;
    211 
    212     if( c->gotError )
    213         c->gotError( iobuf, what, c->userData );
     210event_read_cb( int fd, short event UNUSED, void * vio )
     211{
     212    int res;
     213    short what = EVBUFFER_READ;
     214    tr_peerIo * io = vio;
     215    const size_t howmuch = tr_bandwidthClamp( io->bandwidth, TR_DOWN, io->session->so_rcvbuf );
     216    const tr_direction dir = TR_DOWN;
     217
     218    assert( tr_isPeerIo( io ) );
     219
     220    dbgmsg( io, "libevent says this peer is ready to read" );
     221
     222    /* if we don't have any bandwidth left, stop reading */
     223    if( howmuch < 1 ) {
     224        tr_peerIoSetEnabled( io, dir, FALSE );
     225        return;
     226    }
     227
     228    res = evbuffer_read( io->inbuf, fd, howmuch );
     229    if( res == -1 ) {
     230        if( errno == EAGAIN || errno == EINTR )
     231            goto reschedule;
     232        /* error case */
     233        what |= EVBUFFER_ERROR;
     234    } else if( res == 0 ) {
     235        /* eof case */
     236        what |= EVBUFFER_EOF;
     237    }
     238
     239    if( res <= 0 )
     240        goto error;
     241
     242    tr_peerIoSetEnabled( io, dir, TRUE );
     243
     244    /* Invoke the user callback - must always be called last */
     245    canReadWrapper( io );
     246
     247    return;
     248
     249 reschedule:
     250    tr_peerIoSetEnabled( io, dir, TRUE );
     251    return;
     252
     253 error:
     254    if( io->gotError != NULL )
     255        io->gotError( io, what, io->userData );
     256}
     257
     258static int
     259tr_evbuffer_write( tr_peerIo * io, int fd, size_t howmuch )
     260{
     261    struct evbuffer * buffer = io->outbuf;
     262    int n = MIN( EVBUFFER_LENGTH( buffer ), howmuch );
     263
     264#ifdef WIN32
     265    n = send(fd, buffer->buffer, n,  0 );
     266#else
     267    n = write(fd, buffer->buffer, n );
     268#endif
     269    dbgmsg( io, "wrote %d to peer (%s)", n, (n==-1?strerror(errno):"") );
     270
     271    if( n == -1 )
     272        return -1;
     273    if (n == 0)
     274        return 0;
     275    evbuffer_drain( buffer, n );
     276
     277    return n;
     278}
     279
     280static void
     281event_write_cb( int fd, short event UNUSED, void * vio )
     282{
     283    int res = 0;
     284    short what = EVBUFFER_WRITE;
     285    tr_peerIo * io = vio;
     286    size_t howmuch;
     287    const tr_direction dir = TR_UP;
     288
     289    assert( tr_isPeerIo( io ) );
     290
     291    dbgmsg( io, "libevent says this peer is ready to write" );
     292
     293    howmuch = MIN( (size_t)io->session->so_sndbuf, EVBUFFER_LENGTH( io->outbuf ) );
     294    howmuch = tr_bandwidthClamp( io->bandwidth, dir, howmuch );
     295
     296    /* if we don't have any bandwidth left, stop writing */
     297    if( howmuch < 1 ) {
     298        tr_peerIoSetEnabled( io, dir, FALSE );
     299        return;
     300    }
     301
     302    res = tr_evbuffer_write( io, fd, howmuch );
     303    if (res == -1) {
     304#ifndef WIN32
     305/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not
     306 *  *set errno. thus this error checking is not portable*/
     307        if (errno == EAGAIN || errno == EINTR || errno == EINPROGRESS)
     308            goto reschedule;
     309        /* error case */
     310        what |= EVBUFFER_ERROR;
     311
     312#else
     313        goto reschedule;
     314#endif
     315
     316    } else if (res == 0) {
     317        /* eof case */
     318        what |= EVBUFFER_EOF;
     319    }
     320    if (res <= 0)
     321        goto error;
     322
     323    if( EVBUFFER_LENGTH( io->outbuf ) )
     324        tr_peerIoSetEnabled( io, dir, TRUE );
     325
     326    didWriteWrapper( io, res );
     327    return;
     328
     329 reschedule:
     330    if( EVBUFFER_LENGTH( io->outbuf ) )
     331        tr_peerIoSetEnabled( io, dir, TRUE );
     332    return;
     333
     334 error:
     335    if( io->gotError != NULL )
     336        io->gotError( io, what, io->userData );
    214337}
    215338
     
    218341**/
    219342
    220 static void
    221 bufevNew( tr_peerIo * io )
    222 {
    223     io->iobuf = tr_iobuf_new( io->session,
    224                               io->bandwidth,
    225                               io->socket,
    226                               EV_READ | EV_WRITE,
    227                               canReadWrapper,
    228                               didWriteWrapper,
    229                               gotErrorWrapper,
    230                               io );
    231 
    232     tr_iobuf_settimeout( io->iobuf, io->timeout, io->timeout );
    233 }
    234343
    235344static int
    236 isPeerIo( const tr_peerIo * io )
    237 {
    238     return ( io != NULL ) && ( io->magicNumber == MAGIC_NUMBER );
     345isFlag( int flag )
     346{
     347    return( ( flag == 0 ) || ( flag == 1 ) );
    239348}
    240349
    241350static tr_peerIo*
    242 tr_peerIoNew( tr_session *          session,
    243               const struct in_addr * in_addr,
    244               uint16_t               port,
    245               const uint8_t *        torrentHash,
    246               int                    isIncoming,
    247               int                    socket )
     351tr_peerIoNew( tr_session       * session,
     352              const tr_address * addr,
     353              tr_port            port,
     354              const uint8_t    * torrentHash,
     355              int                isIncoming,
     356              int                socket )
    248357{
    249358    tr_peerIo * io;
     
    256365    io->crypto = tr_cryptoNew( torrentHash, isIncoming );
    257366    io->session = session;
    258     io->in_addr = *in_addr;
     367    io->addr = *addr;
    259368    io->port = port;
    260369    io->socket = socket;
    261370    io->isIncoming = isIncoming != 0;
    262     io->timeout = IO_TIMEOUT_SECS;
    263371    io->timeCreated = time( NULL );
     372    io->inbuf = evbuffer_new( );
     373    io->outbuf = evbuffer_new( );
     374    event_set( &io->event_read, io->socket, EV_READ, event_read_cb, io );
     375    event_set( &io->event_write, io->socket, EV_WRITE, event_write_cb, io );
     376#if 0
    264377    bufevNew( io );
     378#endif
    265379    tr_peerIoSetBandwidth( io, session->bandwidth );
    266380    return io;
     
    268382
    269383tr_peerIo*
    270 tr_peerIoNewIncoming( tr_session *          session,
    271                       const struct in_addr * in_addr,
    272                       uint16_t               port,
    273                       int                    socket )
     384tr_peerIoNewIncoming( tr_session       * session,
     385                      const tr_address * addr,
     386                      tr_port            port,
     387                      int                socket )
    274388{
    275389    assert( session );
    276     assert( in_addr );
     390    assert( addr );
    277391    assert( socket >= 0 );
    278392
    279     return tr_peerIoNew( session, in_addr, port,
    280                          NULL, 1,
    281                          socket );
     393    return tr_peerIoNew( session, addr, port, NULL, 1, socket );
    282394}
    283395
    284396tr_peerIo*
    285 tr_peerIoNewOutgoing( tr_session *          session,
    286                       const struct in_addr * in_addr,
    287                       int                    port,
    288                       const uint8_t *        torrentHash )
     397tr_peerIoNewOutgoing( tr_session       * session,
     398                      const tr_address * addr,
     399                      tr_port            port,
     400                      const uint8_t    * torrentHash )
    289401{
    290402    int socket;
    291403
    292404    assert( session );
    293     assert( in_addr );
    294     assert( port >= 0 );
     405    assert( addr );
    295406    assert( torrentHash );
    296407
    297     socket = tr_netOpenTCP( session, in_addr, port );
     408    socket = tr_netOpenTCP( session, addr, port );
    298409
    299410    return socket < 0
    300411           ? NULL
    301            : tr_peerIoNew( session, in_addr, port, torrentHash, 0, socket );
     412           : tr_peerIoNew( session, addr, port, torrentHash, 0, socket );
    302413}
    303414
     
    307418    tr_peerIo * io = vio;
    308419
     420    event_del( &io->event_read );
     421    event_del( &io->event_write );
    309422    tr_peerIoSetBandwidth( io, NULL );
    310     tr_iobuf_free( io->iobuf );
     423    evbuffer_free( io->outbuf );
     424    evbuffer_free( io->inbuf );
    311425    tr_netClose( io->socket );
    312426    tr_cryptoFree( io->crypto );
     
    332446tr_peerIoGetSession( tr_peerIo * io )
    333447{
    334     assert( isPeerIo( io ) );
     448    assert( tr_isPeerIo( io ) );
    335449    assert( io->session );
    336450
     
    338452}
    339453
    340 const struct in_addr*
     454const tr_address*
    341455tr_peerIoGetAddress( const tr_peerIo * io,
    342                            uint16_t * port )
    343 {
    344     assert( isPeerIo( io ) );
     456                           tr_port  * port )
     457{
     458    assert( tr_isPeerIo( io ) );
    345459
    346460    if( port )
    347461        *port = io->port;
    348462
    349     return &io->in_addr;
     463    return &io->addr;
    350464}
    351465
    352466const char*
    353 tr_peerIoAddrStr( const struct in_addr * addr,
    354                   uint16_t               port )
     467tr_peerIoAddrStr( const tr_address * addr, tr_port port )
    355468{
    356469    static char buf[512];
    357 
    358     tr_snprintf( buf, sizeof( buf ), "%s:%u", inet_ntoa( *addr ),
    359                 ntohs( port ) );
     470    tr_snprintf( buf, sizeof( buf ), "%s:%u", inet_ntoa( *addr ), ntohs( port ) );
    360471    return buf;
    361472}
     
    364475tr_peerIoGetAddrStr( const tr_peerIo * io )
    365476{
    366     return tr_peerIoAddrStr( &io->in_addr, io->port );
    367 }
    368 
    369 static void
    370 tr_peerIoTryRead( tr_peerIo * io )
    371 {
    372     if( EVBUFFER_LENGTH( tr_iobuf_input( io->iobuf )))
    373         (*canReadWrapper)( io->iobuf, ~0, io );
    374 }
    375 
    376 void
    377 tr_peerIoSetIOFuncs( tr_peerIo *     io,
    378                      tr_can_read_cb  readcb,
    379                      tr_did_write_cb writecb,
    380                      tr_net_error_cb errcb,
    381                      void *          userData )
     477    return tr_peerIoAddrStr( &io->addr, io->port );
     478}
     479
     480void
     481tr_peerIoSetIOFuncs( tr_peerIo        * io,
     482                     tr_can_read_cb     readcb,
     483                     tr_did_write_cb    writecb,
     484                     tr_net_error_cb    errcb,
     485                     void             * userData )
    382486{
    383487    io->canRead = readcb;
     
    385489    io->gotError = errcb;
    386490    io->userData = userData;
    387 
    388     tr_peerIoTryRead( io );
    389 }
    390 
    391 int
     491}
     492
     493tr_bool
    392494tr_peerIoIsIncoming( const tr_peerIo * c )
    393495{
    394     return c->isIncoming ? 1 : 0;
     496    return c->isIncoming != 0;
    395497}
    396498
     
    403505        tr_netClose( io->socket );
    404506
    405     io->socket = tr_netOpenTCP( io->session, &io->in_addr, io->port );
     507    io->socket = tr_netOpenTCP( io->session, &io->addr, io->port );
    406508
    407509    if( io->socket >= 0 )
     
    411513
    412514        tr_netSetTOS( io->socket, io->session->peerSocketTOS );
    413         tr_iobuf_free( io->iobuf );
     515#if 0
    414516        bufevNew( io );
     517#endif
    415518
    416519        tr_peerIoSetBandwidth( io, bandwidth );
     
    419522
    420523    return -1;
    421 }
    422 
    423 void
    424 tr_peerIoSetTimeoutSecs( tr_peerIo * io,
    425                          int         secs )
    426 {
    427     io->timeout = secs;
    428     tr_iobuf_settimeout( io->iobuf, io->timeout, io->timeout );
    429     tr_iobuf_enable( io->iobuf, EV_READ | EV_WRITE );
    430524}
    431525
     
    438532                         const uint8_t * hash )
    439533{
    440     assert( isPeerIo( io ) );
     534    assert( tr_isPeerIo( io ) );
    441535
    442536    tr_cryptoSetTorrentHash( io->crypto, hash );
     
    446540tr_peerIoGetTorrentHash( tr_peerIo * io )
    447541{
    448     assert( isPeerIo( io ) );
     542    assert( tr_isPeerIo( io ) );
    449543    assert( io->crypto );
    450544
     
    455549tr_peerIoHasTorrentHash( const tr_peerIo * io )
    456550{
    457     assert( isPeerIo( io ) );
     551    assert( tr_isPeerIo( io ) );
    458552    assert( io->crypto );
    459553
     
    469563                     const uint8_t * peer_id )
    470564{
    471     assert( isPeerIo( io ) );
     565    assert( tr_isPeerIo( io ) );
    472566
    473567    if( ( io->peerIdIsSet = peer_id != NULL ) )
     
    480574tr_peerIoGetPeersId( const tr_peerIo * io )
    481575{
    482     assert( isPeerIo( io ) );
     576    assert( tr_isPeerIo( io ) );
    483577    assert( io->peerIdIsSet );
    484578
     
    491585
    492586void
    493 tr_peerIoEnableLTEP( tr_peerIo * io,
    494                      int         flag )
    495 {
    496     assert( isPeerIo( io ) );
    497     assert( flag == 0 || flag == 1 );
    498 
     587tr_peerIoEnableFEXT( tr_peerIo * io,
     588                     tr_bool     flag )
     589{
     590    assert( tr_isPeerIo( io ) );
     591    assert( isFlag( flag ) );
     592
     593    dbgmsg( io, "setting FEXT support flag to %d", (flag?1:0) );
     594    io->fastExtensionSupported = flag;
     595}
     596
     597tr_bool
     598tr_peerIoSupportsFEXT( const tr_peerIo * io )
     599{
     600    assert( tr_isPeerIo( io ) );
     601
     602    return io->fastExtensionSupported;
     603}
     604
     605/**
     606***
     607**/
     608
     609void
     610tr_peerIoEnableLTEP( tr_peerIo  * io,
     611                     tr_bool      flag )
     612{
     613    assert( tr_isPeerIo( io ) );
     614    assert( isFlag( flag ) );
     615
     616    dbgmsg( io, "setting LTEP support flag to %d", (flag?1:0) );
    499617    io->extendedProtocolSupported = flag;
    500618}
    501619
    502 void
    503 tr_peerIoEnableFEXT( tr_peerIo * io,
    504                      int         flag )
    505 {
    506     assert( isPeerIo( io ) );
    507     assert( flag == 0 || flag == 1 );
    508 
    509     io->fastPeersSupported = flag;
    510 }
    511 
    512 int
     620tr_bool
    513621tr_peerIoSupportsLTEP( const tr_peerIo * io )
    514622{
    515     assert( isPeerIo( io ) );
     623    assert( tr_isPeerIo( io ) );
    516624
    517625    return io->extendedProtocolSupported;
    518 }
    519 
    520 int
    521 tr_peerIoSupportsFEXT( const tr_peerIo * io )
    522 {
    523     assert( isPeerIo( io ) );
    524 
    525     return io->fastPeersSupported;
    526626}
    527627
     
    540640    const double currentSpeed = tr_bandwidthGetPieceSpeed( io->bandwidth, TR_UP );
    541641    const double period = 20; /* arbitrary */
    542     return MAX( maxBlockSize*5.5, currentSpeed*1024*period );
     642    const double numBlocks = 5.5; /* the 5 is arbitrary; the .5 is to leave room for messages */
     643    return MAX( maxBlockSize*numBlocks, currentSpeed*1024*period );
    543644}
    544645
     
    547648{
    548649    const size_t desiredLen = getDesiredOutputBufferSize( io );
    549     const size_t currentLen = EVBUFFER_LENGTH( tr_iobuf_output( io->iobuf ) );
     650    const size_t currentLen = EVBUFFER_LENGTH( io->outbuf );
    550651    size_t freeSpace = 0;
    551652
     
    560661                       tr_bandwidth  * bandwidth )
    561662{
    562     assert( isPeerIo( io ) );
     663    assert( tr_isPeerIo( io ) );
    563664
    564665    if( io->bandwidth )
    565         tr_bandwidthRemoveBuffer( io->bandwidth, io->iobuf );
     666        tr_bandwidthRemovePeer( io->bandwidth, io );
    566667
    567668    io->bandwidth = bandwidth;
    568     tr_iobuf_set_bandwidth( io->iobuf, bandwidth );
    569669
    570670    if( io->bandwidth )
    571         tr_bandwidthAddBuffer( io->bandwidth, io->iobuf );
    572 
    573     tr_iobuf_enable( io->iobuf, EV_READ | EV_WRITE );
     671        tr_bandwidthAddPeer( io->bandwidth, io );
    574672}
    575673
     
    588686                        int         encryptionMode )
    589687{
    590     assert( isPeerIo( io ) );
     688    assert( tr_isPeerIo( io ) );
    591689    assert( encryptionMode == PEER_ENCRYPTION_NONE
    592690          || encryptionMode == PEER_ENCRYPTION_RC4 );
     
    620718    tr_list_append( &io->output_datatypes, datatype );
    621719
    622     evbuffer_add( tr_iobuf_output( io->iobuf ), writeme, writemeLen );
    623     tr_iobuf_enable( io->iobuf, EV_WRITE );
     720    evbuffer_add( io->outbuf, writeme, writemeLen );
    624721}
    625722
     
    736833    uint16_t tmp;
    737834
     835    assert( tr_isPeerIo( io ) );
     836
    738837    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof( uint16_t ) );
    739838    *setme = ntohs( tmp );
     
    747846    uint32_t tmp;
    748847
     848    assert( tr_isPeerIo( io ) );
     849
    749850    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof( uint32_t ) );
    750851    *setme = ntohl( tmp );
     
    756857                size_t            byteCount )
    757858{
    758     uint8_t * tmp = tr_new( uint8_t, byteCount );
    759 
     859    uint8_t * tmp;
     860
     861    assert( tr_isPeerIo( io ) );
     862
     863    tmp = tr_new( uint8_t, byteCount );
    760864    tr_peerIoReadBytes( io, inbuf, tmp, byteCount );
    761865    tr_free( tmp );
     
    767871    return time( NULL ) - io->timeCreated;
    768872}
     873
     874/***
     875****
     876***/
     877
     878static int
     879tr_peerIoTryRead( tr_peerIo * io, size_t howmuch )
     880{
     881    int res;
     882
     883    assert( tr_isPeerIo( io ) );
     884
     885    howmuch = tr_bandwidthClamp( io->bandwidth, TR_DOWN, howmuch );
     886
     887    res = howmuch ? evbuffer_read( io->inbuf, io->socket, howmuch ) : 0;
     888
     889    dbgmsg( io, "read %d from peer (%s)", res, (res==-1?strerror(errno):"") );
     890
     891    if( EVBUFFER_LENGTH( io->inbuf ) )
     892        canReadWrapper( io );
     893
     894    if( ( res <= 0 ) && ( io->gotError ) && ( errno != EAGAIN ) && ( errno != EINTR ) && ( errno != EINPROGRESS ) )
     895    {
     896        short what = EVBUFFER_READ | EVBUFFER_ERROR;
     897        if( res == 0 )
     898            what |= EVBUFFER_EOF;
     899        io->gotError( io, what, io->userData );
     900    }
     901
     902    return res;
     903}
     904
     905static int
     906tr_peerIoTryWrite( tr_peerIo * io, size_t howmuch )
     907{
     908    int n;
     909
     910    assert( tr_isPeerIo( io ) );
     911
     912    howmuch = tr_bandwidthClamp( io->bandwidth, TR_UP, howmuch );
     913
     914    n = tr_evbuffer_write( io, io->socket, (int)howmuch );
     915
     916    if( n > 0 )
     917        didWriteWrapper( io, n );
     918
     919    if( ( n < 0 ) && ( io->gotError ) && ( errno != EPIPE ) && ( errno != EAGAIN ) && ( errno != EINTR ) && ( errno != EINPROGRESS ) ) {
     920        short what = EVBUFFER_WRITE | EVBUFFER_ERROR;
     921        io->gotError( io, what, io->userData );
     922    }
     923
     924    return n;
     925}
     926
     927int
     928tr_peerIoFlush( tr_peerIo  * io, tr_direction dir, size_t limit )
     929{
     930    int ret;
     931
     932    assert( tr_isPeerIo( io ) );
     933    assert( tr_isDirection( dir ) );
     934
     935    if( dir==TR_DOWN )
     936        ret = tr_peerIoTryRead( io, limit );
     937    else
     938        ret = tr_peerIoTryWrite( io, limit );
     939
     940    return ret;
     941}
     942
     943struct evbuffer *
     944tr_peerIoGetReadBuffer( tr_peerIo * io )
     945{
     946    assert( tr_isPeerIo( io ) );
     947
     948    return io->inbuf;
     949}
     950
     951tr_bool
     952tr_peerIoHasBandwidthLeft( const tr_peerIo * io, tr_direction dir )
     953{
     954    assert( tr_isPeerIo( io ) );
     955    assert( tr_isDirection( dir ) );
     956
     957    return tr_bandwidthClamp( io->bandwidth, dir, 1024 ) > 0;
     958}
     959
     960/***
     961****
     962****/
     963
     964static void
     965event_enable( tr_peerIo * io, short event )
     966{
     967    assert( tr_isPeerIo( io ) );
     968
     969    if( event & EV_READ )
     970        event_add( &io->event_read, NULL );
     971
     972    if( event & EV_WRITE )
     973        event_add( &io->event_write, NULL );
     974}
     975
     976static void
     977event_disable( struct tr_peerIo * io, short event )
     978{
     979    assert( tr_isPeerIo( io ) );
     980
     981    if( event & EV_READ )
     982        event_del( &io->event_read );
     983
     984    if( event & EV_WRITE )
     985        event_del( &io->event_write );
     986}
     987
     988
     989void
     990tr_peerIoSetEnabled( tr_peerIo    * io,
     991                     tr_direction   dir,
     992                     tr_bool        isEnabled )
     993{
     994    short event;
     995
     996    assert( tr_isPeerIo( io ) );
     997    assert( tr_isDirection( dir ) );
     998
     999    event = dir == TR_UP ? EV_WRITE : EV_READ;
     1000
     1001    if( isEnabled )
     1002        event_enable( io, event );
     1003    else
     1004        event_disable( io, event );
     1005}
  • branches/1.4x/libtransmission/peer-io.h

    r7176 r7455  
    11/*
    2  * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
     2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@transmissionbt.com>
    33 *
    44 * This file is licensed by the GPL version 2.  Works owned by the
     
    1818#define TR_PEER_IO_H
    1919
    20 /**
    21 ***
    22 **/
    23 
    24 struct in_addr;
     20#include "net.h" /* tr_address */
     21/**
     22***
     23**/
     24
    2525struct evbuffer;
    2626struct tr_bandwidth;
    2727struct tr_crypto;
    28 struct tr_iobuf;
    2928typedef struct tr_peerIo tr_peerIo;
    3029
     
    3332**/
    3433
    35 tr_peerIo*           tr_peerIoNewOutgoing( struct tr_handle     * session,
    36                                            const struct in_addr * addr,
    37                                            int                    port,
    38                                            const  uint8_t       * torrentHash );
    39 
    40 tr_peerIo*           tr_peerIoNewIncoming( struct tr_handle     * session,
    41                                            const struct in_addr * addr,
    42                                            uint16_t               port,
    43                                            int                    socket );
    44 
    45 void                 tr_peerIoFree( tr_peerIo * io );
    46 
    47 tr_session*          tr_peerIoGetSession( tr_peerIo * io );
    48 
    49 /**
    50 ***
    51 **/
    52 
    53 void                 tr_peerIoEnableLTEP( tr_peerIo * io,
    54                                           int         flag );
    55 
    56 void                 tr_peerIoEnableFEXT( tr_peerIo * io,
    57                                           int         flag );
    58 
    59 int                  tr_peerIoSupportsLTEP( const tr_peerIo * io );
    60 
    61 int                  tr_peerIoSupportsFEXT( const tr_peerIo * io );
    62 
    63 /**
    64 ***
    65 **/
    66 
    67 const char*          tr_peerIoAddrStr( const struct in_addr * addr,
    68                                        uint16_t               port );
    69 
    70 const char*          tr_peerIoGetAddrStr( const tr_peerIo * io );
    71 
    72 const struct in_addr*tr_peerIoGetAddress( const tr_peerIo * io,
    73                                                 uint16_t * port );
     34tr_peerIo*  tr_peerIoNewOutgoing( tr_session        * session,
     35                                  const tr_address  * addr,
     36                                  tr_port             port,
     37                                  const  uint8_t    * torrentHash );
     38
     39tr_peerIo*  tr_peerIoNewIncoming( tr_session        * session,
     40                                  const tr_address  * addr,
     41                                  tr_port             port,
     42                                  int                 socket );
     43
     44void        tr_peerIoFree       ( tr_peerIo         * io );
     45
     46tr_bool     tr_isPeerIo         ( const tr_peerIo   * io );
     47
     48
     49/**
     50***
     51**/
     52
     53void        tr_peerIoEnableLTEP( tr_peerIo * io, tr_bool flag );
     54
     55tr_bool     tr_peerIoSupportsLTEP( const tr_peerIo * io );
     56
     57void        tr_peerIoEnableFEXT( tr_peerIo * io, tr_bool flag );
     58
     59tr_bool     tr_peerIoSupportsFEXT( const tr_peerIo * io );
     60
     61/**
     62***
     63**/
     64
     65tr_session* tr_peerIoGetSession ( tr_peerIo * io );
     66
     67const char* tr_peerIoAddrStr( const tr_address * addr,
     68                              tr_port            port );
     69
     70const char* tr_peerIoGetAddrStr( const tr_peerIo * io );
     71
     72const tr_address * tr_peerIoGetAddress( const tr_peerIo * io,
     73                                        tr_port         * port );
    7474
    7575const uint8_t*       tr_peerIoGetTorrentHash( tr_peerIo * io );
     
    8282int                  tr_peerIoReconnect( tr_peerIo * io );
    8383
    84 int                  tr_peerIoIsIncoming( const tr_peerIo * io );
    85 
    86 void                 tr_peerIoSetTimeoutSecs( tr_peerIo * io,
    87                                               int         secs );
     84tr_bool              tr_peerIoIsIncoming( const tr_peerIo * io );
    8885
    8986int                  tr_peerIoGetAge( const tr_peerIo * io );
     
    111108ReadState;
    112109
    113 typedef ReadState ( *tr_can_read_cb  )( struct tr_iobuf  * iobuf,
     110typedef ReadState ( *tr_can_read_cb  )( tr_peerIo        * io,
    114111                                        void             * user_data,
    115112                                        size_t           * setme_piece_byte_count );
     
    120117                                        void             * userData );
    121118
    122 typedef void      ( *tr_net_error_cb )( struct tr_iobuf  * ev,
     119typedef void      ( *tr_net_error_cb )( tr_peerIo        * io,
    123120                                        short              what,
    124121                                        void             * userData );
     
    157154EncryptionMode;
    158155
    159 void              tr_peerIoSetEncryption( tr_peerIo * io,
    160                                           int         encryptionMode );
    161 
    162 int               tr_peerIoIsEncrypted( const tr_peerIo * io );
    163 
    164 void              tr_peerIoWriteBytes( tr_peerIo *       io,
    165                                        struct evbuffer * outbuf,
    166                                        const void *      bytes,
    167                                        size_t            byteCount );
    168 
    169 void              tr_peerIoWriteUint8( tr_peerIo *       io,
    170                                        struct evbuffer * outbuf,
    171                                        uint8_t           writeme );
    172 
    173 void              tr_peerIoWriteUint16( tr_peerIo *       io,
    174                                         struct evbuffer * outbuf,
    175                                         uint16_t          writeme );
    176 
    177 void              tr_peerIoWriteUint32( tr_peerIo *       io,
    178                                         struct evbuffer * outbuf,
    179                                         uint32_t          writeme );
    180 
    181 void              tr_peerIoReadBytes( tr_peerIo *       io,
    182                                       struct evbuffer * inbuf,
    183                                       void *            bytes,
    184                                       size_t            byteCount );
    185 
    186 void              tr_peerIoReadUint8( tr_peerIo *       io,
    187                                       struct evbuffer * inbuf,
    188                                       uint8_t *         setme );
    189 
    190 void              tr_peerIoReadUint16( tr_peerIo *       io,
    191                                        struct evbuffer * inbuf,
    192                                        uint16_t *        setme );
    193 
    194 void              tr_peerIoReadUint32( tr_peerIo *       io,
    195                                        struct evbuffer * inbuf,
    196                                        uint32_t *        setme );
    197 
    198 void              tr_peerIoDrain( tr_peerIo *       io,
    199                                   struct evbuffer * inbuf,
    200                                   size_t            byteCount );
    201 
    202 /**
    203 ***
    204 **/
    205 
    206 size_t            tr_peerIoGetWriteBufferSpace( const tr_peerIo * io );
    207 
    208 void              tr_peerIoSetBandwidth( tr_peerIo            * io,
    209                                          struct tr_bandwidth  * bandwidth );
    210 
    211 void              tr_peerIoBandwidthUsed( tr_peerIo           * io,
    212                                           tr_direction          direction,
    213                                           size_t                byteCount,
    214                                           int                   isPieceData );
     156void      tr_peerIoSetEncryption( tr_peerIo * io,
     157                                  int         encryptionMode );
     158
     159int       tr_peerIoIsEncrypted( const tr_peerIo * io );
     160
     161void      tr_peerIoWriteBytes( tr_peerIo *       io,
     162                               struct evbuffer * outbuf,
     163                               const void *      bytes,
     164                               size_t            byteCount );
     165
     166void      tr_peerIoWriteUint8( tr_peerIo *       io,
     167                               struct evbuffer * outbuf,
     168                               uint8_t           writeme );
     169
     170void      tr_peerIoWriteUint16( tr_peerIo *       io,
     171                                struct evbuffer * outbuf,
     172                                uint16_t          writeme );
     173
     174void      tr_peerIoWriteUint32( tr_peerIo *       io,
     175                                struct evbuffer * outbuf,
     176                                uint32_t          writeme );
     177
     178void      tr_peerIoReadBytes( tr_peerIo *       io,
     179                              struct evbuffer * inbuf,
     180                              void *            bytes,
     181                              size_t            byteCount );
     182
     183void      tr_peerIoReadUint8( tr_peerIo *       io,
     184                              struct evbuffer * inbuf,
     185                              uint8_t *         setme );
     186
     187void      tr_peerIoReadUint16( tr_peerIo *       io,
     188                               struct evbuffer * inbuf,
     189                               uint16_t *        setme );
     190
     191void      tr_peerIoReadUint32( tr_peerIo *       io,
     192                               struct evbuffer * inbuf,
     193                               uint32_t *        setme );
     194
     195void      tr_peerIoDrain( tr_peerIo *       io,
     196                          struct evbuffer * inbuf,
     197                          size_t            byteCount );
     198
     199/**
     200***
     201**/
     202
     203size_t    tr_peerIoGetWriteBufferSpace( const tr_peerIo * io );
     204
     205void      tr_peerIoSetBandwidth( tr_peerIo            * io,
     206                                 struct tr_bandwidth  * bandwidth );
     207
     208void      tr_peerIoBandwidthUsed( tr_peerIo           * io,
     209                                  tr_direction          direction,
     210                                  size_t                byteCount,
     211                                  int                   isPieceData );
     212
     213/**
     214***
     215**/
     216
     217tr_bool   tr_peerIoHasBandwidthLeft( const tr_peerIo  * io,
     218                                     tr_direction       direction );
     219
     220void      tr_peerIoSetEnabled( tr_peerIo    * io,
     221                               tr_direction   dir,
     222                               tr_bool        isEnabled );
     223                       
     224int       tr_peerIoFlush( tr_peerIo     * io,
     225                          tr_direction    dir,
     226                          size_t          byteLimit );
     227
     228struct evbuffer * tr_peerIoGetReadBuffer( tr_peerIo * io );
     229
    215230
    216231
  • branches/1.4x/libtransmission/peer-mgr-private.h

    r7354 r7455  
    5353    uint8_t                  encryption_preference;
    5454    uint16_t                 port;
    55     struct in_addr           in_addr;
     55    struct in_addr           addr;
    5656    struct tr_peerIo       * io;
    5757
  • branches/1.4x/libtransmission/peer-mgr.c

    r7354 r7455  
    5858   
    5959    /* how frequently to reallocate bandwidth */
    60     BANDWIDTH_PERIOD_MSEC = 250,
     60    BANDWIDTH_PERIOD_MSEC = 500,
    6161
    6262    /* max # of peers to ask fer per torrent per reconnect pulse */
     
    9090**/
    9191
    92 /* We keep one of these for every peer we know about, whether
    93  * it's connected or not, so the struct must be small.
    94  * When our current connections underperform, we dip back
    95  * into this list for new ones. */
     92enum
     93{
     94    UPLOAD_ONLY_UKNOWN,
     95    UPLOAD_ONLY_YES,
     96    UPLOAD_ONLY_NO
     97};
     98
     99/**
     100 * Peer information that should be kept even before we've connected and
     101 * after we've disconnected.  These are kept in a pool of peer_atoms to decide
     102 * which ones would make good candidates for connecting to, and to watch out
     103 * for banned peers.
     104 *
     105 * @see tr_peer
     106 * @see tr_peermsgs
     107 */
    96108struct peer_atom
    97109{
    98     uint8_t           from;
    99     uint8_t           flags; /* these match the added_f flags */
    100     uint8_t           myflags; /* flags that aren't defined in added_f */
    101     uint16_t          port;
    102     uint16_t          numFails;
    103     struct in_addr    addr;
    104     time_t            time; /* when the peer's connection status last changed */
    105     time_t            piece_data_time;
     110    uint8_t     from;
     111    uint8_t     flags;       /* these match the added_f flags */
     112    uint8_t     myflags;     /* flags that aren't defined in added_f */
     113    uint8_t     uploadOnly;  /* UPLOAD_ONLY_ */
     114    tr_port     port;
     115    uint16_t    numFails;
     116    tr_address  addr;
     117    time_t      time;        /* when the peer's connection status last changed */
     118    time_t      piece_data_time;
    106119};
    107120
     
    131144    tr_ptrArray     * torrents; /* Torrent */
    132145    tr_ptrArray     * incomingHandshakes; /* tr_handshake */
     146    tr_ptrArray     * finishedHandshakes; /* tr_handshake */
    133147    tr_timer        * bandwidthTimer;
    134148};
     
    185199
    186200static int
    187 compareAddresses( const struct in_addr * a,
    188                   const struct in_addr * b )
    189 {
    190     if( a->s_addr != b->s_addr )
    191         return a->s_addr < b->s_addr ? -1 : 1;
    192 
    193     return 0;
    194 }
    195 
    196 static int
    197 handshakeCompareToAddr( const void * va,
    198                         const void * vb )
     201handshakeCompareToAddr( const void * va, const void * vb )
    199202{
    200203    const tr_handshake * a = va;
    201204
    202     return compareAddresses( tr_handshakeGetAddr( a, NULL ), vb );
    203 }
    204 
    205 static int
    206 handshakeCompare( const void * a,
    207                   const void * b )
     205    return tr_compareAddresses( tr_handshakeGetAddr( a, NULL ), vb );
     206}
     207
     208static int
     209handshakeCompare( const void * a, const void * b )
    208210{
    209211    return handshakeCompareToAddr( a, tr_handshakeGetAddr( b, NULL ) );
     
    211213
    212214static tr_handshake*
    213 getExistingHandshake( tr_ptrArray *          handshakes,
    214                       const struct in_addr * in_addr )
    215 {
    216     return tr_ptrArrayFindSorted( handshakes,
    217                                   in_addr,
    218                                   handshakeCompareToAddr );
    219 }
    220 
    221 static int
    222 comparePeerAtomToAddress( const void * va,
    223                           const void * vb )
     215getExistingHandshake( tr_ptrArray      * handshakes,
     216                      const tr_address * addr )
     217{
     218    return tr_ptrArrayFindSorted( handshakes, addr, handshakeCompareToAddr );
     219}
     220
     221static int
     222comparePeerAtomToAddress( const void * va, const void * vb )
    224223{
    225224    const struct peer_atom * a = va;
    226225
    227     return compareAddresses( &a->addr, vb );
    228 }
    229 
    230 static int
    231 comparePeerAtoms( const void * va,
    232                   const void * vb )
     226    return tr_compareAddresses( &a->addr, vb );
     227}
     228
     229static int
     230comparePeerAtoms( const void * va, const void * vb )
    233231{
    234232    const struct peer_atom * b = vb;
     
    271269
    272270static int
    273 peerCompare( const void * va,
    274              const void * vb )
     271peerCompare( const void * va, const void * vb )
    275272{
    276273    const tr_peer * a = va;
    277274    const tr_peer * b = vb;
    278275
    279     return compareAddresses( &a->in_addr, &b->in_addr );
    280 }
    281 
    282 static int
    283 peerCompareToAddr( const void * va,
    284                    const void * vb )
     276    return tr_compareAddresses( &a->addr, &b->addr );
     277}
     278
     279static int
     280peerCompareToAddr( const void * va, const void * vb )
    285281{
    286282    const tr_peer * a = va;
    287283
    288     return compareAddresses( &a->in_addr, vb );
     284    return tr_compareAddresses( &a->addr, vb );
    289285}
    290286
    291287static tr_peer*
    292 getExistingPeer( Torrent *              torrent,
    293                  const struct in_addr * in_addr )
     288getExistingPeer( Torrent          * torrent,
     289                 const tr_address * addr )
    294290{
    295291    assert( torrentIsLocked( torrent ) );
    296     assert( in_addr );
    297 
    298     return tr_ptrArrayFindSorted( torrent->peers,
    299                                   in_addr,
    300                                   peerCompareToAddr );
     292    assert( addr );
     293
     294    return tr_ptrArrayFindSorted( torrent->peers, addr, peerCompareToAddr );
    301295}
    302296
    303297static struct peer_atom*
    304 getExistingAtom( const                  Torrent * t,
    305                  const struct in_addr * addr )
     298getExistingAtom( const Torrent    * t,
     299                 const tr_address * addr )
    306300{
    307301    assert( torrentIsLocked( t ) );
     
    309303}
    310304
    311 static int
    312 peerIsInUse( const Torrent *        ct,
    313              const struct in_addr * addr )
     305static tr_bool
     306peerIsInUse( const Torrent    * ct,
     307             const tr_address * addr )
    314308{
    315309    Torrent * t = (Torrent*) ct;
     
    318312
    319313    return getExistingPeer( t, addr )
    320            || getExistingHandshake( t->outgoingHandshakes, addr )
    321            || getExistingHandshake( t->manager->incomingHandshakes, addr );
     314        || getExistingHandshake( t->outgoingHandshakes, addr )
     315        || getExistingHandshake( t->manager->incomingHandshakes, addr );
    322316}
    323317
    324318static tr_peer*
    325 peerConstructor( tr_torrent * tor, const struct in_addr * in_addr )
     319peerConstructor( tr_torrent * tor, const tr_address * addr )
    326320{
    327321    tr_peer * p;
    328 
    329322    p = tr_new0( tr_peer, 1 );
    330     memcpy( &p->in_addr, in_addr, sizeof( struct in_addr ) );
     323    p->addr = *addr;
    331324    p->bandwidth = tr_bandwidthNew( tor->session, tor->bandwidth );
    332325    return p;
     
    334327
    335328static tr_peer*
    336 getPeer( Torrent *              torrent,
    337          const struct in_addr * in_addr )
     329getPeer( Torrent          * torrent,
     330         const tr_address * addr )
    338331{
    339332    tr_peer * peer;
     
    341334    assert( torrentIsLocked( torrent ) );
    342335
    343     peer = getExistingPeer( torrent, in_addr );
     336    peer = getExistingPeer( torrent, addr );
    344337
    345338    if( peer == NULL )
    346339    {
    347         peer = peerConstructor( torrent->tor, in_addr );
     340        peer = peerConstructor( torrent->tor, addr );
    348341        tr_ptrArrayInsertSorted( torrent->peers, peer, peerCompare );
    349342    }
     
    356349{
    357350    assert( peer );
    358     assert( peer->msgs );
    359 
    360     tr_peerMsgsUnsubscribe( peer->msgs, peer->msgsTag );
    361     tr_peerMsgsFree( peer->msgs );
     351
     352    if( peer->msgs != NULL )
     353    {
     354        tr_peerMsgsUnsubscribe( peer->msgs, peer->msgsTag );
     355        tr_peerMsgsFree( peer->msgs );
     356    }
    362357
    363358    tr_peerIoFree( peer->io );
     
    381376    assert( torrentIsLocked( t ) );
    382377
    383     atom = getExistingAtom( t, &peer->in_addr );
     378    atom = getExistingAtom( t, &peer->addr );
    384379    assert( atom );
    385380    atom->time = time( NULL );
     
    456451}
    457452
    458 /**
    459  * For explanation, see http://www.bittorrent.org/fast_extensions.html
    460  * Also see the "test-allowed-set" unit test
    461  *
    462  * @param k number of pieces in set
    463  * @param sz number of pieces in the torrent
    464  * @param infohash torrent's SHA1 hash
    465  * @param ip peer's address
    466  */
    467 struct tr_bitfield *
    468 tr_peerMgrGenerateAllowedSet(
    469     const uint32_t         k,
    470     const uint32_t         sz,
    471     const                  uint8_t        *
    472                            infohash,
    473     const struct in_addr * ip )
    474 {
    475     uint8_t       w[SHA_DIGEST_LENGTH + 4];
    476     uint8_t       x[SHA_DIGEST_LENGTH];
    477     tr_bitfield * a;
    478     uint32_t      a_size;
    479 
    480     *(uint32_t*)w = ntohl( htonl( ip->s_addr ) & 0xffffff00 );   /* (1) */
    481     memcpy( w + 4, infohash, SHA_DIGEST_LENGTH );              /* (2) */
    482     tr_sha1( x, w, sizeof( w ), NULL );                        /* (3) */
    483 
    484     a = tr_bitfieldNew( sz );
    485     a_size = 0;
    486 
    487     while( a_size < k )
    488     {
    489         int i;
    490         for( i = 0; i < 5 && a_size < k; ++i )                      /* (4) */
    491         {
    492             uint32_t j = i * 4;                                /* (5) */
    493             uint32_t y = ntohl( *( uint32_t* )( x + j ) );             /* (6) */
    494             uint32_t index = y % sz;                           /* (7) */
    495             if( !tr_bitfieldHas( a, index ) )                  /* (8) */
    496             {
    497                 tr_bitfieldAdd( a, index );                    /* (9) */
    498                 ++a_size;
    499             }
    500         }
    501         tr_sha1( x, x, sizeof( x ), NULL );                    /* (3) */
    502     }
    503 
    504     return a;
    505 }
    506453
    507454static int bandwidthPulse( void * vmgr );
     
    516463    m->torrents = tr_ptrArrayNew( );
    517464    m->incomingHandshakes = tr_ptrArrayNew( );
     465    m->finishedHandshakes = tr_ptrArrayNew( );
    518466    m->bandwidthTimer = tr_timerNew( session, bandwidthPulse, m, BANDWIDTH_PERIOD_MSEC );
    519467    return m;
     
    523471tr_peerMgrFree( tr_peerMgr * manager )
    524472{
     473    tr_handshake * handshake;
     474
    525475    managerLock( manager );
    526476
     
    534484    tr_ptrArrayFree( manager->incomingHandshakes, NULL );
    535485
     486    while(( handshake = tr_ptrArrayPop( manager->finishedHandshakes )))
     487        tr_handshakeFree( handshake );
     488
     489    tr_ptrArrayFree( manager->finishedHandshakes, NULL );
     490
    536491    /* free the torrents. */
    537492    tr_ptrArrayFree( manager->torrents, torrentDestructor );
     
    542497
    543498static tr_peer**
    544 getConnectedPeers( Torrent * t,
    545                    int *     setmeCount )
    546 {
    547     int       i, peerCount, connectionCount;
     499getConnectedPeers( Torrent * t, int * setmeCount )
     500{
     501    int i, peerCount, connectionCount;
    548502    tr_peer **peers;
    549503    tr_peer **ret;
     
    578532***/
    579533
    580 int
    581 tr_peerMgrPeerIsSeed( const tr_peerMgr *    mgr,
    582                       const uint8_t *        torrentHash,
    583                       const struct in_addr * addr )
    584 {
    585     int                      isSeed = FALSE;
    586     const Torrent *          t = NULL;
     534tr_bool
     535tr_peerMgrPeerIsSeed( const tr_peerMgr  * mgr,
     536                      const uint8_t     * torrentHash,
     537                      const tr_address * addr )
     538{
     539    tr_bool isSeed = FALSE;
     540    const Torrent * t = NULL;
    587541    const struct peer_atom * atom = NULL;
    588542
     
    648602
    649603static int
    650 compareRefillPiece( const void * aIn,
    651                     const void * bIn )
     604compareRefillPiece( const void * aIn, const void * bIn )
    652605{
    653606    const struct tr_refill_piece * a = aIn;
     
    678631
    679632static tr_piece_index_t *
    680 getPreferredPieces( Torrent           * t,
    681                     tr_piece_index_t  * pieceCount )
     633getPreferredPieces( Torrent * t, tr_piece_index_t * pieceCount )
    682634{
    683635    const tr_torrent  * tor = t->tor;
     
    877829        for( j=0; !handled && j<peerCount; )
    878830        {
    879             const int val = tr_peerMsgsAddRequest( peers[j]->msgs,
    880                                                    index, offset, length );
     831            const tr_addreq_t val = tr_peerMsgsAddRequest( peers[j]->msgs, index, offset, length );
    881832            switch( val )
    882833            {
     
    905856        for( j=0; !handled && j<webseedCount; )
    906857        {
    907             const tr_addreq_t val = tr_webseedAddRequest( webseeds[j],
    908                                                           index, offset, length );
     858            const tr_addreq_t val = tr_webseedAddRequest( webseeds[j], index, offset, length );
    909859            switch( val )
    910860            {
     
    943893    assert( torrentIsLocked( t ) );
    944894
     895    tordbg( t, "got a block; cancelling any duplicate requests from peers %"PRIu32":%"PRIu32"->%"PRIu32, index, offset, length );
    945896    peers = getConnectedPeers( t, &size );
    946897    for( i=0; i<size; ++i )
     
    954905{
    955906    tordbg( t, "increasing peer %s strike count to %d",
    956             tr_peerIoAddrStr( &peer->in_addr,
     907            tr_peerIoAddrStr( &peer->addr,
    957908                              peer->port ), peer->strikes + 1 );
    958909
    959910    if( ++peer->strikes >= MAX_BAD_PIECES_PER_PEER )
    960911    {
    961         struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
     912        struct peer_atom * atom = getExistingAtom( t, &peer->addr );
    962913        atom->myflags |= MYFLAG_BANNED;
    963914        peer->doPurge = 1;
     
    988939
    989940static void
    990 peerCallbackFunc( void * vpeer,
    991                   void * vevent,
    992                   void * vt )
    993 {
    994     tr_peer *             peer = vpeer; /* may be NULL if peer is a webseed */
    995     Torrent *             t = (Torrent *) vt;
     941peerSuggestedPiece( Torrent            * t UNUSED,
     942                    tr_peer            * peer UNUSED,
     943                    tr_piece_index_t     pieceIndex UNUSED,
     944                    int                  isFastAllowed UNUSED )
     945{
     946#if 0
     947    assert( t );
     948    assert( peer );
     949    assert( peer->msgs );
     950
     951    /* is this a valid piece? */
     952    if(  pieceIndex >= t->tor->info.pieceCount )
     953        return;
     954
     955    /* don't ask for it if we've already got it */
     956    if( tr_cpPieceIsComplete( t->tor->completion, pieceIndex ) )
     957        return;
     958
     959    /* don't ask for it if they don't have it */
     960    if( !tr_bitfieldHas( peer->have, pieceIndex ) )
     961        return;
     962
     963    /* don't ask for it if we're choked and it's not fast */
     964    if( !isFastAllowed && peer->clientIsChoked )
     965        return;
     966
     967    /* request the blocks that we don't have in this piece */
     968    {
     969        tr_block_index_t block;
     970        const tr_torrent * tor = t->tor;
     971        const tr_block_index_t start = tr_torPieceFirstBlock( tor, pieceIndex );
     972        const tr_block_index_t end = start + tr_torPieceCountBlocks( tor, pieceIndex );
     973
     974        for( block=start; block<end; ++block )
     975        {
     976            if( !tr_cpBlockIsComplete( tor->completion, block ) )
     977            {
     978                const uint32_t offset = getBlockOffsetInPiece( tor, block );
     979                const uint32_t length = tr_torBlockCountBytes( tor, block );
     980                tr_peerMsgsAddRequest( peer->msgs, pieceIndex, offset, length );
     981                incrementPieceRequests( t, pieceIndex );
     982            }
     983        }
     984    }
     985#endif
     986}
     987
     988static void
     989peerCallbackFunc( void * vpeer, void * vevent, void * vt )
     990{
     991    tr_peer * peer = vpeer; /* may be NULL if peer is a webseed */
     992    Torrent * t = vt;
    996993    const tr_peer_event * e = vevent;
    997994
     
    1000997    switch( e->eventType )
    1001998    {
     999        case TR_PEER_UPLOAD_ONLY:
     1000            /* update our atom */
     1001            if( peer ) {
     1002                struct peer_atom * a = getExistingAtom( t, &peer->addr );
     1003                a->uploadOnly = e->uploadOnly ? UPLOAD_ONLY_YES : UPLOAD_ONLY_NO;
     1004            }
     1005            break;
     1006
    10021007        case TR_PEER_NEED_REQ:
    10031008            refillSoon( t );
     
    10241029            /* update our atom */
    10251030            if( peer ) {
    1026                 struct peer_atom * a = getExistingAtom( t, &peer->in_addr );
     1031                struct peer_atom * a = getExistingAtom( t, &peer->addr );
    10271032                if( e->wasPieceData )
    10281033                    a->piece_data_time = now;
     
    10311036            break;
    10321037        }
     1038
     1039        case TR_PEER_CLIENT_GOT_SUGGEST:
     1040            if( peer )
     1041                peerSuggestedPiece( t, peer, e->pieceIndex, FALSE );
     1042            break;
     1043
     1044        case TR_PEER_CLIENT_GOT_ALLOWED_FAST:
     1045            if( peer )
     1046                peerSuggestedPiece( t, peer, e->pieceIndex, TRUE );
     1047            break;
    10331048
    10341049        case TR_PEER_CLIENT_GOT_DATA:
     
    10361051            const time_t now = time( NULL );
    10371052            tr_torrent * tor = t->tor;
    1038 
    10391053            tor->activityDate = now;
    10401054
     
    10541068            /* update our atom */
    10551069            if( peer ) {
    1056                 struct peer_atom * a = getExistingAtom( t, &peer->in_addr );
     1070                struct peer_atom * a = getExistingAtom( t, &peer->addr );
    10571071                if( e->wasPieceData )
    10581072                    a->piece_data_time = now;
     
    10661080            if( peer )
    10671081            {
    1068                 struct peer_atom * atom = getExistingAtom( t,
    1069                                                            &peer->in_addr );
    1070                 const int          peerIsSeed = e->progress >= 1.0;
    1071                 if( peerIsSeed )
    1072                 {
    1073                     tordbg( t, "marking peer %s as a seed",
    1074                            tr_peerIoAddrStr( &atom->addr,
    1075                                              atom->port ) );
     1082                struct peer_atom * atom = getExistingAtom( t, &peer->addr );
     1083                const int peerIsSeed = e->progress >= 1.0;
     1084                if( peerIsSeed ) {
     1085                    tordbg( t, "marking peer %s as a seed", tr_peerIoAddrStr( &atom->addr, atom->port ) );
    10761086                    atom->flags |= ADDED_F_SEED_FLAG;
    1077                 }
    1078                 else
    1079                 {
    1080                     tordbg( t, "marking peer %s as a non-seed",
    1081                            tr_peerIoAddrStr( &atom->addr,
    1082                                              atom->port ) );
     1087                } else {
     1088                    tordbg( t, "marking peer %s as a non-seed", tr_peerIoAddrStr( &atom->addr, atom->port ) );
    10831089                    atom->flags &= ~ADDED_F_SEED_FLAG;
    10841090                }
     
    10911097            tr_torrent *     tor = t->tor;
    10921098
    1093             tr_block_index_t block = _tr_block( tor, e->pieceIndex,
    1094                                                 e->offset );
     1099            tr_block_index_t block = _tr_block( tor, e->pieceIndex, e->offset );
    10951100
    10961101            tr_cpBlockAdd( tor->completion, block );
     
    11021107            {
    11031108                const tr_piece_index_t p = e->pieceIndex;
    1104                 const int              ok = tr_ioTestPiece( tor, p );
     1109                const tr_bool ok = tr_ioTestPiece( tor, p );
    11051110
    11061111                if( !ok )
    11071112                {
    1108                     tr_torerr( tor,
    1109                               _( "Piece %lu, which was just downloaded, failed its checksum test" ),
    1110                               (unsigned long)p );
     1113                    tr_torerr( tor, _( "Piece %lu, which was just downloaded, failed its checksum test" ),
     1114                               (unsigned long)p );
    11111115                }
    11121116
     
    11191123                else
    11201124                {
    1121                     int        i, peerCount;
     1125                    int i, peerCount;
    11221126                    tr_peer ** peers = getConnectedPeers( t, &peerCount );
    11231127                    for( i = 0; i < peerCount; ++i )
     
    11361140                addStrike( t, peer );
    11371141                peer->doPurge = 1;
     1142                tordbg( t, "setting doPurge because we got an EINVAL error" );
    11381143            }
    11391144            else if( ( e->err == ERANGE )
     
    11431148                /* some protocol error from the peer */
    11441149                peer->doPurge = 1;
     1150                tordbg( t, "setting doPurge because we got an ERANGE, EMSGSIZE, or ENOTCONN error" );
    11451151            }
    11461152            else /* a local error, such as an IO error */
     
    11621168
    11631169static void
    1164 ensureAtomExists( Torrent *              t,
    1165                   const struct in_addr * addr,
    1166                   uint16_t               port,
    1167                   uint8_t                flags,
    1168                   uint8_t                from )
     1170ensureAtomExists( Torrent          * t,
     1171                  const tr_address * addr,
     1172                  tr_port            port,
     1173                  uint8_t            flags,
     1174                  uint8_t            from )
    11691175{
    11701176    if( getExistingAtom( t, addr ) == NULL )
     
    11761182        a->flags = flags;
    11771183        a->from = from;
    1178         tordbg( t, "got a new atom: %s",
    1179                tr_peerIoAddrStr( &a->addr, a->port ) );
     1184        tordbg( t, "got a new atom: %s", tr_peerIoAddrStr( &a->addr, a->port ) );
    11801185        tr_ptrArrayInsertSorted( t->pool, a, comparePeerAtoms );
    11811186    }
     
    11911196getPeerCount( const Torrent * t )
    11921197{
    1193     return tr_ptrArraySize( t->peers ) + tr_ptrArraySize(
    1194                t->outgoingHandshakes );
     1198    return tr_ptrArraySize( t->peers ) + tr_ptrArraySize( t->outgoingHandshakes );
    11951199}
    11961200
    11971201/* FIXME: this is kind of a mess. */
    1198 static int
    1199 myHandshakeDoneCB( tr_handshake * handshake,
    1200                    tr_peerIo *    io,
     1202static tr_bool
     1203myHandshakeDoneCB( tr_handshake  * handshake,
     1204                   tr_peerIo     * io,
    12011205                   int             isConnected,
    12021206                   const uint8_t * peer_id,
    1203                    void *          vmanager )
    1204 {
    1205     int                    ok = isConnected;
    1206     int                    success = FALSE;
    1207     uint16_t               port;
    1208     const struct in_addr * addr;
    1209     tr_peerMgr *           manager = (tr_peerMgr*) vmanager;
    1210     Torrent *              t;
    1211     tr_handshake *        ours;
     1207                   void          * vmanager )
     1208{
     1209    tr_bool            ok = isConnected;
     1210    tr_bool            success = FALSE;
     1211    tr_port            port;
     1212    const tr_address * addr;
     1213    tr_peerMgr       * manager = vmanager;
     1214    Torrent          * t;
     1215    tr_handshake     * ours;
    12121216
    12131217    assert( io );
     
    12431247                ++atom->numFails;
    12441248        }
    1245 
    1246         tr_peerIoFree( io );
    12471249    }
    12481250    else /* looking good */
     
    12571259        {
    12581260            tordbg( t, "banned peer %s tried to reconnect",
    1259                    tr_peerIoAddrStr( &atom->addr,
    1260                                      atom->port ) );
    1261             tr_peerIoFree( io );
     1261                    tr_peerIoAddrStr( &atom->addr, atom->port ) );
    12621262        }
    12631263        else if( tr_peerIoIsIncoming( io )
     
    12651265
    12661266        {
    1267             tr_peerIoFree( io );
    12681267        }
    12691268        else
     
    12731272            if( peer ) /* we already have this peer */
    12741273            {
    1275                 tr_peerIoFree( io );
    12761274            }
    12771275            else
     
    12891287
    12901288                peer->port = port;
    1291                 peer->io = io;
    1292                 peer->msgs = tr_peerMsgsNew( t->tor, peer, peerCallbackFunc, t, &peer->msgsTag );
     1289                peer->io = tr_handshakeStealIO( handshake );
     1290                tr_peerMsgsNew( t->tor, peer, peerCallbackFunc, t, &peer->msgsTag );
    12931291                tr_peerIoSetBandwidth( io, peer->bandwidth );
    12941292
     
    12981296    }
    12991297
     1298    if( !success )
     1299        tr_ptrArrayAppend( manager->finishedHandshakes, handshake );
     1300
    13001301    if( t )
    13011302        torrentUnlock( t );
     
    13051306
    13061307void
    1307 tr_peerMgrAddIncoming( tr_peerMgr *     manager,
    1308                        struct in_addr * addr,
    1309                        uint16_t         port,
    1310                        int              socket )
     1308tr_peerMgrAddIncoming( tr_peerMgr * manager,
     1309                       tr_address * addr,
     1310                       tr_port      port,
     1311                       int          socket )
    13111312{
    13121313    managerLock( manager );
     
    13141315    if( tr_sessionIsAddressBlocked( manager->session, addr ) )
    13151316    {
    1316         tr_dbg( "Banned IP address \"%s\" tried to connect to us",
    1317                inet_ntoa( *addr ) );
     1317        tr_dbg( "Banned IP address \"%s\" tried to connect to us", inet_ntoa( *addr ) );
    13181318        tr_netClose( socket );
    13191319    }
     
    13391339
    13401340    managerUnlock( manager );
     1341}
     1342
     1343static tr_bool
     1344tr_isPex( const tr_pex * pex )
     1345{
     1346    return pex && tr_isAddress( &pex->addr );
    13411347}
    13421348
     
    13471353                  const tr_pex *  pex )
    13481354{
    1349     Torrent * t;
    1350 
    1351     managerLock( manager );
    1352 
    1353     t = getExistingTorrent( manager, torrentHash );
    1354     if( !tr_sessionIsAddressBlocked( t->manager->session, &pex->in_addr ) )
    1355         ensureAtomExists( t, &pex->in_addr, pex->port, pex->flags, from );
    1356 
    1357     managerUnlock( manager );
     1355    if( tr_isPex( pex ) ) /* safeguard against corrupt data */
     1356    {
     1357        Torrent * t;
     1358        managerLock( manager );
     1359
     1360        t = getExistingTorrent( manager, torrentHash );
     1361        if( !tr_sessionIsAddressBlocked( t->manager->session, &pex->addr ) )
     1362            ensureAtomExists( t, &pex->addr, pex->port, pex->flags, from );
     1363
     1364        managerUnlock( manager );
     1365    }
    13581366}
    13591367
     
    13721380    for( i = 0; i < n; ++i )
    13731381    {
    1374         memcpy( &pex[i].in_addr, walk, 4 ); walk += 4;
     1382        memcpy( &pex[i].addr, walk, 4 ); walk += 4;
    13751383        memcpy( &pex[i].port, walk, 2 ); walk += 2;
    13761384        if( added_f && ( n == added_f_len ) )
     
    14061414            if( tr_bitfieldHas( peer->blame, pieceIndex ) )
    14071415            {
    1408                 tordbg(
    1409                     t,
    1410                     "peer %s contributed to corrupt piece (%d); now has %d strikes",
    1411                     tr_peerIoAddrStr( &peer->in_addr, peer->port ),
    1412                     pieceIndex, (int)peer->strikes + 1 );
     1416                tordbg( t, "peer %s contributed to corrupt piece (%d); now has %d strikes",
     1417                        tr_peerIoAddrStr( &peer->addr, peer->port ),
     1418                        pieceIndex, (int)peer->strikes + 1 );
    14131419                addStrike( t, peer );
    14141420            }
     
    14181424
    14191425int
    1420 tr_pexCompare( const void * va,
    1421                const void * vb )
     1426tr_pexCompare( const void * va, const void * vb )
    14221427{
    14231428    const tr_pex * a = va;
    14241429    const tr_pex * b = vb;
    1425     int            i =
    1426         memcmp( &a->in_addr, &b->in_addr, sizeof( struct in_addr ) );
    1427 
    1428     if( i ) return i;
    1429     if( a->port < b->port ) return -1;
    1430     if( a->port > b->port ) return 1;
     1430    int i;
     1431
     1432    assert( tr_isPex( a ) );
     1433    assert( tr_isPex( b ) );
     1434
     1435    if(( i = tr_compareAddresses( &a->addr, &b->addr )))
     1436        return i;
     1437
     1438    if( a->port != b->port )
     1439        return a->port < b->port ? -1 : 1;
     1440
    14311441    return 0;
    14321442}
    1433 
    1434 int tr_pexCompare( const void * a,
    1435                    const void * b );
    14361443
    14371444static int
     
    14481455
    14491456int
    1450 tr_peerMgrGetPeers( tr_peerMgr *    manager,
    1451                     const uint8_t * torrentHash,
    1452                     tr_pex **      setme_pex )
     1457tr_peerMgrGetPeers( tr_peerMgr      * manager,
     1458                    const uint8_t   * torrentHash,
     1459                    tr_pex         ** setme_pex )
    14531460{
    14541461    int peerCount = 0;
     
    14581465
    14591466    t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
    1460     if( !t )
     1467    if( t == NULL )
    14611468    {
    14621469        *setme_pex = NULL;
     
    14691476        tr_pex * walk = pex;
    14701477
    1471         for( i = 0; i < peerCount; ++i, ++walk )
     1478        for( i=0; i<peerCount; ++i, ++walk )
    14721479        {
    14731480            const tr_peer * peer = peers[i];
    1474             walk->in_addr = peer->in_addr;
     1481            const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
     1482
     1483            assert( tr_isAddress( &peer->addr ) );
     1484            walk->addr = peer->addr;
    14751485            walk->port = peer->port;
    14761486            walk->flags = 0;
    1477             if( peerPrefersCrypto( peer ) ) walk->flags |= ADDED_F_ENCRYPTION_FLAG;
    1478             if( peer->progress >= 1.0 ) walk->flags |= ADDED_F_SEED_FLAG;
     1487            if( peerPrefersCrypto( peer ) )
     1488                walk->flags |= ADDED_F_ENCRYPTION_FLAG;
     1489            if( ( atom->uploadOnly == UPLOAD_ONLY_YES ) || ( peer->progress >= 1.0 ) )
     1490                walk->flags |= ADDED_F_SEED_FLAG;
    14791491        }
    14801492
     
    16031615    const tr_torrent * tor;
    16041616    float              interval;
    1605     int                isComplete;
     1617    tr_bool            isSeed;
    16061618    int                peerCount;
    16071619    const tr_peer **   peers;
     
    16121624    tor = t->tor;
    16131625    interval = tor->info.pieceCount / (float)tabCount;
    1614     isComplete = tor
    1615                  && ( tr_cpGetStatus ( tor->completion ) == TR_CP_COMPLETE );
     1626    isSeed = tor && ( tr_cpGetStatus ( tor->completion ) == TR_CP_COMPLETE );
    16161627    peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
    16171628
     
    16221633        const int piece = i * interval;
    16231634
    1624         if( isComplete || tr_cpPieceIsComplete( tor->completion, piece ) )
     1635        if( isSeed || tr_cpPieceIsComplete( tor->completion, piece ) )
    16251636            tab[i] = -1;
    1626         else if( peerCount )
    1627         {
     1637        else if( peerCount ) {
    16281638            int j;
    16291639            for( j = 0; j < peerCount; ++j )
     
    16451655    tr_peer **    peers;
    16461656    tr_bitfield * pieces;
    1647 
    16481657    managerLock( manager );
    16491658
     
    16631672                          const uint8_t *    torrentHash )
    16641673{
    1665     int             ret;
     1674    int ret;
    16661675    const Torrent * t;
    1667 
    16681676    managerLock( manager );
    16691677
    16701678    t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
    1671     ret = t && ( !tr_ptrArrayEmpty( t->peers )
    1672                || !tr_ptrArrayEmpty( t->webseeds ) );
     1679    ret = t && ( !tr_ptrArrayEmpty( t->peers ) || !tr_ptrArrayEmpty( t->webseeds ) );
    16731680
    16741681    managerUnlock( manager );
     
    16781685void
    16791686tr_peerMgrTorrentStats( const tr_peerMgr * manager,
    1680                         const uint8_t *    torrentHash,
    1681                         int *              setmePeersKnown,
    1682                         int *              setmePeersConnected,
    1683                         int *              setmeSeedsConnected,
    1684                         int *              setmeWebseedsSendingToUs,
    1685                         int *              setmePeersSendingToUs,
    1686                         int *              setmePeersGettingFromUs,
    1687                         int *              setmePeersFrom )
    1688 {
    1689     int                 i, size;
    1690     const Torrent *     t;
    1691     const tr_peer **    peers;
     1687                        const uint8_t    * torrentHash,
     1688                        int              * setmePeersKnown,
     1689                        int              * setmePeersConnected,
     1690                        int              * setmeSeedsConnected,
     1691                        int              * setmeWebseedsSendingToUs,
     1692                        int              * setmePeersSendingToUs,
     1693                        int              * setmePeersGettingFromUs,
     1694                        int              * setmePeersFrom )
     1695{
     1696    int i, size;
     1697    const Torrent * t;
     1698    const tr_peer ** peers;
    16921699    const tr_webseed ** webseeds;
    16931700
     
    17041711    *setmeWebseedsSendingToUs  = 0;
    17051712
    1706     for( i = 0; i < TR_PEER_FROM__MAX; ++i )
     1713    for( i=0; i<TR_PEER_FROM__MAX; ++i )
    17071714        setmePeersFrom[i] = 0;
    17081715
    1709     for( i = 0; i < size; ++i )
    1710     {
    1711         const tr_peer *          peer = peers[i];
    1712         const struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
     1716    for( i=0; i<size; ++i )
     1717    {
     1718        const tr_peer * peer = peers[i];
     1719        const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
    17131720
    17141721        if( peer->io == NULL ) /* not connected */
    17151722            continue;
    17161723
    1717         ++ * setmePeersConnected;
     1724        ++*setmePeersConnected;
    17181725
    17191726        ++setmePeersFrom[atom->from];
    17201727
    17211728        if( clientIsDownloadingFrom( peer ) )
    1722             ++ * setmePeersSendingToUs;
     1729            ++*setmePeersSendingToUs;
    17231730
    17241731        if( clientIsUploadingTo( peer ) )
    1725             ++ * setmePeersGettingFromUs;
     1732            ++*setmePeersGettingFromUs;
    17261733
    17271734        if( atom->flags & ADDED_F_SEED_FLAG )
    1728             ++ * setmeSeedsConnected;
     1735            ++*setmeSeedsConnected;
    17291736    }
    17301737
    17311738    webseeds = (const tr_webseed **) tr_ptrArrayPeek( t->webseeds, &size );
    1732     for( i = 0; i < size; ++i )
    1733     {
     1739    for( i=0; i<size; ++i )
    17341740        if( tr_webseedIsActive( webseeds[i] ) )
    1735             ++ * setmeWebseedsSendingToUs;
    1736     }
     1741            ++*setmeWebseedsSendingToUs;
    17371742
    17381743    managerUnlock( manager );
     
    17431748                     const uint8_t *    torrentHash )
    17441749{
    1745     const Torrent *     t;
     1750    const Torrent * t;
    17461751    const tr_webseed ** webseeds;
    1747     int                 i;
    1748     int                 webseedCount;
    1749     float *             ret;
     1752    int i;
     1753    int webseedCount;
     1754    float * ret;
    17501755
    17511756    assert( manager );
     
    17581763    ret = tr_new0( float, webseedCount );
    17591764
    1760     for( i = 0; i < webseedCount; ++i )
     1765    for( i=0; i<webseedCount; ++i )
    17611766        if( !tr_webseedGetSpeed( webseeds[i], &ret[i] ) )
    17621767            ret[i] = -1.0;
     
    17671772
    17681773double
    1769 tr_peerGetPieceSpeed( const tr_peer    * peer,
    1770                       tr_direction       direction )
     1774tr_peerGetPieceSpeed( const tr_peer * peer, tr_direction direction )
    17711775{
    17721776    assert( peer );
     
    17981802        char *                   pch;
    17991803        const tr_peer *          peer = peers[i];
    1800         const struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
     1804        const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
    18011805        tr_peer_stat *           stat = ret + i;
    18021806
    1803         tr_netNtop( &peer->in_addr, stat->addr, sizeof( stat->addr ) );
     1807        tr_netNtop( &peer->addr, stat->addr, sizeof( stat->addr ) );
    18041808        tr_strlcpy( stat->client, ( peer->client ? peer->client : "" ),
    18051809                   sizeof( stat->client ) );
     
    18171821        stat->isDownloadingFrom  = clientIsDownloadingFrom( peer );
    18181822        stat->isUploadingTo      = clientIsUploadingTo( peer );
     1823        stat->isSeed             = ( atom->uploadOnly == UPLOAD_ONLY_YES ) || ( peer->progress >= 1.0 );
    18191824
    18201825        pch = stat->flagStr;
     
    18241829        if( stat->isUploadingTo ) *pch++ = 'U';
    18251830        else if( stat->peerIsInterested ) *pch++ = 'u';
    1826         if( !stat->clientIsChoked && !stat->clientIsInterested ) *pch++ =
    1827                 'K';
     1831        if( !stat->clientIsChoked && !stat->clientIsInterested ) *pch++ = 'K';
    18281832        if( !stat->peerIsChoked && !stat->peerIsInterested ) *pch++ = '?';
    18291833        if( stat->isEncrypted ) *pch++ = 'E';
     
    18991903    {
    19001904        tr_peer * peer = peers[i];
     1905        struct peer_atom * atom = getExistingAtom( t, &peer->addr );
     1906
    19011907        if( peer->progress >= 1.0 ) /* choke all seeds */
     1908        {
    19021909            tr_peerMsgsSetChoke( peer->msgs, TRUE );
    1903         else if( chokeAll )
     1910        }
     1911        else if( atom->uploadOnly == UPLOAD_ONLY_YES ) /* choke partial seeds */
     1912        {
    19041913            tr_peerMsgsSetChoke( peer->msgs, TRUE );
    1905         else {
     1914        }
     1915        else if( chokeAll ) /* choke everyone if we're not uploading */
     1916        {
     1917            tr_peerMsgsSetChoke( peer->msgs, TRUE );
     1918        }
     1919        else
     1920        {
    19061921            struct ChokeData * n = &choke[size++];
    19071922            n->peer         = peer;
     
    19281943     */
    19291944    unchokedInterested = 0;
    1930     for( i = 0; i < size && unchokedInterested < MAX_UNCHOKED_PEERS; ++i )
    1931     {
     1945    for( i=0; i<size && unchokedInterested<MAX_UNCHOKED_PEERS; ++i ) {
    19321946        choke[i].doUnchoke = 1;
    19331947        if( choke[i].isInterested )
     
    19381952    if( i < size )
    19391953    {
    1940         int                n;
     1954        int n;
    19411955        struct ChokeData * c;
    1942         tr_ptrArray *      randPool = tr_ptrArrayNew( );
    1943 
    1944         for( ; i < size; ++i )
     1956        tr_ptrArray * randPool = tr_ptrArrayNew( );
     1957
     1958        for( ; i<size; ++i )
    19451959        {
    19461960            if( choke[i].isInterested )
    19471961            {
    19481962                const tr_peer * peer = choke[i].peer;
    1949                 int             x = 1, y;
     1963                int x = 1, y;
    19501964                if( isNew( peer ) ) x *= 3;
    19511965                if( isSame( peer ) ) x *= 3;
    1952                 for( y = 0; y < x; ++y )
     1966                for( y=0; y<x; ++y )
    19531967                    tr_ptrArrayAppend( randPool, &choke[i] );
    19541968            }
    19551969        }
    19561970
    1957         if( ( n = tr_ptrArraySize( randPool ) ) )
     1971        if(( n = tr_ptrArraySize( randPool )))
    19581972        {
    1959             c = tr_ptrArrayNth( randPool, tr_cryptoWeakRandInt( n ) );
     1973            c = tr_ptrArrayNth( randPool, tr_cryptoWeakRandInt( n ));
    19601974            c->doUnchoke = 1;
    19611975            t->optimistic = c->peer;
     
    19651979    }
    19661980
    1967     for( i = 0; i < size; ++i )
     1981    for( i=0; i<size; ++i )
    19681982        tr_peerMsgsSetChoke( choke[i].peer->msgs, !choke[i].doUnchoke );
    19691983
     
    19972011    const tr_torrent *       tor = t->tor;
    19982012    const time_t             now = time( NULL );
    1999     const struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
     2013    const struct peer_atom * atom = getExistingAtom( t, &peer->addr );
    20002014
    20012015    /* if it's marked for purging, close it */
     
    20032017    {
    20042018        tordbg( t, "purging peer %s because its doPurge flag is set",
    2005                tr_peerIoAddrStr( &atom->addr,
    2006                                  atom->port ) );
     2019                tr_peerIoAddrStr( &atom->addr, atom->port ) );
    20072020        return TRUE;
    20082021    }
     
    20172030        else if( peer->progress < tr_cpPercentDone( tor->completion ) )
    20182031            peerHasEverything = FALSE;
    2019         else
    2020         {
    2021             tr_bitfield * tmp =
    2022                 tr_bitfieldDup( tr_cpPieceBitfield( tor->completion ) );
     2032        else {
     2033            tr_bitfield * tmp = tr_bitfieldDup( tr_cpPieceBitfield( tor->completion ) );
    20232034            tr_bitfieldDifference( tmp, peer->have );
    20242035            peerHasEverything = tr_bitfieldCountTrueBits( tmp ) == 0;
    20252036            tr_bitfieldFree( tmp );
    20262037        }
    2027         if( peerHasEverything
    2028           && ( !tr_torrentAllowsPex( tor ) || ( now - atom->time >= 30 ) ) )
     2038
     2039        if( peerHasEverything && ( !tr_torrentAllowsPex(tor) || (now-atom->time>=30 )))
    20292040        {
    20302041            tordbg( t, "purging peer %s because we're both seeds",
    2031                    tr_peerIoAddrStr( &atom->addr,
    2032                                      atom->port ) );
     2042                    tr_peerIoAddrStr( &atom->addr, atom->port ) );
    20332043            return TRUE;
    20342044        }
     
    20602070
    20612071static tr_peer **
    2062 getPeersToClose( Torrent * t,
    2063                  int *     setmeSize )
    2064 {
    2065     int               i, peerCount, outsize;
    2066     tr_peer **        peers = (tr_peer**) tr_ptrArrayPeek( t->peers,
    2067                                                            &peerCount );
     2072getPeersToClose( Torrent * t, int * setmeSize )
     2073{
     2074    int i, peerCount, outsize;
     2075    tr_peer ** peers = (tr_peer**) tr_ptrArrayPeek( t->peers, &peerCount );
    20682076    struct tr_peer ** ret = tr_new( tr_peer *, peerCount );
    20692077
     
    21012109        return a->time < b->time ? -1 : 1;
    21022110
     2111    /* all other things being equal, prefer peers whose
     2112     * information comes from a more reliable source */
     2113    if( a->from != b->from )
     2114        return a->from < b->from ? -1 : 1;
     2115
    21032116    return 0;
    21042117}
     
    21132126     * data, try to reconnect to them sooner rather that later -- we don't
    21142127     * want network troubles to get in the way of a good peer. */
    2115     if( ( now - atom->piece_data_time ) <=
    2116        ( MINIMUM_RECONNECT_INTERVAL_SECS * 2 ) )
     2128    if( ( now - atom->piece_data_time ) <= ( MINIMUM_RECONNECT_INTERVAL_SECS * 2 ) )
    21172129        sec = MINIMUM_RECONNECT_INTERVAL_SECS;
    21182130
     
    21232135    /* otherwise, the interval depends on how many times we've tried
    21242136     * and failed to connect to the peer */
    2125     else switch( atom->numFails )
    2126         {
    2127             case 0:
    2128                 sec = 0; break;
    2129 
    2130             case 1:
    2131                 sec = 5; break;
    2132 
    2133             case 2:
    2134                 sec = 2 * 60; break;
    2135 
    2136             case 3:
    2137                 sec = 15 * 60; break;
    2138 
    2139             case 4:
    2140                 sec = 30 * 60; break;
    2141 
    2142             case 5:
    2143                 sec = 60 * 60; break;
    2144 
    2145             default:
    2146                 sec = 120 * 60; break;
    2147         }
     2137    else switch( atom->numFails ) {
     2138        case 0: sec = 0; break;
     2139        case 1: sec = 5; break;
     2140        case 2: sec = 2 * 60; break;
     2141        case 3: sec = 15 * 60; break;
     2142        case 4: sec = 30 * 60; break;
     2143        case 5: sec = 60 * 60; break;
     2144        default: sec = 120 * 60; break;
     2145    }
    21482146
    21492147    return sec;
     
    21512149
    21522150static struct peer_atom **
    2153 getPeerCandidates(                               Torrent * t,
    2154                                            int * setmeSize )
     2151getPeerCandidates( Torrent * t, int * setmeSize )
    21552152{
    21562153    int                 i, atomCount, retCount;
     
    21852182
    21862183        /* no need to connect if we're both seeds... */
    2187         if( seed && ( atom->flags & ADDED_F_SEED_FLAG ) )
     2184        if( seed && ( ( atom->flags & ADDED_F_SEED_FLAG ) ||
     2185                      ( atom->uploadOnly == UPLOAD_ONLY_YES ) ) )
    21882186            continue;
    21892187
     
    21922190        if( ( now - atom->time ) < interval )
    21932191        {
    2194             tordbg(
    2195                 t,
    2196                 "RECONNECT peer %d (%s) is in its grace period of %d seconds..",
    2197                 i, tr_peerIoAddrStr( &atom->addr,
    2198                                      atom->port ), interval );
     2192            tordbg( t, "RECONNECT peer %d (%s) is in its grace period of %d seconds..",
     2193                    i, tr_peerIoAddrStr( &atom->addr, atom->port ), interval );
    21992194            continue;
    22002195        }
     
    22352230    else
    22362231    {
    2237         int                 i, nCandidates, nBad;
     2232        int i, nCandidates, nBad;
    22382233        struct peer_atom ** candidates = getPeerCandidates( t, &nCandidates );
    2239         struct tr_peer **   connections = getPeersToClose( t, &nBad );
     2234        struct tr_peer ** connections = getPeersToClose( t, &nBad );
    22402235
    22412236        if( nBad || nCandidates )
    2242             tordbg(
    2243                 t, "reconnect pulse for [%s]: %d bad connections, "
    2244                    "%d connection candidates, %d atoms, max per pulse is %d",
    2245                 t->tor->info.name, nBad, nCandidates,
    2246                 tr_ptrArraySize( t->pool ),
    2247                 (int)MAX_RECONNECTIONS_PER_PULSE );
     2237            tordbg( t, "reconnect pulse for [%s]: %d bad connections, "
     2238                    "%d connection candidates, %d atoms, max per pulse is %d",
     2239                    t->tor->info.name, nBad, nCandidates,
     2240                    tr_ptrArraySize( t->pool ),
     2241                    (int)MAX_RECONNECTIONS_PER_PULSE );
    22482242
    22492243        /* disconnect some peers.
     
    22512245           so reset their `numFails' weight to zero.  otherwise we connected
    22522246           to them fruitlessly, so mark it as another fail */
    2253         for( i = 0; i < nBad; ++i )
    2254         {
    2255             tr_peer *          peer = connections[i];
    2256             struct peer_atom * atom = getExistingAtom( t, &peer->in_addr );
     2247        for( i = 0; i < nBad; ++i ) {
     2248            tr_peer * peer = connections[i];
     2249            struct peer_atom * atom = getExistingAtom( t, &peer->addr );
    22572250            if( atom->piece_data_time )
    22582251                atom->numFails = 0;
    22592252            else
    22602253                ++atom->numFails;
    2261             tordbg( t, "removing bad peer %s",
    2262                    tr_peerIoGetAddrStr( peer->io ) );
     2254            tordbg( t, "removing bad peer %s", tr_peerIoGetAddrStr( peer->io ) );
    22632255            removePeer( t, peer );
    22642256        }
     
    22682260           && ( i < MAX_RECONNECTIONS_PER_PULSE )
    22692261           && ( getPeerCount( t ) < getMaxPeerCount( t->tor ) )
    2270            && ( newConnectionsThisSecond < MAX_CONNECTIONS_PER_SECOND );
    2271              ++i )
     2262           && ( newConnectionsThisSecond < MAX_CONNECTIONS_PER_SECOND ); ++i )
    22722263        {
    22732264            tr_peerMgr *       mgr = t->manager;
     
    22782269                   tr_peerIoAddrStr( &atom->addr, atom->port ) );
    22792270
    2280             io =
    2281                 tr_peerIoNewOutgoing( mgr->session, &atom->addr, atom->port,
    2282                                       t->hash );
     2271            io = tr_peerIoNewOutgoing( mgr->session, &atom->addr, atom->port, t->hash );
    22832272            if( io == NULL )
    22842273            {
     
    22872276            else
    22882277            {
    2289                 tr_handshake * handshake = tr_handshakeNew(
    2290                     io,
    2291                     mgr->session->
    2292                     encryptionMode,
    2293                     myHandshakeDoneCB,
    2294                     mgr );
     2278                tr_handshake * handshake = tr_handshakeNew( io,
     2279                                                            mgr->session->encryptionMode,
     2280                                                            myHandshakeDoneCB,
     2281                                                            mgr );
    22952282
    22962283                assert( tr_peerIoGetTorrentHash( io ) );
     
    23402327bandwidthPulse( void * vmgr )
    23412328{
     2329    tr_handshake * handshake;
    23422330    tr_peerMgr * mgr = vmgr;
    23432331    managerLock( mgr );
    23442332
     2333    /* FIXME: this next line probably isn't necessary... */
    23452334    pumpAllPeers( mgr );
     2335
     2336    /* allocate bandwidth to the peers */
    23462337    tr_bandwidthAllocate( mgr->session->bandwidth, TR_UP, BANDWIDTH_PERIOD_MSEC );
    23472338    tr_bandwidthAllocate( mgr->session->bandwidth, TR_DOWN, BANDWIDTH_PERIOD_MSEC );
    2348     pumpAllPeers( mgr );
     2339
     2340    /* free all the finished handshakes */
     2341    while(( handshake = tr_ptrArrayPop( mgr->finishedHandshakes )))
     2342        tr_handshakeFree( handshake );
    23492343
    23502344    managerUnlock( mgr );
  • branches/1.4x/libtransmission/peer-mgr.h

    r7176 r7455  
    4343typedef struct tr_pex
    4444{
    45     struct in_addr in_addr;
     45    tr_address  addr;
    4646    uint16_t    port;
    4747    uint8_t     flags;
     
    5555void tr_peerMgrFree( tr_peerMgr * manager );
    5656
    57 int tr_peerMgrPeerIsSeed( const tr_peerMgr      * mgr,
    58                           const uint8_t         * torrentHash,
    59                           const struct in_addr  * addr );
     57tr_bool tr_peerMgrPeerIsSeed( const tr_peerMgr      * mgr,
     58                              const uint8_t         * torrentHash,
     59                              const struct in_addr  * addr );
    6060
    6161void tr_peerMgrAddIncoming( tr_peerMgr     * manager,
  • branches/1.4x/libtransmission/peer-msgs.c

    r7354 r7455  
    2525#include "crypto.h"
    2626#include "inout.h"
    27 #include "iobuf.h"
    2827#ifdef WIN32
    2928#include "net.h" /* for ECONN */
     
    5554    BT_CANCEL               = 8,
    5655    BT_PORT                 = 9,
    57     BT_SUGGEST              = 13,
    58     BT_HAVE_ALL             = 14,
    59     BT_HAVE_NONE            = 15,
    60     BT_REJECT               = 16,
    61     BT_ALLOWED_FAST         = 17,
     56
     57    BT_FEXT_SUGGEST         = 13,
     58    BT_FEXT_HAVE_ALL        = 14,
     59    BT_FEXT_HAVE_NONE       = 15,
     60    BT_FEXT_REJECT          = 16,
     61    BT_FEXT_ALLOWED_FAST    = 17,
     62
    6263    BT_LTEP                 = 20,
    6364
     
    6566
    6667    TR_LTEP_PEX             = 1,
     68
     69
    6770
    6871    MIN_CHOKE_PERIOD_SEC    = ( 10 ),
     
    7275
    7376    PEX_INTERVAL            = ( 90 * 1000 ), /* msec between sendPex() calls */
    74     PEER_PULSE_INTERVAL     = ( 250 ),       /* msec between peerPulse() calls
    75                                                */
    7677
    7778    MAX_QUEUE_SIZE          = ( 100 ),
    78 
    79     /* (fast peers) max number of pieces we fast-allow to another peer */
    80     MAX_FAST_ALLOWED_COUNT   = 10,
    81 
    82     /* (fast peers) max threshold for allowing fast-pieces requests */
    83     MAX_FAST_ALLOWED_THRESHOLD = 10,
    8479
    8580    /* how long an unsent request can stay queued before it's returned
     
    9893    /* number of pieces to remove from the bitfield when
    9994     * lazy bitfields are turned on */
    100     LAZY_PIECE_COUNT = 26
     95    LAZY_PIECE_COUNT = 26,
     96
     97    /* number of pieces we'll allow in our fast set */
     98    MAX_FAST_SET_SIZE = 3
    10199};
    102100
     
    122120
    123121static int
    124 compareRequest( const void * va,
    125                 const void * vb )
     122compareRequest( const void * va, const void * vb )
    126123{
    127124    const struct peer_request * a = va;
     
    170167
    171168static void
    172 reqListCopy( struct request_list *       dest,
    173              const struct request_list * src )
     169reqListCopy( struct request_list * dest, const struct request_list * src )
    174170{
    175171    dest->count = dest->max = src->count;
    176     dest->requests =
    177         tr_memdup( src->requests, dest->count * sizeof( struct peer_request ) );
     172    dest->requests = tr_memdup( src->requests, dest->count * sizeof( struct peer_request ) );
    178173}
    179174
     
    185180
    186181    memmove( &list->requests[i],
    187             &list->requests[i + 1],
    188             sizeof( struct peer_request ) * ( --list->count - i ) );
     182             &list->requests[i + 1],
     183             sizeof( struct peer_request ) * ( --list->count - i ) );
    189184}
    190185
     
    260255};
    261256
     257/**
     258 * Low-level communication state information about a connected peer.
     259 *
     260 * This structure remembers the low-level protocol states that we're
     261 * in with this peer, such as active requests, pex messages, and so on.
     262 * Its fields are all private to peer-msgs.c.
     263 *
     264 * Data not directly involved with sending & receiving messages is
     265 * stored in tr_peer, where it can be accessed by both peermsgs and
     266 * the peer manager.
     267 *
     268 * @see struct peer_atom
     269 * @see tr_peer
     270 */
    262271struct tr_peermsgs
    263272{
     
    266275    tr_bool         clientSentLtepHandshake;
    267276    tr_bool         peerSentLtepHandshake;
     277    tr_bool         haveFastSet;
    268278
    269279    uint8_t         state;
    270280    uint8_t         ut_pex_id;
    271281    uint16_t        pexCount;
    272     uint16_t        minActiveRequests;
    273282    uint16_t        maxActiveRequests;
     283
     284    size_t                 fastsetSize;
     285    tr_piece_index_t       fastset[MAX_FAST_SET_SIZE];
    274286
    275287    /* how long the outMessages batch should be allowed to grow before
     
    278290    int                    outMessagesBatchPeriod;
    279291
    280     tr_peer *              info;
     292    tr_peer *              peer;
    281293
    282294    tr_session *           session;
    283295    tr_torrent *           torrent;
    284     tr_peerIo *            io;
    285296
    286297    tr_publisher_t *       publisher;
     
    289300
    290301    struct request_list    peerAskedFor;
    291     struct request_list    peerAskedForFast;
    292302    struct request_list    clientAskedFor;
    293303    struct request_list    clientWillAskFor;
    294304
    295     tr_timer *             pexTimer;
     305    tr_timer             * pexTimer;
     306    tr_pex               * pex;
    296307
    297308    time_t                 clientSentPexAt;
     
    301312    time_t                outMessagesBatchedAt;
    302313
    303     tr_bitfield *         peerAllowedPieces;
    304 
    305314    struct tr_incoming    incoming;
    306 
    307     tr_pex *              pex;
    308315
    309316    /* if the peer supports the Extension Protocol in BEP 10 and
     
    318325
    319326static void
    320 myDebug( const char *               file,
    321          int                        line,
     327myDebug( const char * file, int line,
    322328         const struct tr_peermsgs * msgs,
    323          const char *               fmt,
    324          ... )
     329         const char * fmt, ... )
    325330{
    326331    FILE * fp = tr_getLog( );
     
    336341                             tr_getLogTimeStr( timestr, sizeof( timestr ) ),
    337342                             msgs->torrent->info.name,
    338                              tr_peerIoGetAddrStr( msgs->io ),
    339                              msgs->info->client );
     343                             tr_peerIoGetAddrStr( msgs->peer->io ),
     344                             msgs->peer->client );
    340345        va_start( args, fmt );
    341346        evbuffer_add_vprintf( buf, fmt, args );
     
    371376
    372377static void
    373 protocolSendRequest( tr_peermsgs *               msgs,
     378dbgOutMessageLen( tr_peermsgs * msgs )
     379{
     380    dbgmsg( msgs, "outMessage size is now %zu", EVBUFFER_LENGTH( msgs->outMessages ) );
     381}
     382
     383static void
     384protocolSendReject( tr_peermsgs * msgs, const struct peer_request * req )
     385{
     386    tr_peerIo       * io  = msgs->peer->io;
     387    struct evbuffer * out = msgs->outMessages;
     388
     389    assert( tr_peerIoSupportsFEXT( msgs->peer->io ) );
     390
     391    tr_peerIoWriteUint32( io, out, sizeof( uint8_t ) + 3 * sizeof( uint32_t ) );
     392    tr_peerIoWriteUint8 ( io, out, BT_FEXT_REJECT );
     393    tr_peerIoWriteUint32( io, out, req->index );
     394    tr_peerIoWriteUint32( io, out, req->offset );
     395    tr_peerIoWriteUint32( io, out, req->length );
     396
     397    dbgmsg( msgs, "rejecting %u:%u->%u...", req->index, req->offset, req->length );
     398    dbgOutMessageLen( msgs );
     399}
     400
     401static void
     402protocolSendRequest( tr_peermsgs               * msgs,
    374403                     const struct peer_request * req )
    375404{
    376     tr_peerIo *       io = msgs->io;
     405    tr_peerIo       * io  = msgs->peer->io;
    377406    struct evbuffer * out = msgs->outMessages;
    378407
     
    382411    tr_peerIoWriteUint32( io, out, req->offset );
    383412    tr_peerIoWriteUint32( io, out, req->length );
    384     dbgmsg( msgs, "requesting %u:%u->%u... outMessage size is now %d",
    385            req->index, req->offset, req->length, (int)EVBUFFER_LENGTH( out ) );
     413
     414    dbgmsg( msgs, "requesting %u:%u->%u...", req->index, req->offset, req->length );
     415    dbgOutMessageLen( msgs );
    386416    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
    387417}
    388418
    389419static void
    390 protocolSendCancel( tr_peermsgs *              msgs,
     420protocolSendCancel( tr_peermsgs               * msgs,
    391421                    const struct peer_request * req )
    392422{
    393     tr_peerIo *       io = msgs->io;
     423    tr_peerIo       * io  = msgs->peer->io;
    394424    struct evbuffer * out = msgs->outMessages;
    395425
     
    399429    tr_peerIoWriteUint32( io, out, req->offset );
    400430    tr_peerIoWriteUint32( io, out, req->length );
    401     dbgmsg( msgs, "cancelling %u:%u->%u... outMessage size is now %d",
    402            req->index, req->offset, req->length, (int)EVBUFFER_LENGTH( out ) );
     431
     432    dbgmsg( msgs, "cancelling %u:%u->%u...", req->index, req->offset, req->length );
     433    dbgOutMessageLen( msgs );
    403434    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
    404435}
     
    408439                  uint32_t      index )
    409440{
    410     tr_peerIo *       io = msgs->io;
     441    tr_peerIo       * io  = msgs->peer->io;
    411442    struct evbuffer * out = msgs->outMessages;
    412443
    413     tr_peerIoWriteUint32( io, out, sizeof( uint8_t ) + sizeof( uint32_t ) );
     444    tr_peerIoWriteUint32( io, out, sizeof(uint8_t) + sizeof(uint32_t) );
    414445    tr_peerIoWriteUint8 ( io, out, BT_HAVE );
    415446    tr_peerIoWriteUint32( io, out, index );
    416     dbgmsg( msgs, "sending Have %u.. outMessage size is now %d",
    417            index, (int)EVBUFFER_LENGTH( out ) );
     447
     448    dbgmsg( msgs, "sending Have %u", index );
     449    dbgOutMessageLen( msgs );
    418450    pokeBatchPeriod( msgs, LOW_PRIORITY_INTERVAL_SECS );
    419451}
     452
     453#if 0
     454static void
     455protocolSendAllowedFast( tr_peermsgs * msgs, uint32_t pieceIndex )
     456{
     457    tr_peerIo       * io  = msgs->peer->io;
     458    struct evbuffer * out = msgs->outMessages;
     459
     460    assert( tr_peerIoSupportsFEXT( msgs->peer->io ) );
     461
     462    tr_peerIoWriteUint32( io, out, sizeof(uint8_t) + sizeof(uint32_t) );
     463    tr_peerIoWriteUint8 ( io, out, BT_FEXT_ALLOWED_FAST );
     464    tr_peerIoWriteUint32( io, out, pieceIndex );
     465
     466    dbgmsg( msgs, "sending Allowed Fast %u...", pieceIndex );
     467    dbgOutMessageLen( msgs );
     468}
     469#endif
    420470
    421471static void
     
    423473                   int           choke )
    424474{
    425     tr_peerIo *       io = msgs->io;
     475    tr_peerIo       * io  = msgs->peer->io;
    426476    struct evbuffer * out = msgs->outMessages;
    427477
    428478    tr_peerIoWriteUint32( io, out, sizeof( uint8_t ) );
    429479    tr_peerIoWriteUint8 ( io, out, choke ? BT_CHOKE : BT_UNCHOKE );
    430     dbgmsg( msgs, "sending %s... outMessage size is now %d",
    431            ( choke ? "Choke" : "Unchoke" ),
    432            (int)EVBUFFER_LENGTH( out ) );
     480
     481    dbgmsg( msgs, "sending %s...", choke ? "Choke" : "Unchoke" );
     482    dbgOutMessageLen( msgs );
     483    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
     484}
     485
     486static void
     487protocolSendHaveAll( tr_peermsgs * msgs )
     488{
     489    tr_peerIo       * io  = msgs->peer->io;
     490    struct evbuffer * out = msgs->outMessages;
     491
     492    assert( tr_peerIoSupportsFEXT( msgs->peer->io ) );
     493
     494    tr_peerIoWriteUint32( io, out, sizeof( uint8_t ) );
     495    tr_peerIoWriteUint8 ( io, out, BT_FEXT_HAVE_ALL );
     496
     497    dbgmsg( msgs, "sending HAVE_ALL..." );
     498    dbgOutMessageLen( msgs );
     499    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
     500}
     501
     502static void
     503protocolSendHaveNone( tr_peermsgs * msgs )
     504{
     505    tr_peerIo       * io  = msgs->peer->io;
     506    struct evbuffer * out = msgs->outMessages;
     507
     508    assert( tr_peerIoSupportsFEXT( msgs->peer->io ) );
     509
     510    tr_peerIoWriteUint32( io, out, sizeof( uint8_t ) );
     511    tr_peerIoWriteUint8 ( io, out, BT_FEXT_HAVE_NONE );
     512
     513    dbgmsg( msgs, "sending HAVE_NONE..." );
     514    dbgOutMessageLen( msgs );
    433515    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
    434516}
     
    438520**/
    439521
    440 static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0 };
    441 
    442 static void
    443 publish( tr_peermsgs *   msgs,
    444          tr_peer_event * e )
    445 {
    446     tr_publisherPublish( msgs->publisher, msgs->info, e );
    447 }
    448 
    449 static void
    450 fireError( tr_peermsgs * msgs,
    451            int           err )
     522static const tr_peer_event blankEvent = { 0, 0, 0, 0, 0.0f, 0, 0, 0 };
     523
     524static void
     525publish( tr_peermsgs * msgs, tr_peer_event * e )
     526{
     527    assert( msgs->peer );
     528    assert( msgs->peer->msgs == msgs );
     529
     530    tr_publisherPublish( msgs->publisher, msgs->peer, e );
     531}
     532
     533static void
     534fireError( tr_peermsgs * msgs, int err )
    452535{
    453536    tr_peer_event e = blankEvent;
    454 
    455537    e.eventType = TR_PEER_ERROR;
    456538    e.err = err;
     
    459541
    460542static void
     543fireUploadOnly( tr_peermsgs * msgs, tr_bool uploadOnly )
     544{
     545    tr_peer_event e = blankEvent;
     546    e.eventType = TR_PEER_UPLOAD_ONLY;
     547    e.uploadOnly = uploadOnly;
     548    publish( msgs, &e );
     549}
     550
     551static void
    461552fireNeedReq( tr_peermsgs * msgs )
    462553{
    463554    tr_peer_event e = blankEvent;
    464 
    465555    e.eventType = TR_PEER_NEED_REQ;
    466556    publish( msgs, &e );
     
    471561{
    472562    tr_peer_event e = blankEvent;
    473 
    474563    e.eventType = TR_PEER_PEER_PROGRESS;
    475     e.progress = msgs->info->progress;
     564    e.progress = msgs->peer->progress;
    476565    publish( msgs, &e );
    477566}
    478567
    479568static void
    480 fireGotBlock( tr_peermsgs *               msgs,
    481               const struct peer_request * req )
     569fireGotBlock( tr_peermsgs * msgs, const struct peer_request * req )
    482570{
    483571    tr_peer_event e = blankEvent;
    484 
    485572    e.eventType = TR_PEER_CLIENT_GOT_BLOCK;
    486573    e.pieceIndex = req->index;
     
    500587    e.eventType = TR_PEER_CLIENT_GOT_DATA;
    501588    e.wasPieceData = wasPieceData;
     589    publish( msgs, &e );
     590}
     591
     592static void
     593fireClientGotSuggest( tr_peermsgs * msgs, uint32_t pieceIndex )
     594{
     595    tr_peer_event e = blankEvent;
     596    e.eventType = TR_PEER_CLIENT_GOT_SUGGEST;
     597    e.pieceIndex = pieceIndex;
     598    publish( msgs, &e );
     599}
     600
     601static void
     602fireClientGotAllowedFast( tr_peermsgs * msgs, uint32_t pieceIndex )
     603{
     604    tr_peer_event e = blankEvent;
     605    e.eventType = TR_PEER_CLIENT_GOT_ALLOWED_FAST;
     606    e.pieceIndex = pieceIndex;
    502607    publish( msgs, &e );
    503608}
     
    529634
    530635/**
     636***  ALLOWED FAST SET
     637***  For explanation, see http://www.bittorrent.org/beps/bep_0006.html
     638**/
     639
     640size_t
     641tr_generateAllowedSet( tr_piece_index_t * setmePieces,
     642                       size_t             desiredSetSize,
     643                       size_t             pieceCount,
     644                       const uint8_t    * infohash,
     645                       const tr_address * addr )
     646{
     647    size_t setSize = 0;
     648
     649    assert( setmePieces );
     650    assert( desiredSetSize <= pieceCount );
     651    assert( desiredSetSize );
     652    assert( pieceCount );
     653    assert( infohash );
     654    assert( addr );
     655
     656    if( 1 )
     657    {
     658        uint8_t w[SHA_DIGEST_LENGTH + 4];
     659        uint8_t x[SHA_DIGEST_LENGTH];
     660
     661        *(uint32_t*)w = ntohl( htonl( addr->s_addr ) & 0xffffff00 ); /* (1) */
     662        memcpy( w + 4, infohash, SHA_DIGEST_LENGTH );                /* (2) */
     663        tr_sha1( x, w, sizeof( w ), NULL );                          /* (3) */
     664
     665        while( setSize<desiredSetSize )
     666        {
     667            int i;
     668            for( i=0; i<5 && setSize<desiredSetSize; ++i )           /* (4) */
     669            {
     670                size_t k;
     671                uint32_t j = i * 4;                                  /* (5) */
     672                uint32_t y = ntohl( *( uint32_t* )( x + j ) );       /* (6) */
     673                uint32_t index = y % pieceCount;                     /* (7) */
     674
     675                for( k=0; k<setSize; ++k )                           /* (8) */
     676                    if( setmePieces[k] == index )
     677                        break;
     678
     679                if( k == setSize )
     680                    setmePieces[setSize++] = index;                  /* (9) */
     681            }
     682
     683            tr_sha1( x, x, sizeof( x ), NULL );                      /* (3) */
     684        }
     685    }
     686
     687    return setSize;
     688}
     689
     690static void
     691updateFastSet( tr_peermsgs * msgs UNUSED )
     692{
     693#if 0
     694    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
     695    const int peerIsNeedy = msgs->peer->progress < 0.10;
     696
     697    if( fext && peerIsNeedy && !msgs->haveFastSet )
     698    {
     699        size_t i;
     700        const struct tr_address * addr = tr_peerIoGetAddress( msgs->peer->io, NULL );
     701        const tr_info * inf = &msgs->torrent->info;
     702        const size_t numwant = MIN( MAX_FAST_SET_SIZE, inf->pieceCount );
     703
     704        /* build the fast set */
     705        msgs->fastsetSize = tr_generateAllowedSet( msgs->fastset, numwant, inf->pieceCount, inf->hash, addr );
     706        msgs->haveFastSet = 1;
     707
     708        /* send it to the peer */
     709        for( i=0; i<msgs->fastsetSize; ++i )
     710            protocolSendAllowedFast( msgs, msgs->fastset[i] );
     711    }
     712#endif
     713}
     714
     715/**
    531716***  INTEREST
    532717**/
    533718
    534719static int
    535 isPieceInteresting( const tr_peermsgs * peer,
     720isPieceInteresting( const tr_peermsgs * msgs,
    536721                    tr_piece_index_t    piece )
    537722{
    538     const tr_torrent * torrent = peer->torrent;
     723    const tr_torrent * torrent = msgs->torrent;
    539724
    540725    return ( !torrent->info.pieces[piece].dnd )                 /* we want it */
    541            && ( !tr_cpPieceIsComplete( torrent->completion, piece ) ) /* !have
    542                                                                         */
    543            && ( tr_bitfieldHas( peer->info->have, piece ) );   /* peer has it */
     726          && ( !tr_cpPieceIsComplete( torrent->completion, piece ) ) /* !have */
     727          && ( tr_bitfieldHas( msgs->peer->have, piece ) );    /* peer has it */
    544728}
    545729
     
    562746    bitfield = tr_cpPieceBitfield( torrent->completion );
    563747
    564     if( !msgs->info->have )
     748    if( !msgs->peer->have )
    565749        return TRUE;
    566750
    567     assert( bitfield->byteCount == msgs->info->have->byteCount );
     751    assert( bitfield->byteCount == msgs->peer->have->byteCount );
    568752
    569753    for( i = 0; i < torrent->info.pieceCount; ++i )
     
    583767    assert( weAreInterested == 0 || weAreInterested == 1 );
    584768
    585     msgs->info->clientIsInterested = weAreInterested;
    586     dbgmsg( msgs, "Sending %s",
    587             weAreInterested ? "Interested" : "Not Interested" );
    588     tr_peerIoWriteUint32( msgs->io, out, sizeof( uint8_t ) );
    589     tr_peerIoWriteUint8 (
    590         msgs->io, out, weAreInterested ? BT_INTERESTED : BT_NOT_INTERESTED );
     769    msgs->peer->clientIsInterested = weAreInterested;
     770    dbgmsg( msgs, "Sending %s", weAreInterested ? "Interested" : "Not Interested" );
     771    tr_peerIoWriteUint32( msgs->peer->io, out, sizeof( uint8_t ) );
     772    tr_peerIoWriteUint8 ( msgs->peer->io, out, weAreInterested ? BT_INTERESTED : BT_NOT_INTERESTED );
     773
    591774    pokeBatchPeriod( msgs, HIGH_PRIORITY_INTERVAL_SECS );
    592     dbgmsg( msgs, "outMessage size is now %d", (int)EVBUFFER_LENGTH( out ) );
     775    dbgOutMessageLen( msgs );
    593776}
    594777
     
    598781    const int i = isPeerInteresting( msgs );
    599782
    600     if( i != msgs->info->clientIsInterested )
     783    if( i != msgs->peer->clientIsInterested )
    601784        sendInterest( msgs, i );
    602785    if( i )
     
    604787}
    605788
    606 static void
    607 cancelAllRequestsToClientExceptFast( tr_peermsgs * msgs )
    608 {
    609     reqListClear( &msgs->peerAskedFor );
     789static int
     790popNextRequest( tr_peermsgs *         msgs,
     791                struct peer_request * setme )
     792{
     793    return reqListPop( &msgs->peerAskedFor, setme );
     794}
     795
     796static void
     797cancelAllRequestsToClient( tr_peermsgs * msgs )
     798{
     799    struct peer_request req;
     800    const int mustSendCancel = tr_peerIoSupportsFEXT( msgs->peer->io );
     801
     802    while( popNextRequest( msgs, &req ) )
     803        if( mustSendCancel )
     804            protocolSendReject( msgs, &req );
    610805}
    611806
     
    618813
    619814    assert( msgs );
    620     assert( msgs->info );
     815    assert( msgs->peer );
    621816    assert( choke == 0 || choke == 1 );
    622817
    623     if( msgs->info->chokeChangedAt > fibrillationTime )
    624     {
    625         dbgmsg( msgs, "Not changing choke to %d to avoid fibrillation",
    626                 choke );
    627     }
    628     else if( msgs->info->peerIsChoked != choke )
    629     {
    630         msgs->info->peerIsChoked = choke;
     818    if( msgs->peer->chokeChangedAt > fibrillationTime )
     819    {
     820        dbgmsg( msgs, "Not changing choke to %d to avoid fibrillation", choke );
     821    }
     822    else if( msgs->peer->peerIsChoked != choke )
     823    {
     824        msgs->peer->peerIsChoked = choke;
    631825        if( choke )
    632             cancelAllRequestsToClientExceptFast( msgs );
     826            cancelAllRequestsToClient( msgs );
    633827        protocolSendChoke( msgs, choke );
    634         msgs->info->chokeChangedAt = now;
     828        msgs->peer->chokeChangedAt = now;
    635829    }
    636830}
     
    648842    /* since we have more pieces now, we might not be interested in this peer */
    649843    updateInterest( msgs );
    650 }
    651 
    652 #if 0
    653 static void
    654 sendFastSuggest( tr_peermsgs * msgs,
    655                  uint32_t      pieceIndex )
    656 {
    657     assert( msgs );
    658 
    659     if( tr_peerIoSupportsFEXT( msgs->io ) )
    660     {
    661         tr_peerIoWriteUint32( msgs->io, msgs->outMessages,
    662                              sizeof( uint8_t ) + sizeof( uint32_t ) );
    663         tr_peerIoWriteUint8( msgs->io, msgs->outMessages, BT_SUGGEST );
    664         tr_peerIoWriteUint32( msgs->io, msgs->outMessages, pieceIndex );
    665     }
    666 }
    667 
    668 static void
    669 sendFastHave( tr_peermsgs * msgs,
    670               int           all )
    671 {
    672     assert( msgs );
    673 
    674     if( tr_peerIoSupportsFEXT( msgs->io ) )
    675     {
    676         tr_peerIoWriteUint32( msgs->io, msgs->outMessages, sizeof( uint8_t ) );
    677         tr_peerIoWriteUint8( msgs->io, msgs->outMessages,
    678                             ( all ? BT_HAVE_ALL
    679                               : BT_HAVE_NONE ) );
    680         updateInterest( msgs );
    681     }
    682 }
    683 
    684 #endif
    685 
    686 static void
    687 sendFastReject( tr_peermsgs * msgs,
    688                 uint32_t      pieceIndex,
    689                 uint32_t      offset,
    690                 uint32_t      length )
    691 {
    692     assert( msgs );
    693 
    694     if( tr_peerIoSupportsFEXT( msgs->io ) )
    695     {
    696         struct evbuffer * out = msgs->outMessages;
    697         const uint32_t    len = sizeof( uint8_t ) + 3 * sizeof( uint32_t );
    698         dbgmsg( msgs, "sending fast reject %u:%u->%u", pieceIndex, offset,
    699                 length );
    700         tr_peerIoWriteUint32( msgs->io, out, len );
    701         tr_peerIoWriteUint8( msgs->io, out, BT_REJECT );
    702         tr_peerIoWriteUint32( msgs->io, out, pieceIndex );
    703         tr_peerIoWriteUint32( msgs->io, out, offset );
    704         tr_peerIoWriteUint32( msgs->io, out, length );
    705         pokeBatchPeriod( msgs, LOW_PRIORITY_INTERVAL_SECS );
    706         dbgmsg( msgs, "outMessage size is now %d",
    707                (int)EVBUFFER_LENGTH( out ) );
    708     }
    709 }
    710 
    711 static tr_bitfield*
    712 getPeerAllowedPieces( tr_peermsgs * msgs )
    713 {
    714     if( !msgs->peerAllowedPieces && tr_peerIoSupportsFEXT( msgs->io ) )
    715     {
    716         msgs->peerAllowedPieces = tr_peerMgrGenerateAllowedSet(
    717             MAX_FAST_ALLOWED_COUNT,
    718             msgs->torrent->info.pieceCount,
    719             msgs->torrent->info.hash,
    720             tr_peerIoGetAddress( msgs->io, NULL ) );
    721     }
    722 
    723     return msgs->peerAllowedPieces;
    724 }
    725 
    726 static void
    727 sendFastAllowed( tr_peermsgs * msgs,
    728                  uint32_t      pieceIndex )
    729 {
    730     assert( msgs );
    731 
    732     if( tr_peerIoSupportsFEXT( msgs->io ) )
    733     {
    734         struct evbuffer * out = msgs->outMessages;
    735         dbgmsg( msgs, "sending fast allowed" );
    736         tr_peerIoWriteUint32( msgs->io, out,  sizeof( uint8_t ) +
    737                              sizeof( uint32_t ) );
    738         tr_peerIoWriteUint8( msgs->io, out, BT_ALLOWED_FAST );
    739         tr_peerIoWriteUint32( msgs->io, out, pieceIndex );
    740         pokeBatchPeriod( msgs, LOW_PRIORITY_INTERVAL_SECS );
    741         dbgmsg( msgs, "outMessage size is now %d",
    742                (int)EVBUFFER_LENGTH( out ) );
    743     }
    744 }
    745 
    746 static void
    747 sendFastAllowedSet( tr_peermsgs * msgs )
    748 {
    749     tr_piece_index_t i = 0;
    750 
    751     while( i <= msgs->torrent->info.pieceCount )
    752     {
    753         if( tr_bitfieldHas( getPeerAllowedPieces( msgs ), i ) )
    754             sendFastAllowed( msgs, i );
    755         i++;
    756     }
    757 }
    758 
    759 static void
    760 maybeSendFastAllowedSet( tr_peermsgs * msgs )
    761 {
    762     if( tr_bitfieldCountTrueBits( msgs->info->have ) <=
    763         MAX_FAST_ALLOWED_THRESHOLD )
    764         sendFastAllowedSet( msgs );
    765844}
    766845
     
    787866expireOldRequests( tr_peermsgs * msgs, const time_t now  )
    788867{
    789     int                 i;
    790     time_t              oldestAllowed;
     868    int i;
     869    time_t oldestAllowed;
    791870    struct request_list tmp = REQUEST_LIST_INIT;
     871    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
     872    dbgmsg( msgs, "entering `expire old requests' block" );
    792873
    793874    /* cancel requests that have been queued for too long */
    794875    oldestAllowed = now - QUEUED_REQUEST_TTL_SECS;
    795876    reqListCopy( &tmp, &msgs->clientWillAskFor );
    796     for( i = 0; i < tmp.count; ++i )
    797     {
     877    for( i=0; i<tmp.count; ++i ) {
    798878        const struct peer_request * req = &tmp.requests[i];
    799879        if( req->time_requested < oldestAllowed )
     
    802882    reqListClear( &tmp );
    803883
    804     /* cancel requests that were sent too long ago */
    805     oldestAllowed = now - SENT_REQUEST_TTL_SECS;
    806     reqListCopy( &tmp, &msgs->clientAskedFor );
    807     for( i = 0; i < tmp.count; ++i )
    808     {
    809         const struct peer_request * req = &tmp.requests[i];
    810         if( req->time_requested < oldestAllowed )
    811             tr_peerMsgsCancel( msgs, req->index, req->offset, req->length );
    812     }
    813     reqListClear( &tmp );
     884    /* if the peer doesn't support "Reject Request",
     885     * cancel requests that were sent too long ago. */
     886    if( !fext ) {
     887        oldestAllowed = now - SENT_REQUEST_TTL_SECS;
     888        reqListCopy( &tmp, &msgs->clientAskedFor );
     889        for( i=0; i<tmp.count; ++i ) {
     890            const struct peer_request * req = &tmp.requests[i];
     891            if( req->time_requested < oldestAllowed )
     892                tr_peerMsgsCancel( msgs, req->index, req->offset, req->length );
     893        }
     894        reqListClear( &tmp );
     895    }
     896
     897    dbgmsg( msgs, "leaving `expire old requests' block" );
    814898}
    815899
     
    818902{
    819903    const int           max = msgs->maxActiveRequests;
    820     const int           min = msgs->minActiveRequests;
    821904    int                 sent = 0;
    822905    int                 count = msgs->clientAskedFor.count;
    823906    struct peer_request req;
    824907
    825     if( count > min )
    826         return;
    827     if( msgs->info->clientIsChoked )
     908    if( msgs->peer->clientIsChoked )
    828909        return;
    829910    if( !tr_torrentIsPieceTransferAllowed( msgs->torrent, TR_PEER_TO_CLIENT ) )
     
    832913    while( ( count < max ) && reqListPop( &msgs->clientWillAskFor, &req ) )
    833914    {
    834         const tr_block_index_t block =
    835             _tr_block( msgs->torrent, req.index, req.offset );
     915        const tr_block_index_t block = _tr_block( msgs->torrent, req.index, req.offset );
    836916
    837917        assert( requestIsValid( msgs, &req ) );
    838         assert( tr_bitfieldHas( msgs->info->have, req.index ) );
     918        assert( tr_bitfieldHas( msgs->peer->have, req.index ) );
    839919
    840920        /* don't ask for it if we've already got it... this block may have
     
    852932
    853933    if( sent )
    854         dbgmsg( msgs,
    855                 "pump sent %d requests, now have %d active and %d queued",
    856                 sent,
    857                 msgs->clientAskedFor.count,
    858                 msgs->clientWillAskFor.count );
     934        dbgmsg( msgs, "pump sent %d requests, now have %d active and %d queued",
     935                sent, msgs->clientAskedFor.count, msgs->clientWillAskFor.count );
    859936
    860937    if( count < max )
     
    886963
    887964    /* don't send requests to choked clients */
    888     if( msgs->info->clientIsChoked )
    889     {
     965    if( msgs->peer->clientIsChoked ) {
    890966        dbgmsg( msgs, "declining request because they're choking us" );
    891967        return TR_ADDREQ_CLIENT_CHOKED;
     
    893969
    894970    /* peer doesn't have this piece */
    895     if( !tr_bitfieldHas( msgs->info->have, index ) )
     971    if( !tr_bitfieldHas( msgs->peer->have, index ) )
    896972        return TR_ADDREQ_MISSING;
    897973
     
    9291005cancelAllRequestsToPeer( tr_peermsgs * msgs, tr_bool sendCancel )
    9301006{
    931     int                 i;
     1007    int i;
    9321008    struct request_list a = msgs->clientWillAskFor;
    9331009    struct request_list b = msgs->clientAskedFor;
     
    9691045    /* if it's only in the queue and hasn't been sent yet, free it */
    9701046    if( reqListRemove( &msgs->clientWillAskFor, &req ) ) {
    971         dbgmsg( msgs, "cancelling %"PRIu32":%"PRIu32"->%"PRIu32"\n", pieceIndex, offset, length );
     1047        dbgmsg( msgs, "cancelling %"PRIu32":%"PRIu32"->%"PRIu32, pieceIndex, offset, length );
    9721048        fireCancelledReq( msgs, &req );
    9731049    }
     
    9751051    /* if it's already been sent, send a cancel message too */
    9761052    if( reqListRemove( &msgs->clientAskedFor, &req ) ) {
    977         dbgmsg( msgs, "cancelling %"PRIu32":%"PRIu32"->%"PRIu32"\n", pieceIndex, offset, length );
     1053        dbgmsg( msgs, "cancelling %"PRIu32":%"PRIu32"->%"PRIu32, pieceIndex, offset, length );
    9781054        protocolSendCancel( msgs, &req );
    9791055        fireCancelledReq( msgs, &req );
    9801056    }
    9811057}
     1058
    9821059
    9831060/**
     
    9881065sendLtepHandshake( tr_peermsgs * msgs )
    9891066{
    990     tr_benc           val, *m;
    991     char *            buf;
    992     int               len;
    993     int               pex;
     1067    tr_benc val, *m;
     1068    char * buf;
     1069    int len;
     1070    int pex;
    9941071    struct evbuffer * out = msgs->outMessages;
    9951072
     
    10081085        pex = 1;
    10091086
    1010     tr_bencInitDict( &val, 4 );
    1011     tr_bencDictAddInt( &val, "e",
    1012                        msgs->session->encryptionMode != TR_CLEAR_PREFERRED );
     1087    tr_bencInitDict( &val, 5 );
     1088    tr_bencDictAddInt( &val, "e", msgs->session->encryptionMode != TR_CLEAR_PREFERRED );
    10131089    tr_bencDictAddInt( &val, "p", tr_sessionGetPeerPort( msgs->session ) );
     1090    tr_bencDictAddInt( &val, "upload_only", tr_torrentIsSeed( msgs->torrent ) );
    10141091    tr_bencDictAddStr( &val, "v", TR_NAME " " USERAGENT_PREFIX );
    10151092    m  = tr_bencDictAddDict( &val, "m", 1 );
     
    10181095    buf = tr_bencSave( &val, &len );
    10191096
    1020     tr_peerIoWriteUint32( msgs->io, out, 2 * sizeof( uint8_t ) + len );
    1021     tr_peerIoWriteUint8 ( msgs->io, out, BT_LTEP );
    1022     tr_peerIoWriteUint8 ( msgs->io, out, LTEP_HANDSHAKE );
    1023     tr_peerIoWriteBytes ( msgs->io, out, buf, len );
     1097    tr_peerIoWriteUint32( msgs->peer->io, out, 2 * sizeof( uint8_t ) + len );
     1098    tr_peerIoWriteUint8 ( msgs->peer->io, out, BT_LTEP );
     1099    tr_peerIoWriteUint8 ( msgs->peer->io, out, LTEP_HANDSHAKE );
     1100    tr_peerIoWriteBytes ( msgs->peer->io, out, buf, len );
    10241101    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
    1025     dbgmsg( msgs, "outMessage size is now %d", (int)EVBUFFER_LENGTH( out ) );
     1102    dbgOutMessageLen( msgs );
    10261103
    10271104    /* cleanup */
     
    10391116    uint8_t * tmp = tr_new( uint8_t, len );
    10401117
    1041     tr_peerIoReadBytes( msgs->io, inbuf, tmp, len );
     1118    tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp, len );
    10421119    msgs->peerSentLtepHandshake = 1;
    10431120
    1044     if( tr_bencLoad( tmp, len, &val, NULL ) || val.type != TYPE_DICT )
     1121    if( tr_bencLoad( tmp, len, &val, NULL ) || !tr_bencIsDict( &val ) )
    10451122    {
    10461123        dbgmsg( msgs, "GET  extended-handshake, couldn't get dictionary" );
     
    10531130    /* does the peer prefer encrypted connections? */
    10541131    if( tr_bencDictFindInt( &val, "e", &i ) )
    1055         msgs->info->encryption_preference = i ? ENCRYPTION_PREFERENCE_YES
    1056                                             : ENCRYPTION_PREFERENCE_NO;
     1132        msgs->peer->encryption_preference = i ? ENCRYPTION_PREFERENCE_YES
     1133                                              : ENCRYPTION_PREFERENCE_NO;
    10571134
    10581135    /* check supported messages for utorrent pex */
    10591136    msgs->peerSupportsPex = 0;
    1060     if( tr_bencDictFindDict( &val, "m", &sub ) )
    1061     {
    1062         if( tr_bencDictFindInt( sub, "ut_pex", &i ) )
    1063         {
     1137    if( tr_bencDictFindDict( &val, "m", &sub ) ) {
     1138        if( tr_bencDictFindInt( sub, "ut_pex", &i ) ) {
    10641139            msgs->ut_pex_id = (uint8_t) i;
    10651140            msgs->peerSupportsPex = msgs->ut_pex_id == 0 ? 0 : 1;
     
    10681143    }
    10691144
     1145    /* look for upload_only (BEP 21) */
     1146    if( tr_bencDictFindInt( &val, "upload_only", &i ) )
     1147        fireUploadOnly( msgs, i!=0 );
     1148
    10701149    /* get peer's listening port */
    1071     if( tr_bencDictFindInt( &val, "p", &i ) )
    1072     {
    1073         msgs->info->port = htons( (uint16_t)i );
    1074         dbgmsg( msgs, "msgs->port is now %hu", msgs->info->port );
     1150    if( tr_bencDictFindInt( &val, "p", &i ) ) {
     1151        msgs->peer->port = htons( (uint16_t)i );
     1152        dbgmsg( msgs, "msgs->port is now %hu", msgs->peer->port );
    10751153    }
    10761154
     
    10841162
    10851163static void
    1086 parseUtPex( tr_peermsgs *     msgs,
    1087             int               msglen,
    1088             struct evbuffer * inbuf )
    1089 {
    1090     int                loaded = 0;
    1091     uint8_t *          tmp = tr_new( uint8_t, msglen );
    1092     tr_benc            val;
     1164parseUtPex( tr_peermsgs * msgs, int msglen, struct evbuffer * inbuf )
     1165{
     1166    int loaded = 0;
     1167    uint8_t * tmp = tr_new( uint8_t, msglen );
     1168    tr_benc val;
    10931169    const tr_torrent * tor = msgs->torrent;
    1094     const uint8_t *    added;
    1095     size_t             added_len;
    1096 
    1097     tr_peerIoReadBytes( msgs->io, inbuf, tmp, msglen );
     1170    const uint8_t * added;
     1171    size_t added_len;
     1172
     1173    tr_peerIoReadBytes( msgs->peer->io, inbuf, tmp, msglen );
    10981174
    10991175    if( tr_torrentAllowsPex( tor )
     
    11291205    uint8_t ltep_msgid;
    11301206
    1131     tr_peerIoReadUint8( msgs->io, inbuf, &ltep_msgid );
     1207    tr_peerIoReadUint8( msgs->peer->io, inbuf, &ltep_msgid );
    11321208    msglen--;
    11331209
     
    11361212        dbgmsg( msgs, "got ltep handshake" );
    11371213        parseLtepHandshake( msgs, msglen, inbuf );
    1138         if( tr_peerIoSupportsLTEP( msgs->io ) )
     1214        if( tr_peerIoSupportsLTEP( msgs->peer->io ) )
    11391215        {
    11401216            sendLtepHandshake( msgs );
     
    11651241        return READ_LATER;
    11661242
    1167     tr_peerIoReadUint32( msgs->io, inbuf, &len );
     1243    tr_peerIoReadUint32( msgs->peer->io, inbuf, &len );
    11681244
    11691245    if( len == 0 ) /* peer sent us a keepalive message */
     
    11921268        return READ_LATER;
    11931269
    1194     tr_peerIoReadUint8( msgs->io, inbuf, &id );
     1270    tr_peerIoReadUint8( msgs->peer->io, inbuf, &id );
    11951271    msgs->incoming.id = id;
    11961272
     
    12111287updatePeerProgress( tr_peermsgs * msgs )
    12121288{
    1213     msgs->info->progress = tr_bitfieldCountTrueBits( msgs->info->have )
    1214                            / (float)msgs->torrent->info.pieceCount;
    1215     dbgmsg( msgs, "peer progress is %f", msgs->info->progress );
     1289    msgs->peer->progress = tr_bitfieldCountTrueBits( msgs->peer->have ) / (float)msgs->torrent->info.pieceCount;
     1290    dbgmsg( msgs, "peer progress is %f", msgs->peer->progress );
     1291    updateFastSet( msgs );
    12161292    updateInterest( msgs );
    12171293    firePeerProgress( msgs );
    12181294}
    12191295
    1220 static int
    1221 clientCanSendFastBlock( const tr_peermsgs * msgs UNUSED )
    1222 {
    1223     /* don't send a fast piece if peer has MAX_FAST_ALLOWED_THRESHOLD pieces */
    1224     if( tr_bitfieldCountTrueBits( msgs->info->have ) >
    1225         MAX_FAST_ALLOWED_THRESHOLD )
    1226         return FALSE;
    1227 
    1228     /* ...or if we don't have ourself enough pieces */
    1229     if( tr_bitfieldCountTrueBits( tr_cpPieceBitfield( msgs->torrent->
    1230                                                       completion ) ) <
    1231         MAX_FAST_ALLOWED_THRESHOLD )
    1232         return FALSE;
    1233 
    1234     /* Maybe a bandwidth limit ? */
    1235     return TRUE;
    1236 }
    1237 
    12381296static void
    12391297peerMadeRequest( tr_peermsgs *               msgs,
    12401298                 const struct peer_request * req )
    12411299{
     1300    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
    12421301    const int reqIsValid = requestIsValid( msgs, req );
    1243     const int clientHasPiece = reqIsValid && tr_cpPieceIsComplete(
    1244         msgs->torrent->completion, req->index );
    1245     const int peerIsChoked = msgs->info->peerIsChoked;
    1246     const int peerIsFast = tr_peerIoSupportsFEXT( msgs->io );
    1247     const int pieceIsFast = reqIsValid && tr_bitfieldHas(
    1248         getPeerAllowedPieces( msgs ), req->index );
    1249     const int canSendFast = clientCanSendFastBlock( msgs );
    1250 
    1251     if( !reqIsValid ) /* bad request */
    1252     {
     1302    const int clientHasPiece = reqIsValid && tr_cpPieceIsComplete( msgs->torrent->completion, req->index );
     1303    const int peerIsChoked = msgs->peer->peerIsChoked;
     1304
     1305    int allow = FALSE;
     1306
     1307    if( !reqIsValid )
    12531308        dbgmsg( msgs, "rejecting an invalid request." );
    1254         sendFastReject( msgs, req->index, req->offset, req->length );
    1255     }
    1256     else if( !clientHasPiece ) /* we don't have it */
    1257     {
     1309    else if( !clientHasPiece )
    12581310        dbgmsg( msgs, "rejecting request for a piece we don't have." );
    1259         sendFastReject( msgs, req->index, req->offset, req->length );
    1260     }
    1261     else if( peerIsChoked && !peerIsFast ) /* doesn't he know he's choked? */
    1262     {
    1263         tr_peerMsgsSetChoke( msgs, 1 );
    1264         sendFastReject( msgs, req->index, req->offset, req->length );
    1265     }
    1266     else if( peerIsChoked && peerIsFast && ( !pieceIsFast || !canSendFast ) )
    1267     {
    1268         sendFastReject( msgs, req->index, req->offset, req->length );
    1269     }
    1270     else /* YAY */
    1271     {
    1272         if( peerIsFast && pieceIsFast )
    1273             reqListAppend( &msgs->peerAskedForFast, req );
    1274         else
    1275             reqListAppend( &msgs->peerAskedFor, req );
    1276     }
     1311    else if( peerIsChoked )
     1312        dbgmsg( msgs, "rejecting request from choked peer" );
     1313    else
     1314        allow = TRUE;
     1315
     1316    if( allow )
     1317        reqListAppend( &msgs->peerAskedFor, req );
     1318    else if( fext )
     1319        protocolSendReject( msgs, req );
    12771320}
    12781321
    12791322static int
    1280 messageLengthIsCorrect( const tr_peermsgs * msg,
    1281                         uint8_t             id,
    1282                         uint32_t            len )
     1323messageLengthIsCorrect( const tr_peermsgs * msg, uint8_t id, uint32_t len )
    12831324{
    12841325    switch( id )
     
    12881329        case BT_INTERESTED:
    12891330        case BT_NOT_INTERESTED:
    1290         case BT_HAVE_ALL:
    1291         case BT_HAVE_NONE:
     1331        case BT_FEXT_HAVE_ALL:
     1332        case BT_FEXT_HAVE_NONE:
    12921333            return len == 1;
    12931334
    12941335        case BT_HAVE:
    1295         case BT_SUGGEST:
    1296         case BT_ALLOWED_FAST:
     1336        case BT_FEXT_SUGGEST:
     1337        case BT_FEXT_ALLOWED_FAST:
    12971338            return len == 5;
    12981339
     
    13021343        case BT_REQUEST:
    13031344        case BT_CANCEL:
    1304         case BT_REJECT:
     1345        case BT_FEXT_REJECT:
    13051346            return len == 13;
    13061347
     
    13391380            return READ_LATER;
    13401381
    1341         tr_peerIoReadUint32( msgs->io, inbuf, &req->index );
    1342         tr_peerIoReadUint32( msgs->io, inbuf, &req->offset );
     1382        tr_peerIoReadUint32( msgs->peer->io, inbuf, &req->index );
     1383        tr_peerIoReadUint32( msgs->peer->io, inbuf, &req->offset );
    13431384        req->length = msgs->incoming.length - 9;
    1344         dbgmsg( msgs, "got incoming block header %u:%u->%u", req->index,
    1345                 req->offset,
    1346                 req->length );
     1385        dbgmsg( msgs, "got incoming block header %u:%u->%u", req->index, req->offset, req->length );
    13471386        return READ_NOW;
    13481387    }
    13491388    else
    13501389    {
    1351         int          err;
     1390        int err;
    13521391
    13531392        /* read in another chunk of data */
    1354         const size_t nLeft = req->length - EVBUFFER_LENGTH(
    1355             msgs->incoming.block );
    1356         size_t       n = MIN( nLeft, inlen );
    1357         uint8_t *    buf = tr_new( uint8_t, n );
     1393        const size_t nLeft = req->length - EVBUFFER_LENGTH( msgs->incoming.block );
     1394        size_t n = MIN( nLeft, inlen );
     1395        uint8_t * buf = tr_new( uint8_t, n );
    13581396        assert( EVBUFFER_LENGTH( inbuf ) >= n );
    1359         tr_peerIoReadBytes( msgs->io, inbuf, buf, n );
     1397        tr_peerIoReadBytes( msgs->peer->io, inbuf, buf, n );
    13601398        evbuffer_add( msgs->incoming.block, buf, n );
    13611399        fireClientGotData( msgs, n, TRUE );
    13621400        *setme_piece_bytes_read += n;
    13631401        tr_free( buf );
    1364         dbgmsg( msgs, "got %d bytes for block %u:%u->%u ... %d remain",
    1365                (int)n, req->index, req->offset, req->length,
     1402        dbgmsg( msgs, "got %zu bytes for block %u:%u->%u ... %d remain",
     1403               n, req->index, req->offset, req->length,
    13661404               (int)( req->length - EVBUFFER_LENGTH( msgs->incoming.block ) ) );
    13671405        if( EVBUFFER_LENGTH( msgs->incoming.block ) < req->length )
     
    13691407
    13701408        /* we've got the whole block ... process it */
    1371         err = clientGotBlock( msgs, EVBUFFER_DATA(
    1372                                   msgs->incoming.block ), req );
     1409        err = clientGotBlock( msgs, EVBUFFER_DATA( msgs->incoming.block ), req );
    13731410
    13741411        /* cleanup */
    1375         evbuffer_drain( msgs->incoming.block,
    1376                        EVBUFFER_LENGTH( msgs->incoming.block ) );
     1412        evbuffer_drain( msgs->incoming.block, EVBUFFER_LENGTH( msgs->incoming.block ) );
    13771413        req->length = 0;
    13781414        msgs->state = AWAITING_BT_LENGTH;
    13791415        if( !err )
    13801416            return READ_NOW;
    1381         else
    1382         {
     1417        else {
    13831418            fireError( msgs, err );
    13841419            return READ_ERR;
     
    13881423
    13891424static int
    1390 readBtMessage( tr_peermsgs *     msgs,
    1391                struct evbuffer * inbuf,
    1392                size_t            inlen )
     1425readBtMessage( tr_peermsgs * msgs, struct evbuffer * inbuf, size_t inlen )
    13931426{
    13941427    uint32_t      ui32;
     
    13961429    const uint8_t id = msgs->incoming.id;
    13971430    const size_t  startBufLen = EVBUFFER_LENGTH( inbuf );
     1431    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
    13981432
    13991433    --msglen; /* id length */
     
    14021436        return READ_LATER;
    14031437
    1404     dbgmsg( msgs, "got BT id %d, len %d, buffer size is %d", (int)id,
    1405             (int)msglen,
    1406             (int)inlen );
     1438    dbgmsg( msgs, "got BT id %d, len %d, buffer size is %zu", (int)id, (int)msglen, inlen );
    14071439
    14081440    if( !messageLengthIsCorrect( msgs, id, msglen + 1 ) )
    14091441    {
    1410         dbgmsg( msgs, "bad packet - BT message #%d with a length of %d",
    1411                 (int)id, (int)msglen );
     1442        dbgmsg( msgs, "bad packet - BT message #%d with a length of %d", (int)id, (int)msglen );
    14121443        fireError( msgs, EMSGSIZE );
    14131444        return READ_ERR;
     
    14181449        case BT_CHOKE:
    14191450            dbgmsg( msgs, "got Choke" );
    1420             msgs->info->clientIsChoked = 1;
    1421             cancelAllRequestsToPeer( msgs, FALSE );
     1451            msgs->peer->clientIsChoked = 1;
     1452            if( !fext )
     1453                cancelAllRequestsToPeer( msgs, FALSE );
    14221454            break;
    14231455
    14241456        case BT_UNCHOKE:
    14251457            dbgmsg( msgs, "got Unchoke" );
    1426             msgs->info->clientIsChoked = 0;
     1458            msgs->peer->clientIsChoked = 0;
    14271459            fireNeedReq( msgs );
    14281460            break;
     
    14301462        case BT_INTERESTED:
    14311463            dbgmsg( msgs, "got Interested" );
    1432             msgs->info->peerIsInterested = 1;
     1464            msgs->peer->peerIsInterested = 1;
    14331465            break;
    14341466
    14351467        case BT_NOT_INTERESTED:
    14361468            dbgmsg( msgs, "got Not Interested" );
    1437             msgs->info->peerIsInterested = 0;
     1469            msgs->peer->peerIsInterested = 0;
    14381470            break;
    14391471
    14401472        case BT_HAVE:
    1441             tr_peerIoReadUint32( msgs->io, inbuf, &ui32 );
     1473            tr_peerIoReadUint32( msgs->peer->io, inbuf, &ui32 );
    14421474            dbgmsg( msgs, "got Have: %u", ui32 );
    1443             if( tr_bitfieldAdd( msgs->info->have, ui32 ) )
    1444             {
     1475            if( tr_bitfieldAdd( msgs->peer->have, ui32 ) ) {
    14451476                fireError( msgs, ERANGE );
    14461477                return READ_ERR;
     
    14551486            dbgmsg( msgs, "got a bitfield" );
    14561487            msgs->peerSentBitfield = 1;
    1457             tr_peerIoReadBytes( msgs->io, inbuf, msgs->info->have->bits,
    1458                                 msglen );
     1488            tr_peerIoReadBytes( msgs->peer->io, inbuf, msgs->peer->have->bits, msglen );
    14591489            updatePeerProgress( msgs );
    1460             maybeSendFastAllowedSet( msgs );
    14611490            fireNeedReq( msgs );
    14621491            break;
     
    14661495        {
    14671496            struct peer_request r;
    1468             tr_peerIoReadUint32( msgs->io, inbuf, &r.index );
    1469             tr_peerIoReadUint32( msgs->io, inbuf, &r.offset );
    1470             tr_peerIoReadUint32( msgs->io, inbuf, &r.length );
    1471             dbgmsg( msgs, "got Request: %u:%u->%u", r.index, r.offset,
    1472                     r.length );
     1497            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.index );
     1498            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.offset );
     1499            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.length );
     1500            dbgmsg( msgs, "got Request: %u:%u->%u", r.index, r.offset, r.length );
    14731501            peerMadeRequest( msgs, &r );
    14741502            break;
     
    14781506        {
    14791507            struct peer_request r;
    1480             tr_peerIoReadUint32( msgs->io, inbuf, &r.index );
    1481             tr_peerIoReadUint32( msgs->io, inbuf, &r.offset );
    1482             tr_peerIoReadUint32( msgs->io, inbuf, &r.length );
    1483             dbgmsg( msgs, "got a Cancel %u:%u->%u", r.index, r.offset,
    1484                     r.length );
    1485             reqListRemove( &msgs->peerAskedForFast, &r );
    1486             reqListRemove( &msgs->peerAskedFor, &r );
     1508            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.index );
     1509            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.offset );
     1510            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.length );
     1511            dbgmsg( msgs, "got a Cancel %u:%u->%u", r.index, r.offset, r.length );
     1512            if( reqListRemove( &msgs->peerAskedFor, &r ) && fext )
     1513                protocolSendReject( msgs, &r );
    14871514            break;
    14881515        }
     
    14941521        case BT_PORT:
    14951522            dbgmsg( msgs, "Got a BT_PORT" );
    1496             tr_peerIoReadUint16( msgs->io, inbuf, &msgs->info->port );
     1523            tr_peerIoReadUint16( msgs->peer->io, inbuf, &msgs->peer->port );
    14971524            break;
    14981525
    1499         case BT_SUGGEST:
    1500         {
    1501             dbgmsg( msgs, "Got a BT_SUGGEST" );
    1502             tr_peerIoReadUint32( msgs->io, inbuf, &ui32 );
    1503             /* we don't do anything with this yet */
     1526        case BT_FEXT_SUGGEST:
     1527            dbgmsg( msgs, "Got a BT_FEXT_SUGGEST" );
     1528            tr_peerIoReadUint32( msgs->peer->io, inbuf, &ui32 );
     1529            if( fext )
     1530                fireClientGotSuggest( msgs, ui32 );
     1531            else {
     1532                fireError( msgs, EMSGSIZE );
     1533                return READ_ERR;
     1534            }
    15041535            break;
    1505         }
    1506 
    1507         case BT_HAVE_ALL:
    1508             dbgmsg( msgs, "Got a BT_HAVE_ALL" );
    1509             tr_bitfieldAddRange( msgs->info->have, 0,
    1510                                  msgs->torrent->info.pieceCount );
    1511             updatePeerProgress( msgs );
    1512             maybeSendFastAllowedSet( msgs );
     1536
     1537        case BT_FEXT_ALLOWED_FAST:
     1538            dbgmsg( msgs, "Got a BT_FEXT_ALLOWED_FAST" );
     1539            tr_peerIoReadUint32( msgs->peer->io, inbuf, &ui32 );
     1540            if( fext )
     1541                fireClientGotAllowedFast( msgs, ui32 );
     1542            else {
     1543                fireError( msgs, EMSGSIZE );
     1544                return READ_ERR;
     1545            }
    15131546            break;
    15141547
    1515 
    1516         case BT_HAVE_NONE:
    1517             dbgmsg( msgs, "Got a BT_HAVE_NONE" );
    1518             tr_bitfieldClear( msgs->info->have );
    1519             updatePeerProgress( msgs );
    1520             maybeSendFastAllowedSet( msgs );
     1548        case BT_FEXT_HAVE_ALL:
     1549            dbgmsg( msgs, "Got a BT_FEXT_HAVE_ALL" );
     1550            if( fext ) {
     1551                tr_bitfieldAddRange( msgs->peer->have, 0, msgs->torrent->info.pieceCount );
     1552                updatePeerProgress( msgs );
     1553            } else {
     1554                fireError( msgs, EMSGSIZE );
     1555                return READ_ERR;
     1556            }
    15211557            break;
    15221558
    1523         case BT_REJECT:
     1559        case BT_FEXT_HAVE_NONE:
     1560            dbgmsg( msgs, "Got a BT_FEXT_HAVE_NONE" );
     1561            if( fext ) {
     1562                tr_bitfieldClear( msgs->peer->have );
     1563                updatePeerProgress( msgs );
     1564            } else {
     1565                fireError( msgs, EMSGSIZE );
     1566                return READ_ERR;
     1567            }
     1568            break;
     1569
     1570        case BT_FEXT_REJECT:
    15241571        {
    15251572            struct peer_request r;
    1526             dbgmsg( msgs, "Got a BT_REJECT" );
    1527             tr_peerIoReadUint32( msgs->io, inbuf, &r.index );
    1528             tr_peerIoReadUint32( msgs->io, inbuf, &r.offset );
    1529             tr_peerIoReadUint32( msgs->io, inbuf, &r.length );
    1530             reqListRemove( &msgs->clientAskedFor, &r );
    1531             break;
    1532         }
    1533 
    1534         case BT_ALLOWED_FAST:
    1535         {
    1536             dbgmsg( msgs, "Got a BT_ALLOWED_FAST" );
    1537             tr_peerIoReadUint32( msgs->io, inbuf, &ui32 );
    1538             /* we don't do anything with this yet */
     1573            dbgmsg( msgs, "Got a BT_FEXT_REJECT" );
     1574            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.index );
     1575            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.offset );
     1576            tr_peerIoReadUint32( msgs->peer->io, inbuf, &r.length );
     1577            if( fext )
     1578                reqListRemove( &msgs->clientAskedFor, &r );
     1579            else {
     1580                fireError( msgs, EMSGSIZE );
     1581                return READ_ERR;
     1582            }
    15391583            break;
    15401584        }
     
    15471591        default:
    15481592            dbgmsg( msgs, "peer sent us an UNKNOWN: %d", (int)id );
    1549             tr_peerIoDrain( msgs->io, inbuf, msglen );
     1593            tr_peerIoDrain( msgs->peer->io, inbuf, msglen );
    15501594            break;
    15511595    }
     
    15591603
    15601604static void
    1561 decrementDownloadedCount( tr_peermsgs * msgs,
    1562                           uint32_t      byteCount )
     1605decrementDownloadedCount( tr_peermsgs * msgs, uint32_t byteCount )
    15631606{
    15641607    tr_torrent * tor = msgs->torrent;
     
    15681611
    15691612static void
    1570 clientGotUnwantedBlock( tr_peermsgs *               msgs,
    1571                         const struct peer_request * req )
     1613clientGotUnwantedBlock( tr_peermsgs * msgs, const struct peer_request * req )
    15721614{
    15731615    decrementDownloadedCount( msgs, req->length );
     
    15751617
    15761618static void
    1577 addPeerToBlamefield( tr_peermsgs * msgs,
    1578                      uint32_t      index )
    1579 {
    1580     if( !msgs->info->blame )
    1581         msgs->info->blame = tr_bitfieldNew( msgs->torrent->info.pieceCount );
    1582     tr_bitfieldAdd( msgs->info->blame, index );
     1619addPeerToBlamefield( tr_peermsgs * msgs, uint32_t index )
     1620{
     1621    if( !msgs->peer->blame )
     1622         msgs->peer->blame = tr_bitfieldNew( msgs->torrent->info.pieceCount );
     1623    tr_bitfieldAdd( msgs->peer->blame, index );
    15831624}
    15841625
     
    15891630                const struct peer_request * req )
    15901631{
    1591     int                    err;
    1592     tr_torrent *           tor = msgs->torrent;
     1632    int err;
     1633    tr_torrent * tor = msgs->torrent;
    15931634    const tr_block_index_t block = _tr_block( tor, req->index, req->offset );
    15941635
     
    15961637    assert( req );
    15971638
    1598     if( req->length != tr_torBlockCountBytes( msgs->torrent, block ) )
    1599     {
     1639    if( req->length != tr_torBlockCountBytes( msgs->torrent, block ) ) {
    16001640        dbgmsg( msgs, "wrong block size -- expected %u, got %d",
    16011641                tr_torBlockCountBytes( msgs->torrent, block ), req->length );
     
    16041644
    16051645    /* save the block */
    1606     dbgmsg( msgs, "got block %u:%u->%u", req->index, req->offset,
    1607             req->length );
     1646    dbgmsg( msgs, "got block %u:%u->%u", req->index, req->offset, req->length );
    16081647
    16091648    /**
     
    16111650    **/
    16121651
    1613     if( !reqListRemove( &msgs->clientAskedFor, req ) )
    1614     {
     1652    if( !reqListRemove( &msgs->clientAskedFor, req ) ) {
    16151653        clientGotUnwantedBlock( msgs, req );
    16161654        dbgmsg( msgs, "we didn't ask for this message..." );
     
    16251663    **/
    16261664
    1627     if( tr_cpBlockIsComplete( tor->completion, block ) )
    1628     {
     1665    if( tr_cpBlockIsComplete( tor->completion, block ) ) {
    16291666        dbgmsg( msgs, "we have this block already..." );
    16301667        clientGotUnwantedBlock( msgs, req );
     
    16551692
    16561693static ReadState
    1657 canRead( struct tr_iobuf * iobuf, void * vmsgs, size_t * piece )
     1694canRead( tr_peerIo * io, void * vmsgs, size_t * piece )
    16581695{
    16591696    ReadState         ret;
    16601697    tr_peermsgs *     msgs = vmsgs;
    1661     struct evbuffer * in = tr_iobuf_input( iobuf );
     1698    struct evbuffer * in = tr_peerIoGetReadBuffer( io );
    16621699    const size_t      inlen = EVBUFFER_LENGTH( in );
    16631700
     
    17001737{
    17011738    tr_peermsgs * msgs = vmsgs;
    1702     const double rateToClient = tr_peerGetPieceSpeed( msgs->info, TR_PEER_TO_CLIENT );
    1703     const int estimatedBlocksInNext30Seconds =
    1704                   ( rateToClient * 30 * 1024 ) / msgs->torrent->blockSize;
    1705     msgs->minActiveRequests = 8;
    1706     msgs->maxActiveRequests = msgs->minActiveRequests + estimatedBlocksInNext30Seconds;
     1739    const double rateToClient = tr_peerGetPieceSpeed( msgs->peer, TR_PEER_TO_CLIENT );
     1740    const int seconds = 10;
     1741    const int floor = 8;
     1742    const int estimatedBlocksInPeriod = ( rateToClient * seconds * 1024 ) / msgs->torrent->blockSize;
     1743
     1744    msgs->maxActiveRequests = floor + estimatedBlocksInPeriod;
     1745
    17071746    if( msgs->reqq > 0 )
    17081747        msgs->maxActiveRequests = MIN( msgs->maxActiveRequests, msgs->reqq );
     1748
    17091749    return TRUE;
    1710 }
    1711 
    1712 static int
    1713 popNextRequest( tr_peermsgs *         msgs,
    1714                 struct peer_request * setme )
    1715 {
    1716     return reqListPop( &msgs->peerAskedForFast, setme )
    1717         || reqListPop( &msgs->peerAskedFor, setme );
    17181750}
    17191751
     
    17231755    size_t bytesWritten = 0;
    17241756    struct peer_request req;
    1725     const int haveMessages = EVBUFFER_LENGTH( msgs->outMessages ) != 0;
     1757    const tr_bool haveMessages = EVBUFFER_LENGTH( msgs->outMessages ) != 0;
     1758    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
    17261759
    17271760    /**
     
    17381771        const size_t len = EVBUFFER_LENGTH( msgs->outMessages );
    17391772        /* flush the protocol messages */
    1740         dbgmsg( msgs, "flushing outMessages... to %p (length is %zu)", msgs->io, len );
    1741         tr_peerIoWriteBuf( msgs->io, msgs->outMessages, FALSE );
     1773        dbgmsg( msgs, "flushing outMessages... to %p (length is %zu)", msgs->peer->io, len );
     1774        tr_peerIoWriteBuf( msgs->peer->io, msgs->outMessages, FALSE );
    17421775        msgs->clientSentAnythingAt = now;
    17431776        msgs->outMessagesBatchedAt = 0;
     
    17501783    **/
    17511784
    1752     if( ( tr_peerIoGetWriteBufferSpace( msgs->io ) >= msgs->torrent->blockSize )
    1753         && popNextRequest( msgs, &req )
    1754         && requestIsValid( msgs, &req )
    1755         && tr_cpPieceIsComplete( msgs->torrent->completion, req.index ) )
    1756     {
    1757         /* send a block */
    1758         uint8_t * buf = tr_new( uint8_t, req.length );
    1759         const int err = tr_ioRead( msgs->torrent, req.index, req.offset, req.length, buf );
    1760         if( err ) {
    1761             fireError( msgs, err );
    1762             bytesWritten = 0;
    1763             msgs = NULL;
    1764         } else {
    1765             tr_peerIo * io = msgs->io;
    1766             struct evbuffer * out = evbuffer_new( );
    1767             dbgmsg( msgs, "sending block %u:%u->%u", req.index, req.offset, req.length );
    1768             tr_peerIoWriteUint32( io, out, sizeof( uint8_t ) + 2 * sizeof( uint32_t ) + req.length );
    1769             tr_peerIoWriteUint8 ( io, out, BT_PIECE );
    1770             tr_peerIoWriteUint32( io, out, req.index );
    1771             tr_peerIoWriteUint32( io, out, req.offset );
    1772             tr_peerIoWriteBytes ( io, out, buf, req.length );
    1773             tr_peerIoWriteBuf( io, out, TRUE );
    1774             bytesWritten += EVBUFFER_LENGTH( out );
    1775             evbuffer_free( out );
    1776             msgs->clientSentAnythingAt = now;
     1785    if( ( tr_peerIoGetWriteBufferSpace( msgs->peer->io ) >= msgs->torrent->blockSize )
     1786        && popNextRequest( msgs, &req ) )
     1787    {
     1788        if( requestIsValid( msgs, &req )
     1789            && tr_cpPieceIsComplete( msgs->torrent->completion, req.index ) )
     1790        {
     1791            /* send a block */
     1792            uint8_t * buf = tr_new( uint8_t, req.length );
     1793            const int err = tr_ioRead( msgs->torrent, req.index, req.offset, req.length, buf );
     1794            if( err ) {
     1795                fireError( msgs, err );
     1796                bytesWritten = 0;
     1797                msgs = NULL;
     1798            } else {
     1799                tr_peerIo * io = msgs->peer->io;
     1800                struct evbuffer * out = evbuffer_new( );
     1801                dbgmsg( msgs, "sending block %u:%u->%u", req.index, req.offset, req.length );
     1802                tr_peerIoWriteUint32( io, out, sizeof( uint8_t ) + 2 * sizeof( uint32_t ) + req.length );
     1803                tr_peerIoWriteUint8 ( io, out, BT_PIECE );
     1804                tr_peerIoWriteUint32( io, out, req.index );
     1805                tr_peerIoWriteUint32( io, out, req.offset );
     1806                tr_peerIoWriteBytes ( io, out, buf, req.length );
     1807                tr_peerIoWriteBuf( io, out, TRUE );
     1808                bytesWritten += EVBUFFER_LENGTH( out );
     1809                evbuffer_free( out );
     1810                msgs->clientSentAnythingAt = now;
     1811            }
     1812            tr_free( buf );
    17771813        }
    1778         tr_free( buf );
     1814        else if( fext ) /* peer needs a reject message */
     1815        {
     1816            protocolSendReject( msgs, &req );
     1817        }
    17791818    }
    17801819
     
    17881827    {
    17891828        dbgmsg( msgs, "sending a keepalive message" );
    1790         tr_peerIoWriteUint32( msgs->io, msgs->outMessages, 0 );
     1829        tr_peerIoWriteUint32( msgs->peer->io, msgs->outMessages, 0 );
    17911830        pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
    17921831    }
     
    18211860
    18221861static void
    1823 gotError( struct tr_iobuf  * iobuf UNUSED,
    1824           short              what,
    1825           void             * vmsgs )
     1862gotError( tr_peerIo  * io UNUSED,
     1863          short        what,
     1864          void       * vmsgs )
    18261865{
    18271866    if( what & EVBUFFER_TIMEOUT )
     
    18721911    }
    18731912
    1874     tr_peerIoWriteUint32( msgs->io, out,
     1913    tr_peerIoWriteUint32( msgs->peer->io, out,
    18751914                          sizeof( uint8_t ) + field->byteCount );
    1876     tr_peerIoWriteUint8 ( msgs->io, out, BT_BITFIELD );
    1877     tr_peerIoWriteBytes ( msgs->io, out, field->bits, field->byteCount );
    1878     dbgmsg( msgs, "sending bitfield... outMessage size is now %d",
    1879            (int)EVBUFFER_LENGTH( out ) );
     1915    tr_peerIoWriteUint8 ( msgs->peer->io, out, BT_BITFIELD );
     1916    tr_peerIoWriteBytes ( msgs->peer->io, out, field->bits, field->byteCount );
     1917    dbgmsg( msgs, "sending bitfield... outMessage size is now %zu",
     1918            EVBUFFER_LENGTH( out ) );
    18801919    pokeBatchPeriod( msgs, IMMEDIATE_PRIORITY_INTERVAL_SECS );
    18811920
     
    18841923
    18851924    tr_bitfieldFree( field );
     1925}
     1926
     1927static void
     1928tellPeerWhatWeHave( tr_peermsgs * msgs )
     1929{
     1930    const tr_bool fext = tr_peerIoSupportsFEXT( msgs->peer->io );
     1931
     1932    if( fext && ( tr_cpGetStatus( msgs->torrent->completion ) == TR_CP_COMPLETE ) )
     1933    {
     1934        protocolSendHaveAll( msgs );
     1935    }
     1936    else if( fext && ( tr_cpHaveValid( msgs->torrent->completion ) == 0 ) )
     1937    {
     1938        protocolSendHaveNone( msgs );
     1939    }
     1940    else
     1941    {
     1942        sendBitfield( msgs );
     1943    }
    18861944}
    18871945
     
    19952053            tmp = walk = tr_new( uint8_t, diffs.addedCount * 6 );
    19962054            for( i = 0; i < diffs.addedCount; ++i ) {
    1997                 memcpy( walk, &diffs.added[i].in_addr, 4 ); walk += 4;
     2055                memcpy( walk, &diffs.added[i].addr, 4 ); walk += 4;
    19982056                memcpy( walk, &diffs.added[i].port, 2 ); walk += 2;
    19992057            }
     
    20132071            tmp = walk = tr_new( uint8_t, diffs.droppedCount * 6 );
    20142072            for( i = 0; i < diffs.droppedCount; ++i ) {
    2015                 memcpy( walk, &diffs.dropped[i].in_addr, 4 ); walk += 4;
     2073                memcpy( walk, &diffs.dropped[i].addr, 4 ); walk += 4;
    20162074                memcpy( walk, &diffs.dropped[i].port, 2 ); walk += 2;
    20172075            }
     
    20222080            /* write the pex message */
    20232081            benc = tr_bencSave( &val, &bencLen );
    2024             tr_peerIoWriteUint32( msgs->io, out, 2 * sizeof( uint8_t ) + bencLen );
    2025             tr_peerIoWriteUint8 ( msgs->io, out, BT_LTEP );
    2026             tr_peerIoWriteUint8 ( msgs->io, out, msgs->ut_pex_id );
    2027             tr_peerIoWriteBytes ( msgs->io, out, benc, bencLen );
     2082            tr_peerIoWriteUint32( msgs->peer->io, out, 2 * sizeof( uint8_t ) + bencLen );
     2083            tr_peerIoWriteUint8 ( msgs->peer->io, out, BT_LTEP );
     2084            tr_peerIoWriteUint8 ( msgs->peer->io, out, msgs->ut_pex_id );
     2085            tr_peerIoWriteBytes ( msgs->peer->io, out, benc, bencLen );
    20282086            pokeBatchPeriod( msgs, HIGH_PRIORITY_INTERVAL_SECS );
    20292087            dbgmsg( msgs, "sending a pex message; outMessage size is now %zu", EVBUFFER_LENGTH( out ) );
     
    20552113tr_peermsgs*
    20562114tr_peerMsgsNew( struct tr_torrent * torrent,
    2057                 struct tr_peer *    info,
     2115                struct tr_peer    * peer,
    20582116                tr_delivery_func    func,
    2059                 void *              userData,
    2060                 tr_publisher_tag * setme )
     2117                void              * userData,
     2118                tr_publisher_tag  * setme )
    20612119{
    20622120    tr_peermsgs * m;
    20632121
    2064     assert( info );
    2065     assert( info->io );
     2122    assert( peer );
     2123    assert( peer->io );
    20662124
    20672125    m = tr_new0( tr_peermsgs, 1 );
    20682126    m->publisher = tr_publisherNew( );
    2069     m->info = info;
     2127    m->peer = peer;
    20702128    m->session = torrent->session;
    20712129    m->torrent = torrent;
    2072     m->io = info->io;
    2073     m->info->clientIsChoked = 1;
    2074     m->info->peerIsChoked = 1;
    2075     m->info->clientIsInterested = 0;
    2076     m->info->peerIsInterested = 0;
    2077     m->info->have = tr_bitfieldNew( torrent->info.pieceCount );
     2130    m->peer->clientIsChoked = 1;
     2131    m->peer->peerIsChoked = 1;
     2132    m->peer->clientIsInterested = 0;
     2133    m->peer->peerIsInterested = 0;
     2134    m->peer->have = tr_bitfieldNew( torrent->info.pieceCount );
    20782135    m->state = AWAITING_BT_LENGTH;
    20792136    m->pexTimer = tr_timerNew( m->session, pexPulse, m, PEX_INTERVAL );
     
    20822139    m->outMessagesBatchPeriod = LOW_PRIORITY_INTERVAL_SECS;
    20832140    m->incoming.block = evbuffer_new( );
    2084     m->peerAllowedPieces = NULL;
    20852141    m->peerAskedFor = REQUEST_LIST_INIT;
    2086     m->peerAskedForFast = REQUEST_LIST_INIT;
    20872142    m->clientAskedFor = REQUEST_LIST_INIT;
    20882143    m->clientWillAskFor = REQUEST_LIST_INIT;
     2144    peer->msgs = m;
     2145
    20892146    *setme = tr_publisherSubscribe( m->publisher, func, userData );
    20902147
    2091     if( tr_peerIoSupportsLTEP( m->io ) )
     2148    if( tr_peerIoSupportsLTEP( peer->io ) )
    20922149        sendLtepHandshake( m );
    20932150
    2094     sendBitfield( m );
    2095 
    2096     tr_peerIoSetTimeoutSecs( m->io, 150 ); /* timeout after N seconds of
    2097                                              inactivity */
    2098     tr_peerIoSetIOFuncs( m->io, canRead, didWrite, gotError, m );
     2151    tellPeerWhatWeHave( m );
     2152
     2153    tr_peerIoSetIOFuncs( m->peer->io, canRead, didWrite, gotError, m );
    20992154    ratePulse( m );
    21002155
     
    21112166        reqListClear( &msgs->clientWillAskFor );
    21122167        reqListClear( &msgs->clientAskedFor );
    2113         reqListClear( &msgs->peerAskedForFast );
    21142168        reqListClear( &msgs->peerAskedFor );
    2115         tr_bitfieldFree( msgs->peerAllowedPieces );
     2169
    21162170        evbuffer_free( msgs->incoming.block );
    21172171