source: branches/daemon/libtransmission/peer.c @ 1712

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

Merge libT revs 1616:1711 from trunk to daemon branch.

  • Property svn:keywords set to Date Rev Author Id
File size: 20.0 KB
Line 
1/******************************************************************************
2 * $Id: peer.c 1712 2007-04-14 06:34:52Z 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[TR_ID_LEN];
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[25+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    char              * client;
140};
141
142#define peer_dbg( a... ) __peer_dbg( peer, ## a )
143static void __peer_dbg( tr_peer_t * peer, char * msg, ... ) PRINTF( 2, 3 );
144
145static void __peer_dbg( tr_peer_t * peer, char * msg, ... )
146{
147    char    string[256];
148    va_list args;
149
150    va_start( args, msg );
151    snprintf( string, sizeof string, "%08x:%04x ",
152             (uint32_t) peer->addr.s_addr, peer->port );
153    vsnprintf( &string[14], sizeof( string ) - 14, msg, args );
154    va_end( args ); 
155
156    tr_dbg( "%s", string );
157}
158
159#include "peerext.h"
160#include "peeraz.h"
161#include "peermessages.h"
162#include "peerutils.h"
163#include "peerparse.h"
164
165/***********************************************************************
166 * tr_peerInit
167 ***********************************************************************
168 * Initializes a new peer.
169 **********************************************************************/
170tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s, int from )
171{
172    tr_peer_t * peer = peerInit();
173
174    assert( 0 <= from && TR_PEER_FROM__MAX > from );
175
176    peer->socket = s;
177    peer->addr = addr;
178    peer->port = port;
179    peer->from = from;
180    if( s >= 0 )
181    {
182        assert( TR_PEER_FROM_INCOMING == from );
183        peer->status = PEER_STATUS_CONNECTING;
184    }
185    else
186    {
187        peer->status = PEER_STATUS_IDLE;
188    }
189
190    return peer;
191}
192
193void tr_peerDestroy( tr_peer_t * peer )
194{
195    tr_torrent_t * tor = peer->tor;
196    tr_request_t * r;
197    int i, block;
198
199    peertreeFree( &peer->sentPeers );
200    for( i = 0; i < peer->inRequestCount; i++ )
201    {
202        r = &peer->inRequests[i];
203        block = tr_block( r->index, r->begin );
204        tr_cpDownloaderRem( tor->completion, block );
205    }
206    tr_bitfieldFree( peer->bitfield );
207    tr_bitfieldFree( peer->blamefield );
208    tr_bitfieldFree( peer->banfield );
209    if( peer->buf )
210    {
211        free( peer->buf );
212    }
213    if( peer->outMessages )
214    {
215        free( peer->outMessages );
216    }
217    if( peer->status > PEER_STATUS_IDLE )
218    {
219        tr_netClose( peer->socket );
220    }
221    tr_rcClose( peer->download );
222    tr_rcClose( peer->upload );
223    free( peer->client );
224    free( peer );
225}
226
227const char *
228tr_peerClient( tr_peer_t * peer )
229{
230    if( PEER_STATUS_HANDSHAKE >= peer->status )
231    {
232        return "not connected";
233    }
234
235    if( NULL == peer->client )
236    {
237        peer->client = tr_clientForId( peer->id );
238    }
239
240    return peer->client;
241}
242
243void tr_peerSetPrivate( tr_peer_t * peer, int private )
244{
245    if( peer->private == private )
246    {
247        return;
248    }
249
250    peer->private = private;
251
252    if( !private )
253    {
254        peer->lastPex = 0;
255    }
256
257    if( EXTENDED_HANDSHAKE == peer->extStatus )
258    {
259        sendExtended( peer->tor, peer, EXTENDED_HANDSHAKE_ID );
260    }
261}
262
263void tr_peerSetTorrent( tr_peer_t * peer, tr_torrent_t * tor )
264{
265    peer->tor = tor;
266}
267
268/***********************************************************************
269 * tr_peerRead
270 ***********************************************************************
271 *
272 **********************************************************************/
273int tr_peerRead( tr_peer_t * peer )
274{
275    tr_torrent_t * tor = peer->tor;
276    int ret;
277
278    /* Try to read */
279    for( ;; )
280    {
281        if( tor )
282        {
283            if( tor->customDownloadLimit )
284            {
285                if( !tr_rcCanTransfer( tor->download ) )
286                {
287                    break;
288                }
289            }
290            else
291            {
292                tr_lockUnlock( &tor->lock );
293                if( !tr_rcCanGlobalTransfer( tor->handle, 0 ) )
294                {
295                    tr_lockLock( &tor->lock );
296                    break;
297                }
298                tr_lockLock( &tor->lock );
299            }
300        }
301
302        if( peer->size < 1 )
303        {
304            peer->size = 1024;
305            peer->buf  = malloc( peer->size );
306        }
307        else if( peer->pos >= peer->size )
308        {
309            peer->size *= 2;
310            peer->buf   = realloc( peer->buf, peer->size );
311        }
312        /* Never read more than 1K each time, otherwise the rate
313           control is no use */
314        ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
315                          MIN( 1024, peer->size - peer->pos ) );
316        if( ret & TR_NET_CLOSE )
317        {
318            peer_dbg( "connection closed" );
319            return TR_ERROR;
320        }
321        else if( ret & TR_NET_BLOCK )
322        {
323            break;
324        }
325        peer->date  = tr_date();
326        peer->pos  += ret;
327        if( NULL != tor )
328        {
329            tr_rcTransferred( peer->download, ret );
330            tr_rcTransferred( tor->download, ret );
331            if( ( ret = parseBuf( tor, peer ) ) )
332            {
333                return ret;
334            }
335        }
336        else
337        {
338            if( ( ret = parseBufHeader( peer ) ) )
339            {
340                return ret;
341            }
342        }
343    }
344
345    return TR_OK;
346}
347
348uint64_t tr_peerDate( tr_peer_t * peer )
349{
350    return peer->date;
351}
352
353/***********************************************************************
354 * tr_peerId
355 ***********************************************************************
356 *
357 **********************************************************************/
358uint8_t * tr_peerId( tr_peer_t * peer )
359{
360    return & peer->id[0];
361}
362
363/***********************************************************************
364 * tr_peerAddress
365 ***********************************************************************
366 *
367 **********************************************************************/
368struct in_addr * tr_peerAddress( tr_peer_t * peer )
369{
370    return &peer->addr;
371}
372
373/***********************************************************************
374 * tr_peerHash
375 ***********************************************************************
376 *
377 **********************************************************************/
378uint8_t * tr_peerHash( tr_peer_t * peer )
379{
380    return parseBufHash( peer );
381}
382
383/***********************************************************************
384 * tr_peerPulse
385 ***********************************************************************
386 *
387 **********************************************************************/
388int tr_peerPulse( tr_peer_t * peer )
389{
390    tr_torrent_t * tor = peer->tor;
391    int ret, size;
392    uint8_t * p;
393
394    if( ( ret = checkPeer( peer ) ) )
395    {
396        return ret;
397    }
398
399    /* Connect */
400    if( PEER_STATUS_IDLE == peer->status )
401    {
402        peer->socket = tr_netOpenTCP( peer->addr, peer->port, 0 );
403        if( peer->socket < 0 )
404        {
405            return TR_ERROR;
406        }
407        peer->status = PEER_STATUS_CONNECTING;
408    }
409
410    /* Try to send handshake */
411    if( PEER_STATUS_CONNECTING == peer->status )
412    {
413        uint8_t buf[68];
414        tr_info_t * inf = &tor->info;
415
416        buf[0] = 19;
417        memcpy( &buf[1], "BitTorrent protocol", 19 );
418        memset( &buf[20], 0, 8 );
419        buf[20] = 0x80;         /* azureus protocol */
420        buf[25] = 0x10;         /* extended messages */
421        memcpy( &buf[28], inf->hash, 20 );
422        memcpy( &buf[48], tor->id, 20 );
423
424        switch( tr_netSend( peer->socket, buf, 68 ) )
425        {
426            case 68:
427                peer_dbg( "SEND handshake" );
428                peer->status = PEER_STATUS_HANDSHAKE;
429                break;
430            case TR_NET_BLOCK:
431                break;
432            default:
433                peer_dbg( "connection closed" );
434                return TR_ERROR;
435        }
436    }
437    if( peer->status < PEER_STATUS_HANDSHAKE )
438    {
439        /* Nothing more we can do till we sent the handshake */
440        return TR_OK;
441    }
442
443    /* Read incoming messages */
444    if( ( ret = tr_peerRead( peer ) ) )
445    {
446        return ret;
447    }
448
449    /* Try to send Azureus handshake */
450    if( PEER_STATUS_AZ_GIVER == peer->status )
451    {
452        switch( sendAZHandshake( tor, peer ) )
453        {
454            case TR_NET_BLOCK:
455                break;
456            case TR_NET_CLOSE:
457                peer_dbg( "connection closed" );
458                return TR_ERROR;
459            default:
460                peer->status = PEER_STATUS_AZ_RECEIVER;
461                break;
462        }
463    }
464
465    if( peer->status < PEER_STATUS_CONNECTED )
466    {
467        /* Nothing more we can do till we got the other guy's handshake */
468        return TR_OK;
469    }
470
471    /* Try to write */
472writeBegin:
473
474    /* Send all smaller messages regardless of the upload cap */
475    while( ( p = messagesPending( peer, &size ) ) )
476    {
477        ret = tr_netSend( peer->socket, p, size );
478        if( ret & TR_NET_CLOSE )
479        {
480            return TR_ERROR;
481        }
482        else if( ret & TR_NET_BLOCK )
483        {
484            goto writeEnd;
485        }
486        messagesSent( peer, ret );
487    }
488
489    /* Send pieces if we can */
490    while( ( p = blockPending( tor, peer, &size ) ) )
491    {
492        if( tor->customUploadLimit )
493        {
494            if( !tr_rcCanTransfer( tor->upload ) )
495            {
496                break;
497            }
498        }
499        else
500        {
501            tr_lockUnlock( &tor->lock );
502            if( !tr_rcCanGlobalTransfer( tor->handle, 1 ) )
503            {
504                tr_lockLock( &tor->lock );
505                break;
506            }
507            tr_lockLock( &tor->lock );
508        }
509
510        ret = tr_netSend( peer->socket, p, size );
511        if( ret & TR_NET_CLOSE )
512        {
513            return TR_ERROR;
514        }
515        else if( ret & TR_NET_BLOCK )
516        {
517            break;
518        }
519
520        blockSent( peer, ret );
521        tr_rcTransferred( peer->upload, ret );
522        tr_rcTransferred( tor->upload, ret );
523
524        tor->uploadedCur += ret;
525        peer->outTotal   += ret;
526        peer->outDate     = tr_date();
527
528        /* In case this block is done, you may have messages
529           pending. Send them before we start the next block */
530        goto writeBegin;
531    }
532writeEnd:
533
534    /* Ask for a block whenever possible */
535    if( !tr_cpIsSeeding( tor->completion ) &&
536        !peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 )
537    {
538        /* This peer is no use to us, and it seems there are
539           more */
540        peer_dbg( "not interesting" );
541        return TR_ERROR;
542    }
543
544    if( peer->amInterested && !peer->peerChoking && !peer->banned )
545    {
546        int block;
547        while( peer->inRequestCount < OUR_REQUEST_COUNT )
548        {
549            block = chooseBlock( tor, peer );
550            if( block < 0 )
551            {
552                break;
553            }
554            sendRequest( tor, peer, block );
555        }
556    }
557
558    return TR_OK;
559}
560
561/***********************************************************************
562 * tr_peerIsConnected
563 ***********************************************************************
564 *
565 **********************************************************************/
566int tr_peerIsConnected( tr_peer_t * peer )
567{
568    return PEER_STATUS_CONNECTED == peer->status;
569}
570
571/***********************************************************************
572 * tr_peerIsIncoming
573 ***********************************************************************
574 *
575 **********************************************************************/
576int tr_peerIsFrom( tr_peer_t * peer )
577{
578    return peer->from;
579}
580
581int tr_peerAmChoking( tr_peer_t * peer )
582{
583    return peer->amChoking;
584}
585int tr_peerAmInterested( tr_peer_t * peer )
586{
587    return peer->amInterested;
588}
589int tr_peerIsChoking( tr_peer_t * peer )
590{
591    return peer->peerChoking;
592}
593int tr_peerIsInterested( tr_peer_t * peer )
594{
595    return peer->peerInterested;
596}
597
598/***********************************************************************
599 * tr_peerProgress
600 ***********************************************************************
601 *
602 **********************************************************************/
603float tr_peerProgress( tr_peer_t * peer )
604{
605    return peer->progress;
606}
607
608/***********************************************************************
609 * tr_peerPort
610 ***********************************************************************
611 * Returns peer's listening port in host byte order
612 **********************************************************************/
613int tr_peerPort( tr_peer_t * peer )
614{
615    return ntohs( peer->port );
616}
617
618/***********************************************************************
619 * tr_peerBitfield
620 ***********************************************************************
621 *
622 **********************************************************************/
623tr_bitfield_t * tr_peerBitfield( tr_peer_t * peer )
624{
625    return peer->bitfield;
626}
627
628float tr_peerDownloadRate( tr_peer_t * peer )
629{
630    return tr_rcRate( peer->download );
631}
632
633float tr_peerUploadRate( tr_peer_t * peer )
634{
635    return tr_rcRate( peer->upload );
636}
637
638void tr_peerChoke( tr_peer_t * peer )
639{
640    sendChoke( peer, 1 );
641    peer->lastChoke = tr_date();
642}
643
644void tr_peerUnchoke( tr_peer_t * peer )
645{
646    sendChoke( peer, 0 );
647    peer->lastChoke = tr_date();
648}
649
650uint64_t tr_peerLastChoke( tr_peer_t * peer )
651{
652    return peer->lastChoke;
653}
654
655void tr_peerSetOptimistic( tr_peer_t * peer, int o )
656{
657    peer->optimistic = o;
658}
659
660int tr_peerIsOptimistic( tr_peer_t * peer )
661{
662    return peer->optimistic;
663}
664
665static inline int peerIsBad( tr_peer_t * peer )
666{
667    return ( peer->badPcs > 4 + 2 * peer->goodPcs );
668}
669
670static inline int peerIsGood( tr_peer_t * peer )
671{
672    return ( peer->goodPcs > 3 * peer->badPcs );
673}
674
675void tr_peerBlame( tr_peer_t * peer, int piece, int success )
676{
677    tr_torrent_t * tor = peer->tor;
678
679    if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
680    {
681        return;
682    }
683
684    if( success )
685    {
686        peer->goodPcs++;
687
688        if( peer->banfield && peerIsGood( peer ) )
689        {
690            /* Assume the peer wasn't responsible for the bad pieces
691               we was banned for */
692            tr_bitfieldClear( peer->banfield );
693        }
694    }
695    else
696    {
697        peer->badPcs++;
698
699        /* Ban the peer for this piece */
700        if( !peer->banfield )
701        {
702            peer->banfield = tr_bitfieldNew( tor->info.pieceCount );
703        }
704        tr_bitfieldAdd( peer->banfield, piece );
705
706        if( peerIsBad( peer ) )
707        {
708            /* Full ban */
709            peer_dbg( "banned (%d / %d)", peer->goodPcs, peer->badPcs );
710            peer->banned = 1;
711            peer->peerInterested = 0;
712        }
713    }
714    tr_bitfieldRem( peer->blamefield, piece );
715}
716
717int tr_peerGetConnectable( tr_torrent_t * tor, uint8_t ** _buf )
718{
719    int count = 0;
720    uint8_t * buf;
721    tr_peer_t * peer;
722    int i;
723
724    if( tor->peerCount < 1 )
725    {
726        *_buf = NULL;
727        return 0;
728    }
729
730    buf = malloc( 6 * tor->peerCount );
731    for( i = 0; i < tor->peerCount; i++ )
732    {
733        peer = tor->peers[i];
734
735        /* Skip peers with no known listening port */
736        if( 0 == peer->port )
737            continue;
738
739        memcpy( &buf[count*6], &peer->addr, 4 );
740        memcpy( &buf[count*6+4], &peer->port, 2 );
741        count++;
742    }
743
744    if( count < 1 )
745    {
746        free( buf ); buf = NULL;
747    }
748    *_buf = buf;
749
750    return count * 6;
751}
Note: See TracBrowser for help on using the repository browser.