source: trunk/libtransmission/peer.c @ 1534

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

Do bounds checking on bitfields.

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