source: trunk/libtransmission/peer.c @ 2769

Last change on this file since 2769 was 2769, checked in by joshe, 15 years ago

Use macros instead of magic numbers when creating and parsing handshake.
Make it trivial to disable extended messaging or azureus protocol at compile-time, for debugging.

  • Property svn:keywords set to Date Rev Author Id
File size: 29.7 KB
Line 
1/******************************************************************************
2 * $Id: peer.c 2769 2007-08-15 19:44:13Z joshe $
3 *
4 * Copyright (c) 2005-2007 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <stdarg.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <time.h>
30
31#include <sys/types.h>
32
33#include "transmission.h"
34#include "bencode.h"
35#include "clients.h" /* for tr_clientForId() */
36#include "completion.h"
37#include "inout.h"
38#include "list.h"
39#include "net.h"
40#include "peer.h"
41#include "peertree.h"
42#include "ratecontrol.h"
43#include "utils.h"
44
45/*****
46******
47*****/
48
49/**
50*** The "SWIFT" system is described by Karthik Tamilmani,
51*** Vinay Pai, and Alexander Mohr of Stony Brook University
52*** in their paper "SWIFT: A System With Incentives For Trading"
53*** http://citeseer.ist.psu.edu/tamilmani04swift.html
54**/
55
56/**
57 * Use SWIFT?
58 */
59static const int SWIFT_ENABLED = 1;
60
61/**
62 * For every byte the peer uploads to us,
63 * allow them to download this many bytes from us
64 */
65static const double SWIFT_REPAYMENT_RATIO = 1.33;
66
67/**
68 * Allow new peers to download this many bytes from
69 * us when getting started.  This can prevent gridlock
70 * with other peers using tit-for-tat algorithms
71 */
72static const int SWIFT_INITIAL_CREDIT = 64 * 1024; /* 64 KiB */
73
74/**
75 * We expend a fraction of our torrent's total upload speed
76 * on largesse by uniformly distributing free credit to
77 * all of our peers.  This too helps prevent gridlock.
78 */
79static const double SWIFT_LARGESSE = 0.10; /* 10% of our UL */
80
81/**
82 * How frequently to extend largesse-based credit
83 */
84static const int SWIFT_REFRESH_INTERVAL_SEC = 5;
85
86/*****
87******
88*****/
89
90#define PERCENT_PEER_WANTED     25      /* Percent before we start relax peers min activeness */
91#define MIN_UPLOAD_IDLE         60000   /* In high peer situations we wait only 1 min
92                                            until dropping peers for idling */
93#define MAX_UPLOAD_IDLE         240000  /* In low peer situations we wait the
94                                            4 mins until dropping peers for idling */
95#define MIN_KEEP_ALIVE          180000  /* In high peer situations we wait only 3 min
96                                            without a keep-alive */
97#define MAX_KEEP_ALIVE          360000  /* In low peer situations we wait the
98                                            6 mins without a keep-alive */
99#define MIN_CON_TIMEOUT         8000    /* Time to timeout connecting to peer,
100                                            during low peer situations */
101#define MAX_CON_TIMEOUT         30000   /* Time to timeout connecting to peer,
102                                            during high peer situations */
103#define PEX_PEER_CUTOFF         50 /* only try to add new peers from pex if
104                                      we have fewer existing peers than this */
105#define PEX_INTERVAL            60 /* don't send pex messages more frequently
106                                      than PEX_INTERVAL +
107                                      rand( PEX_INTERVAL / 10 ) seconds */
108
109/* uncomment this to disable support for the extended messaging bit */
110/* #define DISABLE_EXTMSGS */
111/* uncomment this to disable support for the azureus protocol bit */
112/* #define DISABLE_AZPROTO */
113
114#define HANDSHAKE_NAME          "\023BitTorrent protocol"
115#define HANDSHAKE_NAME_LEN      20
116#define HANDSHAKE_FLAGS_OFF     HANDSHAKE_NAME_LEN
117#define HANDSHAKE_FLAGS_LEN     8
118#define HANDSHAKE_HASH_OFF      ( HANDSHAKE_FLAGS_OFF + HANDSHAKE_FLAGS_LEN )
119#define HANDSHAKE_PEERID_OFF    ( HANDSHAKE_HASH_OFF + SHA_DIGEST_LENGTH )
120#define HANDSHAKE_SIZE          ( HANDSHAKE_PEERID_OFF + TR_ID_LEN )
121
122#ifdef DISABLE_EXTMSGS
123#define HANDSHAKE_HAS_EXTMSGS( bits ) ( 0 )
124#define HANDSHAKE_SET_EXTMSGS( bits ) ( (void)0 )
125#else
126#define HANDSHAKE_HAS_EXTMSGS( bits ) ( (bits)[5] & 0x10 )
127#define HANDSHAKE_SET_EXTMSGS( bits ) ( (bits)[5] |= 0x10 )
128#endif
129
130#ifdef DISABLE_AZPROTO
131#define HANDSHAKE_HAS_AZPROTO( bits ) ( 0 )
132#define HANDSHAKE_SET_AZPROTO( bits ) ( (void)0 )
133#else
134#define HANDSHAKE_HAS_AZPROTO( bits ) ( (bits)[0] & 0x80 )
135#define HANDSHAKE_SET_AZPROTO( bits ) ( (bits)[0] |= 0x80 )
136#endif
137
138#define PEER_MSG_CHOKE          0
139#define PEER_MSG_UNCHOKE        1
140#define PEER_MSG_INTERESTED     2
141#define PEER_MSG_UNINTERESTED   3
142#define PEER_MSG_HAVE           4
143#define PEER_MSG_BITFIELD       5
144#define PEER_MSG_REQUEST        6
145#define PEER_MSG_PIECE          7
146#define PEER_MSG_CANCEL         8
147#define PEER_MSG_PORT           9
148#define PEER_MSG_EXTENDED       20
149
150typedef struct tr_request_s
151{
152    int index;
153    int begin;
154    int length;
155
156} tr_request_t;
157
158struct tr_peer_s
159{
160    tr_torrent_t      * tor;
161
162    struct in_addr      addr;
163    tr_port_t           port;  /* peer's listening port, 0 if not known */
164
165#define PEER_STATUS_IDLE        1 /* Need to connect */
166#define PEER_STATUS_CONNECTING  2 /* Trying to send handshake */
167#define PEER_STATUS_HANDSHAKE   3 /* Waiting for peer's handshake */
168#define PEER_STATUS_AZ_GIVER    4 /* Sending Azureus handshake */
169#define PEER_STATUS_AZ_RECEIVER 5 /* Receiving Azureus handshake */
170#define PEER_STATUS_CONNECTED   6 /* Got peer's handshake */
171    int                 status;
172    int                 socket;
173    char                from;
174    char                private;
175    char                azproto;  /* azureus peer protocol is being used */
176    uint64_t            date;
177    uint64_t            keepAlive;
178
179#define EXTENDED_NOT_SUPPORTED   0 /* extended messages not supported */
180#define EXTENDED_SUPPORTED       1 /* waiting to send extended handshake */
181#define EXTENDED_HANDSHAKE       2 /* sent extended handshake */
182    uint8_t             extStatus;
183    uint8_t             pexStatus;   /* peer's ut_pex id, 0 if not supported */
184    uint64_t            lastPex;     /* time when last pex packet was sent */
185    int                 advertisedPort; /* listening port we last told peer */
186    tr_peertree_t       sentPeers;
187
188    char                isChokedByUs;
189    char                isChokingUs;
190    char                isInteresting;
191    char                isInterested;
192
193    int                 optimistic;
194    int                 timesChoked;
195    uint64_t            lastChoke;
196
197    uint8_t             id[TR_ID_LEN];
198
199    /* The pieces that the peer has */
200    tr_bitfield_t     * bitfield;
201
202    /* blocks we've requested from this peer */
203    tr_bitfield_t     * reqfield;
204    int                 pieceCount;
205    float               progress;
206
207    int                 goodPcs;
208    int                 badPcs;
209    int                 banned;
210    /* The pieces that the peer is contributing to */
211    tr_bitfield_t     * blamefield;
212    /* The bad pieces that the peer has contributed to */
213    tr_bitfield_t     * banfield;
214
215    uint8_t           * buf;
216    int                 size;
217    int                 pos;
218
219    uint8_t           * outMessages;
220    int                 outMessagesSize;
221    int                 outMessagesPos;
222    uint8_t             outBlock[25+16384];
223    int                 outBlockSize;
224    int                 outBlockLoaded;
225    int                 outBlockSending;
226
227    int                 inRequestCount;
228    int                 inRequestMax;
229    int                 inRequestAlloc;
230    tr_request_t      * inRequests;
231    int                 inIndex;
232    int                 inBegin;
233    int                 inLength;
234
235    tr_list_t         * outRequests;
236    uint64_t            outDate;
237
238    tr_ratecontrol_t  * download;
239    tr_ratecontrol_t  * upload;
240
241    char              * client;
242
243    int64_t             credit;
244};
245
246#define peer_dbg( a... ) __peer_dbg( peer, ## a )
247
248static void __peer_dbg( tr_peer_t * peer, char * msg, ... )
249{
250    char    string[256];
251    va_list args;
252
253    va_start( args, msg );
254    snprintf( string, sizeof string, "%08x:%04x ",
255             (uint32_t) peer->addr.s_addr, peer->port );
256    vsnprintf( &string[14], sizeof( string ) - 14, msg, args );
257    va_end( args ); 
258
259    tr_dbg( "%s", string );
260}
261
262/* utilities for endian conversions with char pointers */
263
264static uint32_t tr_ntohl( const void * p )
265{
266    uint32_t u;
267    memcpy( &u, p, sizeof( uint32_t ) );
268    return ntohl( u );
269}
270static void tr_htonl( uint32_t a, void * p )
271{
272    const uint32_t u = htonl( a );
273    memcpy ( p, &u, sizeof( uint32_t ) );
274}
275
276#include "peerext.h"
277#include "peeraz.h"
278#include "peermessages.h"
279#include "peerutils.h"
280#include "peerparse.h"
281
282/***********************************************************************
283 * tr_peerInit
284 ***********************************************************************
285 * Initializes a new peer.
286 **********************************************************************/
287tr_peer_t * tr_peerInit( const struct in_addr * addr, tr_port_t port,
288                         int s, int from )
289{
290    tr_peer_t * peer;
291
292    assert( 0 <= from && TR_PEER_FROM__MAX > from );
293
294    peer                   = tr_new0( tr_peer_t, 1 );
295    peer->isChokedByUs     = TRUE;
296    peer->isChokingUs      = TRUE;
297    peer->date             = tr_date();
298    peer->keepAlive        = peer->date;
299    peer->download         = tr_rcInit();
300    peer->upload           = tr_rcInit();
301    peertreeInit( &peer->sentPeers );
302
303    peer->inRequestMax = peer->inRequestAlloc = 2;
304    peer->inRequests = tr_new0( tr_request_t, peer->inRequestAlloc );
305
306    peer->socket = s;
307    peer->addr = *addr;
308    peer->port = port;
309    peer->from = from;
310    peer->credit = SWIFT_INITIAL_CREDIT;
311    if( s >= 0 )
312    {
313        assert( TR_PEER_FROM_INCOMING == from );
314        peer->status = PEER_STATUS_CONNECTING;
315    }
316    else
317    {
318        peer->status = PEER_STATUS_IDLE;
319    }
320
321    return peer;
322}
323
324void tr_peerDestroy( tr_peer_t * peer )
325{
326    tr_torrent_t * tor = peer->tor;
327    tr_request_t * r;
328    int i, block;
329
330    peertreeFree( &peer->sentPeers );
331    for( i = 0; i < peer->inRequestCount; i++ )
332    {
333        r = &peer->inRequests[i];
334        block = tr_block( r->index, r->begin );
335        if( tor != NULL )
336            tr_cpDownloaderRem( tor->completion, block );
337    }
338    tr_bitfieldFree( peer->bitfield );
339    tr_bitfieldFree( peer->blamefield );
340    tr_bitfieldFree( peer->banfield );
341    tr_bitfieldFree( peer->reqfield );
342    tr_list_foreach( peer->outRequests, tr_free );
343    tr_list_free( &peer->outRequests );
344    tr_free( peer->inRequests );
345    tr_free( peer->buf );
346    tr_free( peer->outMessages );
347    if( peer->status > PEER_STATUS_IDLE )
348    {
349        tr_netClose( peer->socket );
350    }
351    tr_rcClose( peer->download );
352    tr_rcClose( peer->upload );
353    free( peer->client );
354
355    memset( peer, '\0', sizeof(tr_peer_t) );
356
357    free( peer );
358}
359
360const char *
361tr_peerClient( tr_peer_t * peer )
362{
363    if( PEER_STATUS_HANDSHAKE >= peer->status )
364    {
365        return "not connected";
366    }
367
368    if( NULL == peer->client )
369    {
370        peer->client = tr_clientForId( peer->id );
371    }
372
373    return peer->client;
374}
375
376void tr_peerSetPrivate( tr_peer_t * peer, int private )
377{
378    if( peer->private == private )
379    {
380        return;
381    }
382
383    peer->private = private;
384
385    if( !private )
386    {
387        peer->lastPex = 0;
388    }
389
390    if( EXTENDED_HANDSHAKE == peer->extStatus )
391    {
392        sendExtended( peer->tor, peer, EXTENDED_HANDSHAKE_ID );
393    }
394}
395
396void tr_peerSetTorrent( tr_peer_t * peer, tr_torrent_t * tor )
397{
398    peer->tor = tor;
399}
400
401/***********************************************************************
402 * tr_peerRead
403 ***********************************************************************
404 *
405 **********************************************************************/
406int tr_peerRead( tr_peer_t * peer )
407{
408    tr_torrent_t * tor = peer->tor;
409    int ret;
410    uint64_t date;
411
412    /* Try to read */
413    for( ;; )
414    {
415        if( tor )
416        {
417            int canDL;
418            switch( tor->downloadLimitMode ) {
419                case TR_SPEEDLIMIT_GLOBAL:
420                    canDL = !tor->handle->useDownloadLimit ||
421                             tr_rcCanTransfer( tor->handle->download ); break;
422                case TR_SPEEDLIMIT_SINGLE:
423                    canDL = tr_rcCanTransfer( tor->download ); break;
424                default: /* unlimited */
425                    canDL = TRUE;
426            }
427            if( !canDL )
428                break;
429        }
430
431        if( peer->size < 1 )
432        {
433            peer->size = 1024;
434            peer->buf  = malloc( peer->size );
435        }
436        else if( peer->pos >= peer->size )
437        {
438            peer->size *= 2;
439            peer->buf   = realloc( peer->buf, peer->size );
440        }
441
442        /* Read in smallish chunks, otherwise we might read more
443         * than the download cap is supposed to allow us */
444        ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
445                          MIN( 1024, peer->size - peer->pos ) ); 
446
447        if( ret & TR_NET_CLOSE )
448        {
449            peer_dbg( "connection closed" );
450            return TR_ERROR;
451        }
452        else if( ret & TR_NET_BLOCK )
453        {
454            break;
455        }
456        date        = tr_date();
457        peer->date  = date;
458        peer->pos  += ret;
459        if( NULL != tor )
460        {
461            if( peer->isInteresting && !peer->isChokingUs )
462            {
463                tor->activityDate = date;
464            }
465           
466            if( ( ret = parseBuf( tor, peer ) ) )
467            {
468                return ret;
469            }
470        }
471        else
472        {
473            if( ( ret = parseBufHeader( peer ) ) )
474            {
475                return ret;
476            }
477        }
478    }
479
480    return TR_OK;
481}
482
483uint64_t tr_peerDate( const tr_peer_t * peer )
484{
485    return peer->date;
486}
487
488/***********************************************************************
489 * tr_peerAddress
490 ***********************************************************************
491 *
492 **********************************************************************/
493struct in_addr * tr_peerAddress( tr_peer_t * peer )
494{
495    return &peer->addr;
496}
497
498/***********************************************************************
499 * tr_peerHash
500 ***********************************************************************
501 *
502 **********************************************************************/
503const uint8_t * tr_peerHash( const tr_peer_t * peer )
504{
505    return parseBufHash( peer );
506}
507
508/***********************************************************************
509 * tr_peerPulse
510 ***********************************************************************
511 *
512 **********************************************************************/
513int tr_peerPulse( tr_peer_t * peer )
514{
515    tr_torrent_t * tor = peer->tor;
516    int ret, size;
517    uint8_t * p;
518    uint64_t date;
519    int isSeeding;
520
521    assert( peer != NULL );
522    assert( peer->tor != NULL );
523
524    isSeeding = tr_cpGetStatus( tor->completion ) != TR_CP_INCOMPLETE;
525
526    if( ( ret = checkPeer( peer ) ) )
527    {
528        return ret;
529    }
530
531    /* Connect */
532    if( PEER_STATUS_IDLE == peer->status )
533    {
534        peer->socket = tr_netOpenTCP( &peer->addr, peer->port, 0 );
535        if( peer->socket < 0 )
536        {
537            return TR_ERROR;
538        }
539        peer->status = PEER_STATUS_CONNECTING;
540    }
541   
542    /* Disconnect if seeder and torrent is seeding */
543    if(   ( peer->progress >= 1.0 )
544       && ( peer->tor->cpStatus != TR_CP_INCOMPLETE ) )
545    {
546        return TR_ERROR;
547    }
548
549    /* Try to send handshake */
550    if( PEER_STATUS_CONNECTING == peer->status )
551    {
552        uint8_t buf[HANDSHAKE_SIZE];
553        const tr_info_t * inf;
554
555        inf = tr_torrentInfo( tor );
556        assert( 68 == HANDSHAKE_SIZE );
557        memcpy( buf, HANDSHAKE_NAME, HANDSHAKE_NAME_LEN );
558        memset( buf + HANDSHAKE_FLAGS_OFF, 0, HANDSHAKE_FLAGS_LEN );
559        HANDSHAKE_SET_EXTMSGS( buf + HANDSHAKE_FLAGS_OFF );
560        HANDSHAKE_SET_AZPROTO( buf + HANDSHAKE_FLAGS_OFF );
561        memcpy( buf + HANDSHAKE_HASH_OFF, inf->hash, SHA_DIGEST_LENGTH );
562        memcpy( buf + HANDSHAKE_PEERID_OFF, tor->peer_id, TR_ID_LEN );
563
564        switch( tr_netSend( peer->socket, buf, 68 ) )
565        {
566            case HANDSHAKE_SIZE:
567                peer_dbg( "SEND handshake" );
568                peer->status = PEER_STATUS_HANDSHAKE;
569                break;
570            case TR_NET_BLOCK:
571                break;
572            default:
573                peer_dbg( "connection closed" );
574                return TR_ERROR;
575        }
576    }
577    if( peer->status < PEER_STATUS_HANDSHAKE )
578    {
579        /* Nothing more we can do till we sent the handshake */
580        return TR_OK;
581    }
582
583    /* Read incoming messages */
584    if( ( ret = tr_peerRead( peer ) ) )
585    {
586        return ret;
587    }
588
589    /* Try to send Azureus handshake */
590    if( PEER_STATUS_AZ_GIVER == peer->status )
591    {
592        switch( sendAZHandshake( tor, peer ) )
593        {
594            case TR_NET_BLOCK:
595                break;
596            case TR_NET_CLOSE:
597                peer_dbg( "connection closed" );
598                return TR_ERROR;
599            default:
600                peer->status = PEER_STATUS_AZ_RECEIVER;
601                break;
602        }
603    }
604
605    if( peer->status < PEER_STATUS_CONNECTED )
606    {
607        /* Nothing more we can do till we got the other guy's handshake */
608        return TR_OK;
609    }
610
611    /* Try to write */
612writeBegin:
613
614    /* Send all smaller messages regardless of the upload cap */
615    while( ( p = messagesPending( peer, &size ) ) )
616    {
617        ret = tr_netSend( peer->socket, p, size );
618        if( ret & TR_NET_CLOSE )
619        {
620            return TR_ERROR;
621        }
622        else if( ret & TR_NET_BLOCK )
623        {
624            goto writeEnd;
625        }
626        messagesSent( peer, ret );
627    }
628
629    /* Send pieces if we can */
630    while( ( p = blockPending( tor, peer, &size ) ) )
631    {
632        int canUL;
633
634        if( SWIFT_ENABLED && !isSeeding && (peer->credit<0) )
635            canUL = FALSE;
636        else switch( tor->uploadLimitMode )
637        {
638            case TR_SPEEDLIMIT_GLOBAL:
639                canUL = !tor->handle->useUploadLimit ||
640                         tr_rcCanTransfer( tor->handle->upload ); break;
641
642            case TR_SPEEDLIMIT_SINGLE:
643                canUL = tr_rcCanTransfer( tor->upload ); break;
644
645            default: /* unlimited */
646                canUL = TRUE;
647        }
648        if( !canUL )
649            break;
650
651        ret = tr_netSend( peer->socket, p, size );
652        if( ret & TR_NET_CLOSE )
653            return TR_ERROR;
654
655        if( ret & TR_NET_BLOCK )
656            break;
657
658        blockSent( peer, ret );
659
660        if( ret > 0 )
661            tr_peerGotBlockFromUs( peer, ret );
662
663        date              = tr_date();
664        peer->outDate     = date;
665       
666        if( !tr_peerIsChokedByUs( peer ) )
667            tor->activityDate = date;
668
669        /* In case this block is done, you may have messages
670           pending. Send them before we start the next block */
671        goto writeBegin;
672    }
673writeEnd:
674
675    /* Ask for a block whenever possible */
676    if( !isSeeding
677        && !peer->isInteresting
678        && tor->peerCount > TR_MAX_PEER_COUNT - 2 )
679    {
680        /* This peer is no use to us, and it seems there are
681           more */
682        peer_dbg( "not interesting" );
683        return TR_ERROR;
684    }
685
686    if(     peer->isInteresting
687        && !peer->isChokingUs
688        && !peer->banned
689        &&  peer->inRequestCount < peer->inRequestMax )
690    {
691        int poolSize = 0;
692        int endgame = FALSE;
693        int openSlots = peer->inRequestMax - peer->inRequestCount;
694        int * pool = getPreferredPieces ( tor, peer, &poolSize, &endgame );
695
696        if( !endgame )
697        {
698            /* pool is sorted from most to least desirable pieces,
699               so work our way through starting at beginning */
700            int p;
701            for( p=0; p<poolSize && openSlots>0; )
702            {
703                const int piece = pool[p];
704                const int block = tr_cpMissingBlockInPiece ( tor->completion, piece );
705                if( block < 0 )
706                    ++p;
707                else { 
708                    sendRequest( tor, peer, block );
709                    --openSlots;
710                }
711            }
712        }
713        else
714        {
715            /* During endgame we remove the constraint of not asking for
716               pieces we've already requested from a different peer.
717               So if we follow the non-endgame approach of walking through
718               [0..poolCount) we'll bog down asking all peers for 1, then
719               all peers for 2, and so on.  Randomize our starting point
720               into "pool" to reduce such overlap */
721            int piecesLeft = poolSize;
722            int p = piecesLeft ? tr_rand(piecesLeft) : 0;
723            for( ; openSlots>0 && piecesLeft>0; --piecesLeft, p=(p+1)%poolSize )
724            {
725                const int piece = pool[p]; 
726                const int firstBlock = tr_torPieceFirstBlock( tor, piece );
727                const int n = tr_torPieceCountBlocks( tor, piece );
728                const int end = firstBlock + n;
729                int block;
730                for( block=firstBlock; openSlots>0 && block<end; ++block )
731                {
732                    /* don't ask for it if we've already got it */
733                    if( tr_cpBlockIsComplete( tor->completion, block ))
734                        continue;
735
736                    /* don't ask for it twice from the same peer */
737                    if( tr_bitfieldHas( peer->reqfield, block ) )
738                        continue;
739
740                    /* ask peer for the piece */
741                    if( !peer->reqfield )
742                         peer->reqfield = tr_bitfieldNew( tor->blockCount );
743                    tr_bitfieldAdd( peer->reqfield, block );
744                    sendRequest( tor, peer, block );
745                    --openSlots;
746                }
747            }
748        }
749
750        tr_free( pool );
751    }
752
753    assert( peer->inRequestCount <= peer->inRequestAlloc );
754    assert( peer->inRequestMax <= peer->inRequestAlloc );
755
756    return TR_OK;
757}
758
759int tr_peerIsConnected( const tr_peer_t * peer )
760{
761    return peer && (peer->status == PEER_STATUS_CONNECTED);
762}
763
764int tr_peerIsFrom( const tr_peer_t * peer )
765{
766    return peer->from;
767}
768
769int tr_peerIsChokedByUs( const tr_peer_t * peer )
770{
771    return peer->isChokedByUs;
772}
773int tr_peerIsInteresting( const tr_peer_t * peer )
774{
775    return peer->isInteresting;
776}
777int tr_peerIsChokingUs( const tr_peer_t * peer )
778{
779    return peer->isChokingUs;
780}
781int tr_peerIsInterested( const tr_peer_t * peer )
782{
783    return peer->isInterested;
784}
785
786float tr_peerProgress( const tr_peer_t * peer )
787{
788    return peer->progress;
789}
790
791int tr_peerPort( const tr_peer_t * peer )
792{
793    return ntohs( peer->port );
794}
795
796int tr_peerHasPiece( const tr_peer_t * peer, int pieceIndex )
797{
798    return tr_bitfieldHas( peer->bitfield, pieceIndex );
799}
800
801float tr_peerDownloadRate( const tr_peer_t * peer )
802{
803    return tr_rcRate( peer->download );
804}
805
806float tr_peerUploadRate( const tr_peer_t * peer )
807{
808    return tr_rcRate( peer->upload );
809}
810
811int tr_peerTimesChoked( const tr_peer_t * peer )
812{
813    return peer->timesChoked;
814}
815
816void tr_peerChoke( tr_peer_t * peer )
817{
818    sendChoke( peer, 1 );
819    peer->lastChoke = tr_date();
820    ++peer->timesChoked;
821}
822
823void tr_peerUnchoke( tr_peer_t * peer )
824{
825    sendChoke( peer, 0 );
826    peer->lastChoke = tr_date();
827}
828
829uint64_t tr_peerLastChoke( const tr_peer_t * peer )
830{
831    return peer->lastChoke;
832}
833
834void tr_peerSetOptimistic( tr_peer_t * peer, int o )
835{
836    peer->optimistic = o;
837}
838
839int tr_peerIsOptimistic( const tr_peer_t * peer )
840{
841    return peer->optimistic;
842}
843
844static int peerIsBad( const tr_peer_t * peer )
845{
846    return peer->badPcs > 4 + 2 * peer->goodPcs;
847}
848
849static int peerIsGood( const tr_peer_t * peer )
850{
851    return peer->goodPcs > 3 * peer->badPcs;
852}
853
854void tr_peerBlame( tr_peer_t * peer, int piece, int success )
855{
856    tr_torrent_t * tor = peer->tor;
857
858    if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
859    {
860        return;
861    }
862
863    if( success )
864    {
865        peer->goodPcs++;
866
867        if( peer->banfield && peerIsGood( peer ) )
868        {
869            /* Assume the peer wasn't responsible for the bad pieces
870               we was banned for */
871            tr_bitfieldClear( peer->banfield );
872        }
873    }
874    else
875    {
876        peer->badPcs++;
877
878        /* Ban the peer for this piece */
879        if( !peer->banfield )
880        {
881            peer->banfield = tr_bitfieldNew( tor->info.pieceCount );
882        }
883        tr_bitfieldAdd( peer->banfield, piece );
884
885        if( peerIsBad( peer ) )
886        {
887            /* Full ban */
888            peer_dbg( "banned (%d / %d)", peer->goodPcs, peer->badPcs );
889            peer->banned = TRUE;
890            peer->isInteresting = FALSE;
891            peer->isInterested = FALSE;
892        }
893    }
894    tr_bitfieldRem( peer->blamefield, piece );
895}
896
897int tr_peerGetConnectable( const tr_torrent_t * tor, uint8_t ** _buf )
898{
899    int count = 0;
900    uint8_t * buf;
901    tr_peer_t * peer;
902    int i;
903
904    if( tor->peerCount < 1 )
905    {
906        *_buf = NULL;
907        return 0;
908    }
909
910    buf = malloc( 6 * tor->peerCount );
911    for( i = 0; i < tor->peerCount; i++ )
912    {
913        peer = tor->peers[i];
914
915        /* Skip peers with no known listening port */
916        if( 0 == peer->port )
917            continue;
918
919        memcpy( &buf[count*6], &peer->addr, 4 );
920        memcpy( &buf[count*6+4], &peer->port, 2 );
921        count++;
922    }
923
924    if( count < 1 )
925    {
926        free( buf ); buf = NULL;
927    }
928    *_buf = buf;
929
930    return count * 6;
931}
932
933/***
934****
935***/
936
937void
938tr_peerSentBlockToUs ( tr_peer_t * peer, int byteCount )
939{
940    tr_torrent_t * tor = peer->tor;
941
942    assert( byteCount >= 0 );
943    assert( byteCount <= tor->info.pieceSize );
944
945    tor->downloadedCur += byteCount;
946    tr_rcTransferred( peer->download, byteCount );
947    tr_rcTransferred( tor->download, byteCount );
948    tr_rcTransferred( tor->handle->download, byteCount );
949
950    peer->credit += (int)(byteCount * SWIFT_REPAYMENT_RATIO);
951}
952
953void
954tr_peerGotBlockFromUs ( tr_peer_t * peer, int byteCount )
955{
956    tr_torrent_t * tor = peer->tor;
957
958    assert( byteCount >= 0 );
959    assert( byteCount <= tor->info.pieceSize );
960
961    tor->uploadedCur += byteCount;
962    tr_rcTransferred( peer->upload, byteCount );
963    tr_rcTransferred( tor->upload, byteCount );
964    tr_rcTransferred( tor->handle->upload, byteCount );
965
966    peer->credit -= byteCount;
967}
968
969static void
970tr_torrentSwiftPulse ( tr_torrent_t * tor )
971{
972    /* Preferred # of seconds for the request queue's turnaround time.
973       This is just an arbitrary number. */
974    const int queueTimeSec = 5;
975    const int blockSizeKiB = tor->blockSize / 1024;
976    const int isSeeding = tr_cpGetStatus( tor->completion ) != TR_CP_INCOMPLETE;
977    int i;
978
979    tr_torrentWriterLock( tor );
980
981    for( i=0; i<tor->peerCount; ++i )
982    {
983        double outboundSpeedKiBs;
984        int size;
985        tr_peer_t * peer = tor->peers[ i ];
986
987        if( !tr_peerIsConnected( peer ) )
988            continue;
989
990        /* decide how many blocks we'll concurrently ask this peer for */
991        outboundSpeedKiBs = tr_rcRate(peer->upload);
992        size = queueTimeSec * outboundSpeedKiBs / blockSizeKiB;
993        if( size < 4 ) /* don't let it get TOO small */
994            size = 4;
995        size += 4; /* and always leave room to grow */
996        peer->inRequestMax = size;
997        if( peer->inRequestAlloc < peer->inRequestMax ) {
998            peer->inRequestAlloc = peer->inRequestMax;
999            peer->inRequests = tr_renew( tr_request_t, peer->inRequests, peer->inRequestAlloc );
1000        }
1001    }
1002
1003    /* if we're not seeding, decide on how much
1004       bandwidth to allocate for leechers */
1005    if( !isSeeding )
1006    {
1007        tr_peer_t ** deadbeats = tr_new( tr_peer_t*, tor->peerCount );
1008        int deadbeatCount = 0;
1009
1010        for( i=0; i<tor->peerCount; ++i ) {
1011            tr_peer_t * peer = tor->peers[ i ];
1012            if( tr_peerIsConnected( peer ) && ( peer->credit < 0 ) )
1013                deadbeats[deadbeatCount++] = peer;
1014        }
1015
1016        if( deadbeatCount )
1017        {
1018            const double ul_KiBsec = tr_rcRate( tor->download );
1019            const double ul_KiB = ul_KiBsec * SWIFT_REFRESH_INTERVAL_SEC;
1020            const double ul_bytes = ul_KiB * 1024;
1021            const double freeCreditTotal = ul_bytes * SWIFT_LARGESSE;
1022            const int freeCreditPerPeer = (int)( freeCreditTotal / deadbeatCount );
1023            for( i=0; i<deadbeatCount; ++i )
1024                deadbeats[i]->credit = freeCreditPerPeer;
1025            tr_dbg( "torrent %s has %d deadbeats, "
1026                    "who are each being granted %d bytes' credit "
1027                    "for a total of %.1f KiB, "
1028                    "%d%% of the torrent's ul speed %.1f\n", 
1029                tor->info.name, deadbeatCount, freeCreditPerPeer,
1030                ul_KiBsec*SWIFT_LARGESSE, (int)(SWIFT_LARGESSE*100), ul_KiBsec );
1031        }
1032
1033        tr_free( deadbeats );
1034    }
1035
1036    tr_torrentWriterUnlock( tor );
1037}
1038void
1039tr_swiftPulse( tr_handle_t * h )
1040{
1041    static time_t lastPulseTime = 0;
1042
1043    if( lastPulseTime + SWIFT_REFRESH_INTERVAL_SEC <= time( NULL ) )
1044    {
1045        tr_torrent_t * tor;
1046        for( tor=h->torrentList; tor; tor=tor->next )
1047            tr_torrentSwiftPulse( tor );
1048
1049        lastPulseTime = time( NULL );
1050    }
1051}
Note: See TracBrowser for help on using the repository browser.