source: trunk/libtransmission/peer.c @ 2339

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

fix bug that gave the wrong peer count when uploading.

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