source: trunk/libtransmission/peer.c @ 2544

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

this looks bug but it's not: just janitorial cleanup, moving #includes from headers into source file

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