source: trunk/libtransmission/peer.c @ 1452

Last change on this file since 1452 was 1452, checked in by livings124, 16 years ago

simplify options for download limits in inspector with 3 check states: mixed for system defaults, checked for override with limit, and no check for no limit

  • Property svn:keywords set to Date Rev Author Id
File size: 16.8 KB
Line 
1/******************************************************************************
2 * $Id: peer.c 1452 2007-02-02 17:33:32Z livings124 $
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    uint8_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    uint8_t      * blamefield;
76    /* The bad pieces that the peer has contributed to */
77    uint8_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    if( peer->bitfield )
166    {
167        free( peer->bitfield );
168    }
169    if( peer->blamefield )
170    {
171        free( peer->blamefield );
172    }
173    if( peer->banfield )
174    {
175        free( peer->banfield );
176    }
177    if( peer->buf )
178    {
179        free( peer->buf );
180    }
181    if( peer->outMessages )
182    {
183        free( peer->outMessages );
184    }
185    if( peer->status > PEER_STATUS_IDLE )
186    {
187        tr_netClose( peer->socket );
188    }
189    tr_rcClose( peer->download );
190    tr_rcClose( peer->upload );
191    free( peer );
192}
193
194void tr_peerSetTorrent( tr_peer_t * peer, tr_torrent_t * tor )
195{
196    peer->tor = tor;
197}
198
199/***********************************************************************
200 * tr_peerRead
201 ***********************************************************************
202 *
203 **********************************************************************/
204int tr_peerRead( tr_peer_t * peer )
205{
206    tr_torrent_t * tor = peer->tor;
207    int ret;
208
209    /* Try to read */
210    for( ;; )
211    {
212        if( tor )
213        {
214            if( tor->customDownloadLimit )
215            {
216                if( !tr_rcCanTransfer( tor->download ) )
217                {
218                    break;
219                }
220            }
221            else
222            {
223                tr_lockUnlock( &tor->lock );
224                if( !tr_rcCanGlobalTransfer( tor->handle, 0 ) )
225                {
226                    tr_lockLock( &tor->lock );
227                    break;
228                }
229                tr_lockLock( &tor->lock );
230            }
231        }
232
233        if( peer->size < 1 )
234        {
235            peer->size = 1024;
236            peer->buf  = malloc( peer->size );
237        }
238        else if( peer->pos >= peer->size )
239        {
240            peer->size *= 2;
241            peer->buf   = realloc( peer->buf, peer->size );
242        }
243        /* Never read more than 1K each time, otherwise the rate
244           control is no use */
245        ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
246                          MIN( 1024, peer->size - peer->pos ) );
247        if( ret & TR_NET_CLOSE )
248        {
249            peer_dbg( "connection closed" );
250            return TR_ERROR;
251        }
252        else if( ret & TR_NET_BLOCK )
253        {
254            break;
255        }
256        peer->date  = tr_date();
257        peer->pos  += ret;
258        if( NULL != tor )
259        {
260            tr_rcTransferred( peer->download, ret );
261            tr_rcTransferred( tor->download, ret );
262            if( ( ret = parseBuf( tor, peer ) ) )
263            {
264                return ret;
265            }
266        }
267        else
268        {
269            if( ( ret = parseBufHeader( peer ) ) )
270            {
271                return ret;
272            }
273        }
274    }
275
276    return TR_OK;
277}
278
279uint64_t tr_peerDate( tr_peer_t * peer )
280{
281    return peer->date;
282}
283
284/***********************************************************************
285 * tr_peerId
286 ***********************************************************************
287 *
288 **********************************************************************/
289uint8_t * tr_peerId( tr_peer_t * peer )
290{
291    return & peer->id[0];
292}
293
294/***********************************************************************
295 * tr_peerAddress
296 ***********************************************************************
297 *
298 **********************************************************************/
299struct in_addr * tr_peerAddress( tr_peer_t * peer )
300{
301    return &peer->addr;
302}
303
304/***********************************************************************
305 * tr_peerHash
306 ***********************************************************************
307 *
308 **********************************************************************/
309uint8_t * tr_peerHash( tr_peer_t * peer )
310{
311    return parseBufHash( peer );
312}
313
314/***********************************************************************
315 * tr_peerPulse
316 ***********************************************************************
317 *
318 **********************************************************************/
319int tr_peerPulse( tr_peer_t * peer )
320{
321    tr_torrent_t * tor = peer->tor;
322    int ret, size;
323    uint8_t * p;
324
325    if( ( ret = checkPeer( peer ) ) )
326    {
327        return ret;
328    }
329
330    /* Connect */
331    if( peer->status & PEER_STATUS_IDLE )
332    {
333        peer->socket = tr_netOpenTCP( peer->addr, peer->port, 0 );
334        if( peer->socket < 0 )
335        {
336            return TR_ERROR;
337        }
338        peer->status = PEER_STATUS_CONNECTING;
339    }
340
341    /* Try to send handshake */
342    if( peer->status & PEER_STATUS_CONNECTING )
343    {
344        uint8_t buf[68];
345        tr_info_t * inf = &tor->info;
346
347        buf[0] = 19;
348        memcpy( &buf[1], "BitTorrent protocol", 19 );
349        memset( &buf[20], 0, 8 );
350        memcpy( &buf[28], inf->hash, 20 );
351        memcpy( &buf[48], tor->id, 20 );
352
353        switch( tr_netSend( peer->socket, buf, 68 ) )
354        {
355            case 68:
356                peer_dbg( "SEND handshake" );
357                peer->status = PEER_STATUS_HANDSHAKE;
358                break;
359            case TR_NET_BLOCK:
360                break;
361            default:
362                peer_dbg( "connection closed" );
363                return TR_ERROR;
364        }
365    }
366    if( peer->status < PEER_STATUS_HANDSHAKE )
367    {
368        /* Nothing more we can do till we sent the handshake */
369        return TR_OK;
370    }
371
372    /* Read incoming messages */
373    if( ( ret = tr_peerRead( peer ) ) )
374    {
375        return ret;
376    }
377    if( peer->status < PEER_STATUS_CONNECTED )
378    {
379        /* Nothing more we can do till we got the other guy's handshake */
380        return TR_OK;
381    }
382
383    /* Try to write */
384writeBegin:
385
386    /* Send all smaller messages regardless of the upload cap */
387    while( ( p = messagesPending( peer, &size ) ) )
388    {
389        ret = tr_netSend( peer->socket, p, size );
390        if( ret & TR_NET_CLOSE )
391        {
392            return TR_ERROR;
393        }
394        else if( ret & TR_NET_BLOCK )
395        {
396            goto writeEnd;
397        }
398        messagesSent( peer, ret );
399    }
400
401    /* Send pieces if we can */
402    while( ( p = blockPending( tor, peer, &size ) ) )
403    {
404        if( tor->customUploadLimit )
405        {
406            if( !tr_rcCanTransfer( tor->upload ) )
407            {
408                break;
409            }
410        }
411        else
412        {
413            tr_lockUnlock( &tor->lock );
414            if( !tr_rcCanGlobalTransfer( tor->handle, 1 ) )
415            {
416                tr_lockLock( &tor->lock );
417                break;
418            }
419            tr_lockLock( &tor->lock );
420        }
421
422        ret = tr_netSend( peer->socket, p, size );
423        if( ret & TR_NET_CLOSE )
424        {
425            return TR_ERROR;
426        }
427        else if( ret & TR_NET_BLOCK )
428        {
429            break;
430        }
431
432        blockSent( peer, ret );
433        tr_rcTransferred( peer->upload, ret );
434        tr_rcTransferred( tor->upload, ret );
435
436        tor->uploadedCur += ret;
437        peer->outTotal   += ret;
438        peer->outDate     = tr_date();
439
440        /* In case this block is done, you may have messages
441           pending. Send them before we start the next block */
442        goto writeBegin;
443    }
444writeEnd:
445
446    /* Ask for a block whenever possible */
447    if( !tr_cpIsSeeding( tor->completion ) &&
448        !peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 )
449    {
450        /* This peer is no use to us, and it seems there are
451           more */
452        peer_dbg( "not interesting" );
453        return TR_ERROR;
454    }
455
456    if( peer->amInterested && !peer->peerChoking && !peer->banned )
457    {
458        int block;
459        while( peer->inRequestCount < OUR_REQUEST_COUNT )
460        {
461            block = chooseBlock( tor, peer );
462            if( block < 0 )
463            {
464                break;
465            }
466            sendRequest( tor, peer, block );
467        }
468    }
469
470    return TR_OK;
471}
472
473/***********************************************************************
474 * tr_peerIsConnected
475 ***********************************************************************
476 *
477 **********************************************************************/
478int tr_peerIsConnected( tr_peer_t * peer )
479{
480    return peer->status & PEER_STATUS_CONNECTED;
481}
482
483/***********************************************************************
484 * tr_peerIsIncoming
485 ***********************************************************************
486 *
487 **********************************************************************/
488int tr_peerIsIncoming( tr_peer_t * peer )
489{
490    return peer->incoming;
491}
492
493int tr_peerAmChoking( tr_peer_t * peer )
494{
495    return peer->amChoking;
496}
497int tr_peerAmInterested( tr_peer_t * peer )
498{
499    return peer->amInterested;
500}
501int tr_peerIsChoking( tr_peer_t * peer )
502{
503    return peer->peerChoking;
504}
505int tr_peerIsInterested( tr_peer_t * peer )
506{
507    return peer->peerInterested;
508}
509
510/***********************************************************************
511 * tr_peerProgress
512 ***********************************************************************
513 *
514 **********************************************************************/
515float tr_peerProgress( tr_peer_t * peer )
516{
517    return peer->progress;
518}
519
520/***********************************************************************
521 * tr_peerPort
522 ***********************************************************************
523 * Returns peer's listening port in host byte order
524 **********************************************************************/
525int tr_peerPort( tr_peer_t * peer )
526{
527    return ntohs( peer->port );
528}
529
530/***********************************************************************
531 * tr_peerBitfield
532 ***********************************************************************
533 *
534 **********************************************************************/
535uint8_t * tr_peerBitfield( tr_peer_t * peer )
536{
537    return peer->bitfield;
538}
539
540float tr_peerDownloadRate( tr_peer_t * peer )
541{
542    return tr_rcRate( peer->download );
543}
544
545float tr_peerUploadRate( tr_peer_t * peer )
546{
547    return tr_rcRate( peer->upload );
548}
549
550void tr_peerChoke( tr_peer_t * peer )
551{
552    sendChoke( peer, 1 );
553    peer->lastChoke = tr_date();
554}
555
556void tr_peerUnchoke( tr_peer_t * peer )
557{
558    sendChoke( peer, 0 );
559    peer->lastChoke = tr_date();
560}
561
562uint64_t tr_peerLastChoke( tr_peer_t * peer )
563{
564    return peer->lastChoke;
565}
566
567void tr_peerSetOptimistic( tr_peer_t * peer, int o )
568{
569    peer->optimistic = o;
570}
571
572int tr_peerIsOptimistic( tr_peer_t * peer )
573{
574    return peer->optimistic;
575}
576
577static inline int peerIsBad( tr_peer_t * peer )
578{
579    return ( peer->badPcs > 4 + 2 * peer->goodPcs );
580}
581
582static inline int peerIsGood( tr_peer_t * peer )
583{
584    return ( peer->goodPcs > 3 * peer->badPcs );
585}
586
587void tr_peerBlame( tr_peer_t * peer, int piece, int success )
588{
589    tr_torrent_t * tor = peer->tor;
590
591    if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
592    {
593        return;
594    }
595
596    if( success )
597    {
598        peer->goodPcs++;
599
600        if( peer->banfield && peerIsGood( peer ) )
601        {
602            /* Assume the peer wasn't responsible for the bad pieces
603               we was banned for */
604            memset( peer->banfield, 0x00, ( tor->info.pieceCount + 7 ) / 8 );
605        }
606    }
607    else
608    {
609        peer->badPcs++;
610
611        /* Ban the peer for this piece */
612        if( !peer->banfield )
613        {
614            peer->banfield = calloc( ( tor->info.pieceCount + 7 ) / 8, 1 );
615        }
616        tr_bitfieldAdd( peer->banfield, piece );
617
618        if( peerIsBad( peer ) )
619        {
620            /* Full ban */
621            peer_dbg( "banned (%d / %d)", peer->goodPcs, peer->badPcs );
622            peer->banned = 1;
623            peer->peerInterested = 0;
624        }
625    }
626    tr_bitfieldRem( peer->blamefield, piece );
627}
628
629int tr_peerGetConnectable( tr_torrent_t * tor, uint8_t ** _buf )
630{
631    int count = 0;
632    uint8_t * buf;
633    tr_peer_t * peer;
634    int i;
635
636    if( tor->peerCount < 1 )
637    {
638        *_buf = NULL;
639        return 0;
640    }
641
642    buf = malloc( 6 * tor->peerCount );
643    for( i = 0; i < tor->peerCount; i++ )
644    {
645        peer = tor->peers[i];
646
647        /* Skip peers with no known listening port */
648        if( 0 == peer->port )
649            continue;
650
651        memcpy( &buf[count*6], &peer->addr, 4 );
652        memcpy( &buf[count*6+4], &peer->port, 2 );
653        count++;
654    }
655
656    if( count < 1 )
657    {
658        free( buf ); buf = NULL;
659    }
660    *_buf = buf;
661
662    return count * 6;
663}
Note: See TracBrowser for help on using the repository browser.