source: trunk/libtransmission/peer.c @ 2746

Last change on this file since 2746 was 2746, checked in by charles, 15 years ago

make list less error-prone by changing the API s.t. we're guaranteed to update the list's pointer correctly.

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