source: trunk/libtransmission/peer.c @ 1579

Last change on this file since 1579 was 1579, checked in by joshe, 15 years ago

Merge PEX branch, I hope this works.

  • Property svn:keywords set to Date Rev Author Id
File size: 19.4 KB
Line 
1/******************************************************************************
2 * $Id: peer.c 1579 2007-03-23 08:28:01Z joshe $
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#define MAX_REQUEST_COUNT       32
29#define OUR_REQUEST_COUNT       8  /* TODO: we should detect if we are on a
30                                      high-speed network and adapt */
31#define PEX_PEER_CUTOFF         50 /* only try to add new peers from pex if
32                                      we have fewer existing peers than this */
33#define PEX_INTERVAL            60 /* don't send pex messages more frequently
34                                      than PEX_INTERVAL +
35                                      rand( PEX_INTERVAL / 10 ) seconds */
36#define PEER_SUPPORTS_EXTENDED_MESSAGES( bits ) ( (bits)[5] & 0x10 )
37#define PEER_SUPPORTS_AZUREUS_PROTOCOL( bits )  ( (bits)[0] & 0x80 )
38
39#define PEER_MSG_CHOKE          0
40#define PEER_MSG_UNCHOKE        1
41#define PEER_MSG_INTERESTED     2
42#define PEER_MSG_UNINTERESTED   3
43#define PEER_MSG_HAVE           4
44#define PEER_MSG_BITFIELD       5
45#define PEER_MSG_REQUEST        6
46#define PEER_MSG_PIECE          7
47#define PEER_MSG_CANCEL         8
48#define PEER_MSG_PORT           9
49#define PEER_MSG_EXTENDED       20
50
51typedef struct tr_request_s
52{
53    int index;
54    int begin;
55    int length;
56
57} tr_request_t;
58
59struct tr_peer_s
60{
61    tr_torrent_t      * tor;
62
63    struct in_addr      addr;
64    in_port_t           port;  /* peer's listening port, 0 if not known */
65
66#define PEER_STATUS_IDLE        1 /* Need to connect */
67#define PEER_STATUS_CONNECTING  2 /* Trying to send handshake */
68#define PEER_STATUS_HANDSHAKE   3 /* Waiting for peer's handshake */
69#define PEER_STATUS_AZ_GIVER    4 /* Sending Azureus handshake */
70#define PEER_STATUS_AZ_RECEIVER 5 /* Receiving Azureus handshake */
71#define PEER_STATUS_CONNECTED   6 /* Got peer's handshake */
72    int                 status;
73    int                 socket;
74    char                from;
75    char                private;
76    char                azproto;  /* azureus peer protocol is being used */
77    uint64_t            date;
78    uint64_t            keepAlive;
79
80#define EXTENDED_NOT_SUPPORTED   0 /* extended messages not supported */
81#define EXTENDED_SUPPORTED       1 /* waiting to send extended handshake */
82#define EXTENDED_HANDSHAKE       2 /* sent extended handshake */
83    uint8_t             extStatus;
84    uint8_t             pexStatus;   /* peer's ut_pex id, 0 if not supported */
85    uint64_t            lastPex;     /* time when last pex packet was sent */
86    int                 advertisedPort; /* listening port we last told peer */
87    tr_peertree_t       sentPeers;
88
89    char                amChoking;
90    char                amInterested;
91    char                peerChoking;
92    char                peerInterested;
93
94    int                 optimistic;
95    uint64_t            lastChoke;
96
97    uint8_t             id[20];
98
99    /* The pieces that the peer has */
100    tr_bitfield_t     * bitfield;
101    int                 pieceCount;
102    float               progress;
103
104    int                 goodPcs;
105    int                 badPcs;
106    int                 banned;
107    /* The pieces that the peer is contributing to */
108    tr_bitfield_t     * blamefield;
109    /* The bad pieces that the peer has contributed to */
110    tr_bitfield_t     * banfield;
111
112    uint8_t           * buf;
113    int                 size;
114    int                 pos;
115
116    uint8_t           * outMessages;
117    int                 outMessagesSize;
118    int                 outMessagesPos;
119    uint8_t             outBlock[13+16384];
120    int                 outBlockSize;
121    int                 outBlockLoaded;
122    int                 outBlockSending;
123
124    int                 inRequestCount;
125    tr_request_t        inRequests[OUR_REQUEST_COUNT];
126    int                 inIndex;
127    int                 inBegin;
128    int                 inLength;
129    uint64_t            inTotal;
130
131    int                 outRequestCount;
132    tr_request_t        outRequests[MAX_REQUEST_COUNT];
133    uint64_t            outTotal;
134    uint64_t            outDate;
135
136    tr_ratecontrol_t  * download;
137    tr_ratecontrol_t  * upload;
138};
139
140#define peer_dbg( a... ) __peer_dbg( peer, ## a )
141static void __peer_dbg( tr_peer_t * peer, char * msg, ... ) PRINTF( 2, 3 );
142
143static void __peer_dbg( tr_peer_t * peer, char * msg, ... )
144{
145    char    string[256];
146    va_list args;
147
148    va_start( args, msg );
149    snprintf( string, sizeof string, "%08x:%04x ",
150             (uint32_t) peer->addr.s_addr, peer->port );
151    vsnprintf( &string[14], sizeof( string ) - 14, msg, args );
152    va_end( args ); 
153
154    tr_dbg( "%s", string );
155}
156
157#include "peerext.h"
158#include "peeraz.h"
159#include "peermessages.h"
160#include "peerutils.h"
161#include "peerparse.h"
162
163/***********************************************************************
164 * tr_peerInit
165 ***********************************************************************
166 * Initializes a new peer.
167 **********************************************************************/
168tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s, int from )
169{
170    tr_peer_t * peer = peerInit();
171
172    assert( 0 <= from && TR_PEER_FROM__MAX > from );
173
174    peer->socket = s;
175    peer->addr = addr;
176    peer->port = port;
177    peer->from = from;
178    if( s >= 0 )
179    {
180        assert( TR_PEER_FROM_INCOMING == from );
181        peer->status = PEER_STATUS_CONNECTING;
182    }
183    else
184    {
185        peer->status = PEER_STATUS_IDLE;
186    }
187
188    return peer;
189}
190
191void tr_peerDestroy( tr_peer_t * peer )
192{
193    tr_torrent_t * tor = peer->tor;
194    tr_request_t * r;
195    int i, block;
196
197    peertreeFree( &peer->sentPeers );
198    for( i = 0; i < peer->inRequestCount; i++ )
199    {
200        r = &peer->inRequests[i];
201        block = tr_block( r->index, r->begin );
202        tr_cpDownloaderRem( tor->completion, block );
203    }
204    tr_bitfieldFree( peer->bitfield );
205    tr_bitfieldFree( peer->blamefield );
206    tr_bitfieldFree( peer->banfield );
207    if( peer->buf )
208    {
209        free( peer->buf );
210    }
211    if( peer->outMessages )
212    {
213        free( peer->outMessages );
214    }
215    if( peer->status > PEER_STATUS_IDLE )
216    {
217        tr_netClose( peer->socket );
218    }
219    tr_rcClose( peer->download );
220    tr_rcClose( peer->upload );
221    free( peer );
222}
223
224void tr_peerSetPrivate( tr_peer_t * peer, int private )
225{
226    peer->private = private;
227}
228
229void tr_peerSetTorrent( tr_peer_t * peer, tr_torrent_t * tor )
230{
231    peer->tor = tor;
232}
233
234/***********************************************************************
235 * tr_peerRead
236 ***********************************************************************
237 *
238 **********************************************************************/
239int tr_peerRead( tr_peer_t * peer )
240{
241    tr_torrent_t * tor = peer->tor;
242    int ret;
243
244    /* Try to read */
245    for( ;; )
246    {
247        if( tor )
248        {
249            if( tor->customDownloadLimit )
250            {
251                if( !tr_rcCanTransfer( tor->download ) )
252                {
253                    break;
254                }
255            }
256            else
257            {
258                tr_lockUnlock( &tor->lock );
259                if( !tr_rcCanGlobalTransfer( tor->handle, 0 ) )
260                {
261                    tr_lockLock( &tor->lock );
262                    break;
263                }
264                tr_lockLock( &tor->lock );
265            }
266        }
267
268        if( peer->size < 1 )
269        {
270            peer->size = 1024;
271            peer->buf  = malloc( peer->size );
272        }
273        else if( peer->pos >= peer->size )
274        {
275            peer->size *= 2;
276            peer->buf   = realloc( peer->buf, peer->size );
277        }
278        /* Never read more than 1K each time, otherwise the rate
279           control is no use */
280        ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
281                          MIN( 1024, peer->size - peer->pos ) );
282        if( ret & TR_NET_CLOSE )
283        {
284            peer_dbg( "connection closed" );
285            return TR_ERROR;
286        }
287        else if( ret & TR_NET_BLOCK )
288        {
289            break;
290        }
291        peer->date  = tr_date();
292        peer->pos  += ret;
293        if( NULL != tor )
294        {
295            tr_rcTransferred( peer->download, ret );
296            tr_rcTransferred( tor->download, ret );
297            if( ( ret = parseBuf( tor, peer ) ) )
298            {
299                return ret;
300            }
301        }
302        else
303        {
304            if( ( ret = parseBufHeader( peer ) ) )
305            {
306                return ret;
307            }
308        }
309    }
310
311    return TR_OK;
312}
313
314uint64_t tr_peerDate( tr_peer_t * peer )
315{
316    return peer->date;
317}
318
319/***********************************************************************
320 * tr_peerId
321 ***********************************************************************
322 *
323 **********************************************************************/
324uint8_t * tr_peerId( tr_peer_t * peer )
325{
326    return & peer->id[0];
327}
328
329/***********************************************************************
330 * tr_peerAddress
331 ***********************************************************************
332 *
333 **********************************************************************/
334struct in_addr * tr_peerAddress( tr_peer_t * peer )
335{
336    return &peer->addr;
337}
338
339/***********************************************************************
340 * tr_peerHash
341 ***********************************************************************
342 *
343 **********************************************************************/
344uint8_t * tr_peerHash( tr_peer_t * peer )
345{
346    return parseBufHash( peer );
347}
348
349/***********************************************************************
350 * tr_peerPulse
351 ***********************************************************************
352 *
353 **********************************************************************/
354int tr_peerPulse( tr_peer_t * peer )
355{
356    tr_torrent_t * tor = peer->tor;
357    int ret, size;
358    uint8_t * p;
359
360    if( ( ret = checkPeer( peer ) ) )
361    {
362        return ret;
363    }
364
365    /* Connect */
366    if( PEER_STATUS_IDLE == peer->status )
367    {
368        peer->socket = tr_netOpenTCP( peer->addr, peer->port, 0 );
369        if( peer->socket < 0 )
370        {
371            return TR_ERROR;
372        }
373        peer->status = PEER_STATUS_CONNECTING;
374    }
375
376    /* Try to send handshake */
377    if( PEER_STATUS_CONNECTING == peer->status )
378    {
379        uint8_t buf[68];
380        tr_info_t * inf = &tor->info;
381
382        buf[0] = 19;
383        memcpy( &buf[1], "BitTorrent protocol", 19 );
384        memset( &buf[20], 0, 8 );
385        buf[20] = 0x80;         /* azureus protocol */
386        buf[25] = 0x10;         /* extended messages */
387        memcpy( &buf[28], inf->hash, 20 );
388        memcpy( &buf[48], tor->id, 20 );
389
390        switch( tr_netSend( peer->socket, buf, 68 ) )
391        {
392            case 68:
393                peer_dbg( "SEND handshake" );
394                peer->status = PEER_STATUS_HANDSHAKE;
395                break;
396            case TR_NET_BLOCK:
397                break;
398            default:
399                peer_dbg( "connection closed" );
400                return TR_ERROR;
401        }
402    }
403    if( peer->status < PEER_STATUS_HANDSHAKE )
404    {
405        /* Nothing more we can do till we sent the handshake */
406        return TR_OK;
407    }
408
409    /* Read incoming messages */
410    if( ( ret = tr_peerRead( peer ) ) )
411    {
412        return ret;
413    }
414
415    /* Try to send Azureus handshake */
416    if( PEER_STATUS_AZ_GIVER == peer->status )
417    {
418        switch( sendAZHandshake( tor, peer ) )
419        {
420            case TR_NET_BLOCK:
421                break;
422            case TR_NET_CLOSE:
423                peer_dbg( "connection closed" );
424                return TR_ERROR;
425            default:
426                peer->status = PEER_STATUS_AZ_RECEIVER;
427                break;
428        }
429    }
430
431    if( peer->status < PEER_STATUS_CONNECTED )
432    {
433        /* Nothing more we can do till we got the other guy's handshake */
434        return TR_OK;
435    }
436
437    /* Try to write */
438writeBegin:
439
440    /* Send all smaller messages regardless of the upload cap */
441    while( ( p = messagesPending( peer, &size ) ) )
442    {
443        ret = tr_netSend( peer->socket, p, size );
444        if( ret & TR_NET_CLOSE )
445        {
446            return TR_ERROR;
447        }
448        else if( ret & TR_NET_BLOCK )
449        {
450            goto writeEnd;
451        }
452        messagesSent( peer, ret );
453    }
454
455    /* Send pieces if we can */
456    while( ( p = blockPending( tor, peer, &size ) ) )
457    {
458        if( tor->customUploadLimit )
459        {
460            if( !tr_rcCanTransfer( tor->upload ) )
461            {
462                break;
463            }
464        }
465        else
466        {
467            tr_lockUnlock( &tor->lock );
468            if( !tr_rcCanGlobalTransfer( tor->handle, 1 ) )
469            {
470                tr_lockLock( &tor->lock );
471                break;
472            }
473            tr_lockLock( &tor->lock );
474        }
475
476        ret = tr_netSend( peer->socket, p, size );
477        if( ret & TR_NET_CLOSE )
478        {
479            return TR_ERROR;
480        }
481        else if( ret & TR_NET_BLOCK )
482        {
483            break;
484        }
485
486        blockSent( peer, ret );
487        tr_rcTransferred( peer->upload, ret );
488        tr_rcTransferred( tor->upload, ret );
489
490        tor->uploadedCur += ret;
491        peer->outTotal   += ret;
492        peer->outDate     = tr_date();
493
494        /* In case this block is done, you may have messages
495           pending. Send them before we start the next block */
496        goto writeBegin;
497    }
498writeEnd:
499
500    /* Ask for a block whenever possible */
501    if( !tr_cpIsSeeding( tor->completion ) &&
502        !peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 )
503    {
504        /* This peer is no use to us, and it seems there are
505           more */
506        peer_dbg( "not interesting" );
507        return TR_ERROR;
508    }
509
510    if( peer->amInterested && !peer->peerChoking && !peer->banned )
511    {
512        int block;
513        while( peer->inRequestCount < OUR_REQUEST_COUNT )
514        {
515            block = chooseBlock( tor, peer );
516            if( block < 0 )
517            {
518                break;
519            }
520            sendRequest( tor, peer, block );
521        }
522    }
523
524    return TR_OK;
525}
526
527/***********************************************************************
528 * tr_peerIsConnected
529 ***********************************************************************
530 *
531 **********************************************************************/
532int tr_peerIsConnected( tr_peer_t * peer )
533{
534    return PEER_STATUS_CONNECTED == peer->status;
535}
536
537/***********************************************************************
538 * tr_peerIsIncoming
539 ***********************************************************************
540 *
541 **********************************************************************/
542int tr_peerIsFrom( tr_peer_t * peer )
543{
544    return peer->from;
545}
546
547int tr_peerAmChoking( tr_peer_t * peer )
548{
549    return peer->amChoking;
550}
551int tr_peerAmInterested( tr_peer_t * peer )
552{
553    return peer->amInterested;
554}
555int tr_peerIsChoking( tr_peer_t * peer )
556{
557    return peer->peerChoking;
558}
559int tr_peerIsInterested( tr_peer_t * peer )
560{
561    return peer->peerInterested;
562}
563
564/***********************************************************************
565 * tr_peerProgress
566 ***********************************************************************
567 *
568 **********************************************************************/
569float tr_peerProgress( tr_peer_t * peer )
570{
571    return peer->progress;
572}
573
574/***********************************************************************
575 * tr_peerPort
576 ***********************************************************************
577 * Returns peer's listening port in host byte order
578 **********************************************************************/
579int tr_peerPort( tr_peer_t * peer )
580{
581    return ntohs( peer->port );
582}
583
584/***********************************************************************
585 * tr_peerBitfield
586 ***********************************************************************
587 *
588 **********************************************************************/
589tr_bitfield_t * tr_peerBitfield( tr_peer_t * peer )
590{
591    return peer->bitfield;
592}
593
594float tr_peerDownloadRate( tr_peer_t * peer )
595{
596    return tr_rcRate( peer->download );
597}
598
599float tr_peerUploadRate( tr_peer_t * peer )
600{
601    return tr_rcRate( peer->upload );
602}
603
604void tr_peerChoke( tr_peer_t * peer )
605{
606    sendChoke( peer, 1 );
607    peer->lastChoke = tr_date();
608}
609
610void tr_peerUnchoke( tr_peer_t * peer )
611{
612    sendChoke( peer, 0 );
613    peer->lastChoke = tr_date();
614}
615
616uint64_t tr_peerLastChoke( tr_peer_t * peer )
617{
618    return peer->lastChoke;
619}
620
621void tr_peerSetOptimistic( tr_peer_t * peer, int o )
622{
623    peer->optimistic = o;
624}
625
626int tr_peerIsOptimistic( tr_peer_t * peer )
627{
628    return peer->optimistic;
629}
630
631static inline int peerIsBad( tr_peer_t * peer )
632{
633    return ( peer->badPcs > 4 + 2 * peer->goodPcs );
634}
635
636static inline int peerIsGood( tr_peer_t * peer )
637{
638    return ( peer->goodPcs > 3 * peer->badPcs );
639}
640
641void tr_peerBlame( tr_peer_t * peer, int piece, int success )
642{
643    tr_torrent_t * tor = peer->tor;
644
645    if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
646    {
647        return;
648    }
649
650    if( success )
651    {
652        peer->goodPcs++;
653
654        if( peer->banfield && peerIsGood( peer ) )
655        {
656            /* Assume the peer wasn't responsible for the bad pieces
657               we was banned for */
658            tr_bitfieldClear( peer->banfield );
659        }
660    }
661    else
662    {
663        peer->badPcs++;
664
665        /* Ban the peer for this piece */
666        if( !peer->banfield )
667        {
668            peer->banfield = tr_bitfieldNew( tor->info.pieceCount );
669        }
670        tr_bitfieldAdd( peer->banfield, piece );
671
672        if( peerIsBad( peer ) )
673        {
674            /* Full ban */
675            peer_dbg( "banned (%d / %d)", peer->goodPcs, peer->badPcs );
676            peer->banned = 1;
677            peer->peerInterested = 0;
678        }
679    }
680    tr_bitfieldRem( peer->blamefield, piece );
681}
682
683int tr_peerGetConnectable( tr_torrent_t * tor, uint8_t ** _buf )
684{
685    int count = 0;
686    uint8_t * buf;
687    tr_peer_t * peer;
688    int i;
689
690    if( tor->peerCount < 1 )
691    {
692        *_buf = NULL;
693        return 0;
694    }
695
696    buf = malloc( 6 * tor->peerCount );
697    for( i = 0; i < tor->peerCount; i++ )
698    {
699        peer = tor->peers[i];
700
701        /* Skip peers with no known listening port */
702        if( 0 == peer->port )
703            continue;
704
705        memcpy( &buf[count*6], &peer->addr, 4 );
706        memcpy( &buf[count*6+4], &peer->port, 2 );
707        count++;
708    }
709
710    if( count < 1 )
711    {
712        free( buf ); buf = NULL;
713    }
714    *_buf = buf;
715
716    return count * 6;
717}
Note: See TracBrowser for help on using the repository browser.