source: trunk/libtransmission/peer.c @ 2233

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

Fix endgame bug that caused the last 2-3% to drag out forever in recent nightlies. Thanks SoftwareElves?

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