source: trunk/libtransmission/peer.c @ 2177

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

adding experimental implementation of Tamilmani's `Swift' tit-for-tat algorithm for testing. To tweak or disable, change the values around line 50 of libtransmission/peer.c

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