source: trunk/libtransmission/peer.c @ 1288

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

support in libT for individual torrent speed caps

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