source: trunk/libtransmission/peer.c @ 1251

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

libT now stores peer upload rate

  • Property svn:keywords set to Date Rev Author Id
File size: 18.7 KB
Line 
1/******************************************************************************
2 * $Id: peer.c 1251 2006-12-18 04:56:27Z 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        {
271            break;
272        }
273
274        if( peer->size < 1 )
275        {
276            peer->size = 1024;
277            peer->buf  = malloc( peer->size );
278        }
279        else if( peer->pos >= peer->size )
280        {
281            peer->size *= 2;
282            peer->buf   = realloc( peer->buf, peer->size );
283        }
284        /* Never read more than 1K each time, otherwise the rate
285           control is no use */
286        ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
287                          MIN( 1024, peer->size - peer->pos ) );
288        if( ret & TR_NET_CLOSE )
289        {
290            peer_dbg( "connection closed" );
291            return 1;
292        }
293        else if( ret & TR_NET_BLOCK )
294        {
295            break;
296        }
297        peer->date  = tr_date();
298        peer->pos  += ret;
299        if( NULL != tor )
300        {
301            tr_rcTransferred( peer->download, ret );
302            tr_rcTransferred( tor->download, ret );
303            tr_rcTransferred( tor->globalDownload, ret );
304            if( parseBuf( tor, peer ) )
305            {
306                return 1;
307            }
308        }
309        else
310        {
311            if( parseBufHeader( peer ) )
312            {
313                return 1;
314            }
315        }
316    }
317
318    return 0;
319}
320
321uint64_t tr_peerDate( tr_peer_t * peer )
322{
323    return peer->date;
324}
325
326/***********************************************************************
327 * tr_peerId
328 ***********************************************************************
329 *
330 **********************************************************************/
331uint8_t * tr_peerId( tr_peer_t * peer )
332{
333    return & peer->id[0];
334}
335
336/***********************************************************************
337 * tr_peerAddress
338 ***********************************************************************
339 *
340 **********************************************************************/
341struct in_addr * tr_peerAddress( tr_peer_t * peer )
342{
343    return &peer->addr;
344}
345
346/***********************************************************************
347 * tr_peerHash
348 ***********************************************************************
349 *
350 **********************************************************************/
351uint8_t * tr_peerHash( tr_peer_t * peer )
352{
353    return parseBufHash( peer );
354}
355
356/***********************************************************************
357 * tr_peerPulse
358 ***********************************************************************
359 *
360 **********************************************************************/
361void tr_peerPulse( tr_torrent_t * tor )
362{
363    int i, ret, size;
364    uint8_t * p;
365    tr_peer_t * peer;
366
367    if( tr_date() > tor->date + 1000 )
368    {
369        tor->date = tr_date();
370
371        for( i = 0; i < tor->peerCount; )
372        {
373            if( checkPeer( tor, i ) )
374            {
375                tr_peerRem( tor, i );
376                continue;
377            }
378            i++;
379        }
380    }
381
382    if( tor->status & TR_STATUS_STOPPING )
383    {
384        return;
385    }
386   
387    /* Shuffle peers */
388    if( tor->peerCount > 1 )
389    {
390        peer = tor->peers[0];
391        memmove( &tor->peers[0], &tor->peers[1],
392                 ( tor->peerCount - 1 ) * sizeof( void * ) );
393        tor->peers[tor->peerCount - 1] = peer;
394    }
395
396    /* Handle peers */
397    for( i = 0; i < tor->peerCount; )
398    {
399        peer = tor->peers[i];
400
401        if( peer->status < PEER_STATUS_HANDSHAKE )
402        {
403            i++;
404            continue;
405        }
406
407        if( tr_peerRead( tor, tor->peers[i] ) )
408        {
409            goto dropPeer;
410        }
411
412        if( peer->status < PEER_STATUS_CONNECTED )
413        {
414            i++;
415            continue;
416        }
417
418        /* Try to write */
419writeBegin:
420
421        /* Send all smaller messages regardless of the upload cap */
422        while( ( p = messagesPending( peer, &size ) ) )
423        {
424            ret = tr_netSend( peer->socket, p, size );
425            if( ret & TR_NET_CLOSE )
426            {
427                goto dropPeer;
428            }
429            else if( ret & TR_NET_BLOCK )
430            {
431                goto writeEnd;
432            }
433            messagesSent( peer, ret );
434        }
435
436        /* Send pieces if we can */
437        while( ( p = blockPending( tor, peer, &size ) ) )
438        {
439            if( !tr_rcCanTransfer( tor->globalUpload ) )
440            {
441                break;
442            }
443
444            ret = tr_netSend( peer->socket, p, size );
445            if( ret & TR_NET_CLOSE )
446            {
447                goto dropPeer;
448            }
449            else if( ret & TR_NET_BLOCK )
450            {
451                break;
452            }
453
454            blockSent( peer, ret );
455            tr_rcTransferred( peer->upload, ret );
456            tr_rcTransferred( tor->upload, ret );
457            tr_rcTransferred( tor->globalUpload, ret );
458
459            tor->uploadedCur += ret;
460            peer->outTotal   += ret;
461            peer->outDate     = tr_date();
462
463            /* In case this block is done, you may have messages
464               pending. Send them before we start the next block */
465            goto writeBegin;
466        }
467writeEnd:
468
469        /* Ask for a block whenever possible */
470        if( !tr_cpIsSeeding( tor->completion ) &&
471            !peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 )
472        {
473            /* This peer is no use to us, and it seems there are
474               more */
475            peer_dbg( "not interesting" );
476            tr_peerRem( tor, i );
477            continue;
478        }
479
480        if( peer->amInterested && !peer->peerChoking && !peer->banned )
481        {
482            int block;
483            while( peer->inRequestCount < OUR_REQUEST_COUNT )
484            {
485                block = chooseBlock( tor, peer );
486                if( block < 0 )
487                {
488                    break;
489                }
490                sendRequest( tor, peer, block );
491            }
492        }
493       
494        i++;
495        continue;
496
497dropPeer:
498        tr_peerRem( tor, i );
499    }
500}
501
502/***********************************************************************
503 * tr_peerIsConnected
504 ***********************************************************************
505 *
506 **********************************************************************/
507int tr_peerIsConnected( tr_peer_t * peer )
508{
509    return peer->status & PEER_STATUS_CONNECTED;
510}
511
512/***********************************************************************
513 * tr_peerIsIncoming
514 ***********************************************************************
515 *
516 **********************************************************************/
517int tr_peerIsIncoming( tr_peer_t * peer )
518{
519    return peer->incoming;
520}
521
522/***********************************************************************
523 * tr_peerIsUploading
524 ***********************************************************************
525 *
526 **********************************************************************/
527int tr_peerIsUploading( tr_peer_t * peer )
528{
529    return ( peer->inRequestCount > 0 );
530}
531
532/***********************************************************************
533 * tr_peerIsDownloading
534 ***********************************************************************
535 *
536 **********************************************************************/
537int tr_peerIsDownloading( tr_peer_t * peer )
538{
539    return peer->outBlockSending;
540}
541
542/***********************************************************************
543 * tr_peerProgress
544 ***********************************************************************
545 *
546 **********************************************************************/
547float tr_peerProgress( tr_peer_t * peer )
548{
549    return peer->progress;
550}
551
552/***********************************************************************
553 * tr_peerPort
554 ***********************************************************************
555 * Returns peer's listening port in host byte order
556 **********************************************************************/
557int tr_peerPort( tr_peer_t * peer )
558{
559    return ntohs( peer->port );
560}
561
562/***********************************************************************
563 * tr_peerBitfield
564 ***********************************************************************
565 *
566 **********************************************************************/
567uint8_t * tr_peerBitfield( tr_peer_t * peer )
568{
569    return peer->bitfield;
570}
571
572float tr_peerDownloadRate( tr_peer_t * peer )
573{
574    return tr_rcRate( peer->download );
575}
576
577float tr_peerUploadRate( tr_peer_t * peer )
578{
579    return tr_rcRate( peer->upload );
580}
581
582int tr_peerIsUnchoked( tr_peer_t * peer )
583{
584    return !peer->amChoking;
585}
586
587int tr_peerIsInterested  ( tr_peer_t * peer )
588{
589    return peer->peerInterested;
590}
591
592void tr_peerChoke( tr_peer_t * peer )
593{
594    sendChoke( peer, 1 );
595    peer->lastChoke = tr_date();
596}
597
598void tr_peerUnchoke( tr_peer_t * peer )
599{
600    sendChoke( peer, 0 );
601    peer->lastChoke = tr_date();
602}
603
604uint64_t tr_peerLastChoke( tr_peer_t * peer )
605{
606    return peer->lastChoke;
607}
608
609void tr_peerSetOptimistic( tr_peer_t * peer, int o )
610{
611    peer->optimistic = o;
612}
613
614int tr_peerIsOptimistic( tr_peer_t * peer )
615{
616    return peer->optimistic;
617}
618
619static inline int peerIsBad( tr_peer_t * peer )
620{
621    return ( peer->badPcs > 4 + 2 * peer->goodPcs );
622}
623
624static inline int peerIsGood( tr_peer_t * peer )
625{
626    return ( peer->goodPcs > 3 * peer->badPcs );
627}
628
629void tr_peerBlame( tr_torrent_t * tor, tr_peer_t * peer,
630                   int piece, int success )
631{
632    if( !peer->blamefield || !tr_bitfieldHas( peer->blamefield, piece ) )
633    {
634        return;
635    }
636
637    if( success )
638    {
639        peer->goodPcs++;
640
641        if( peer->banfield && peerIsGood( peer ) )
642        {
643            /* Assume the peer wasn't responsible for the bad pieces
644               we was banned for */
645            memset( peer->banfield, 0x00, ( tor->info.pieceCount + 7 ) / 8 );
646        }
647    }
648    else
649    {
650        peer->badPcs++;
651
652        /* Ban the peer for this piece */
653        if( !peer->banfield )
654        {
655            peer->banfield = calloc( ( tor->info.pieceCount + 7 ) / 8, 1 );
656        }
657        tr_bitfieldAdd( peer->banfield, piece );
658
659        if( peerIsBad( peer ) )
660        {
661            /* Full ban */
662            peer_dbg( "banned (%d / %d)", peer->goodPcs, peer->badPcs );
663            peer->banned = 1;
664            peer->peerInterested = 0;
665        }
666    }
667    tr_bitfieldRem( peer->blamefield, piece );
668}
669
670int tr_peerGetConnectable( tr_torrent_t * tor, uint8_t ** _buf )
671{
672    int count = 0;
673    uint8_t * buf = malloc( 6 * tor->peerCount );
674    tr_peer_t * peer;
675    int i;
676
677    for( i = 0; i < tor->peerCount; i++ )
678    {
679        peer = tor->peers[i];
680
681        /* Skip peers for which the connection isn't established,
682         * and peers that came from incoming connections */
683        if( peer->status < PEER_STATUS_CONNECTED )
684            continue;
685        if( peer->incoming )
686            continue;
687
688        memcpy( &buf[count*6], &peer->addr, 4 );
689        memcpy( &buf[count*6+4], &peer->port, 2 );
690        count++;
691    }
692
693    if( count < 1 )
694    {
695        free( buf );
696        *_buf = NULL;
697    }
698    else
699    {
700        *_buf = buf;
701    }
702
703    return count * 6;
704}
Note: See TracBrowser for help on using the repository browser.