source: trunk/libtransmission/peer.c @ 61

Last change on this file since 61 was 61, checked in by titer, 16 years ago

Removed now unused tables and some now unused code

File size: 12.7 KB
Line 
1/******************************************************************************
2 * Copyright (c) 2005 Eric Petit
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 *****************************************************************************/
22
23#include "transmission.h"
24
25#define MAX_REQUEST_COUNT 32
26#define OUR_REQUEST_COUNT 8  /* TODO: we should detect if we are on a
27                                high-speed network and adapt */
28
29typedef struct tr_request_s
30{
31    int index;
32    int begin;
33    int length;
34
35} tr_request_t;
36
37struct tr_peer_s
38{
39    struct in_addr addr;
40    in_port_t      port;
41
42#define PEER_STATUS_IDLE       1 /* Need to connect */
43#define PEER_STATUS_CONNECTING 2 /* Trying to send handshake */
44#define PEER_STATUS_HANDSHAKE  4 /* Waiting for peer's handshake */
45#define PEER_STATUS_CONNECTED  8 /* Got peer's handshake */
46    int            status;
47    int            socket;
48    uint64_t       date;
49    uint64_t       keepAlive;
50
51    char           amChoking;
52    char           amInterested;
53    char           peerChoking;
54    char           peerInterested;
55
56    uint8_t        id[20];
57
58    uint8_t      * bitfield;
59
60    uint8_t      * buf;
61    int            size;
62    int            pos;
63
64    uint8_t      * outMessages;
65    int            outMessagesSize;
66    int            outMessagesPos;
67    uint8_t        outBlock[13+16384];
68    int            outBlockSize;
69    int            outBlockLoaded;
70    int            outBlockSending;
71
72    int            inRequestCount;
73    tr_request_t   inRequests[OUR_REQUEST_COUNT];
74    int            inIndex;
75    int            inBegin;
76    int            inLength;
77    uint64_t       inTotal;
78
79    int            outRequestCount;
80    tr_request_t   outRequests[MAX_REQUEST_COUNT];
81    uint64_t       outTotal;
82    uint64_t       outDate;
83    int            outSlow;
84};
85
86#define peer_dbg( a... ) __peer_dbg( peer, ## a )
87static void __peer_dbg( tr_peer_t * peer, char * msg, ... )
88{
89    char    string[256];
90    va_list args;
91
92    va_start( args, msg );
93    sprintf( string, "%08x:%04x ",
94             (uint32_t) peer->addr.s_addr, peer->port );
95    vsnprintf( &string[14], sizeof( string ) - 14, msg, args );
96    va_end( args ); 
97
98    tr_dbg( "%s", string );
99}
100
101#include "peermessages.h"
102#include "peerutils.h"
103#include "peerparse.h"
104
105/***********************************************************************
106 * tr_peerAddOld
107 ***********************************************************************
108 * Tries to add a peer given its IP and port (received from a tracker
109 * which doesn't support the "compact" extension).
110 **********************************************************************/
111void tr_peerAddOld( tr_torrent_t * tor, char * ip, int port )
112{
113    struct in_addr addr;
114
115    if( tr_netResolve( ip, &addr ) )
116    {
117        return;
118    }
119
120    addWithAddr( tor, addr, htons( port ) );
121}
122
123/***********************************************************************
124 * tr_peerAddCompact
125 ***********************************************************************
126 * Tries to add a peer, using 'addr' and 'port' to connect to the peer.
127 **********************************************************************/
128void tr_peerAddCompact( tr_torrent_t * tor, struct in_addr addr,
129                        in_port_t port )
130{
131    addWithAddr( tor, addr, port );
132}
133
134/***********************************************************************
135 * tr_peerInit
136 ***********************************************************************
137 * Initializes a new peer.
138 **********************************************************************/
139tr_peer_t * tr_peerInit( struct in_addr addr, in_port_t port, int s )
140{
141    tr_peer_t * peer = peerInit();
142
143    peer->socket = s;
144    peer->addr   = addr;
145    peer->port   = port;
146    peer->status = PEER_STATUS_CONNECTING;
147
148    return peer;
149}
150
151void tr_peerAttach( tr_torrent_t * tor, tr_peer_t * peer )
152{
153    peerAttach( tor, peer );
154}
155
156void tr_peerDestroy( tr_fd_t * fdlimit, tr_peer_t * peer )
157{
158    if( peer->bitfield )
159    {
160        free( peer->bitfield );
161    }
162    if( peer->buf )
163    {
164        free( peer->buf );
165    }
166    if( peer->outMessages )
167    {
168        free( peer->outMessages );
169    }
170    if( peer->status > PEER_STATUS_IDLE )
171    {
172        tr_netClose( peer->socket );
173        tr_fdSocketClosed( fdlimit, 0 );
174    }
175    free( peer );
176}
177
178/***********************************************************************
179 * tr_peerRem
180 ***********************************************************************
181 * Frees and closes everything related to the peer at index 'i', and
182 * removes it from the peers list.
183 **********************************************************************/
184void tr_peerRem( tr_torrent_t * tor, int i )
185{
186    tr_peer_t * peer = tor->peers[i];
187    int j;
188
189    for( j = 0; j < peer->inRequestCount; j++ )
190    {
191        tr_request_t * r;
192        int            block;
193
194        r     = &peer->inRequests[j];
195        block = tr_block( r->index,r->begin );
196        tr_cpDownloaderRem( tor->completion, block );
197    }
198    if( !peer->amChoking )
199    {
200        //tr_uploadChoked( tor->upload );
201    }
202    tr_peerDestroy( tor->fdlimit, peer );
203    tor->peerCount--;
204    memmove( &tor->peers[i], &tor->peers[i+1],
205             ( tor->peerCount - i ) * sizeof( tr_peer_t * ) );
206}
207
208/***********************************************************************
209 * tr_peerRead
210 ***********************************************************************
211 *
212 **********************************************************************/
213int tr_peerRead( tr_torrent_t * tor, tr_peer_t * peer )
214{
215    int ret;
216
217    /* Try to read */
218    for( ;; )
219    {
220        if( peer->size < 1 )
221        {
222            peer->size = 1024;
223            peer->buf  = malloc( peer->size );
224        }
225        else if( peer->pos >= peer->size )
226        {
227            peer->size *= 2;
228            peer->buf   = realloc( peer->buf, peer->size );
229        }
230        ret = tr_netRecv( peer->socket, &peer->buf[peer->pos],
231                          peer->size - peer->pos );
232        if( ret & TR_NET_CLOSE )
233        {
234            peer_dbg( "connection closed" );
235            return 1;
236        }
237        else if( ret & TR_NET_BLOCK )
238        {
239            break;
240        }
241        peer->date  = tr_date();
242        peer->pos  += ret;
243        if( NULL != tor )
244        {
245            tr_rcTransferred( tor->download, ret );
246            tr_rcTransferred( tor->globalDownload, ret );
247            if( parseBuf( tor, peer ) )
248            {
249                return 1;
250            }
251        }
252        else
253        {
254            if( parseBufHeader( peer ) )
255            {
256                return 1;
257            }
258        }
259    }
260
261    return 0;
262}
263
264/***********************************************************************
265 * tr_peerHash
266 ***********************************************************************
267 *
268 **********************************************************************/
269uint8_t * tr_peerHash( tr_peer_t * peer )
270{
271    return parseBufHash( peer );
272}
273
274/***********************************************************************
275 * tr_peerPulse
276 ***********************************************************************
277 *
278 **********************************************************************/
279void tr_peerPulse( tr_torrent_t * tor )
280{
281    int i, ret, size;
282    uint8_t * p;
283    tr_peer_t * peer;
284
285    if( tr_date() > tor->date + 1000 )
286    {
287        tor->date = tr_date();
288
289        for( i = 0; i < tor->peerCount; )
290        {
291            if( checkPeer( tor, i ) )
292            {
293                tr_peerRem( tor, i );
294                continue;
295            }
296            i++;
297        }
298    }
299
300    if( tor->status & TR_STATUS_STOPPING )
301    {
302        return;
303    }
304   
305    /* Shuffle peers */
306    if( tor->peerCount > 1 )
307    {
308        peer = tor->peers[0];
309        memmove( &tor->peers[0], &tor->peers[1],
310                 ( tor->peerCount - 1 ) * sizeof( void * ) );
311        tor->peers[tor->peerCount - 1] = peer;
312    }
313
314    /* Handle peers */
315    for( i = 0; i < tor->peerCount; )
316    {
317        peer = tor->peers[i];
318
319        if( peer->status < PEER_STATUS_HANDSHAKE )
320        {
321            i++;
322            continue;
323        }
324
325        if( tr_peerRead( tor, tor->peers[i] ) )
326        {
327            goto dropPeer;
328        }
329
330        if( peer->status < PEER_STATUS_CONNECTED )
331        {
332            i++;
333            continue;
334        }
335
336        /* Try to write */
337writeBegin:
338
339        /* Send all smaller messages regardless of the upload cap */
340        while( ( p = messagesPending( peer, &size ) ) )
341        {
342            ret = tr_netSend( peer->socket, p, size );
343            if( ret & TR_NET_CLOSE )
344            {
345                goto dropPeer;
346            }
347            else if( ret & TR_NET_BLOCK )
348            {
349                goto writeEnd;
350            }
351            messagesSent( peer, ret );
352        }
353
354        /* Send pieces if we can */
355        while( ( p = blockPending( tor, peer, &size ) ) )
356        {
357            if( !tr_rcCanTransfer( tor->globalUpload ) )
358            {
359                break;
360            }
361
362            ret = tr_netSend( peer->socket, p, size );
363            if( ret & TR_NET_CLOSE )
364            {
365                goto dropPeer;
366            }
367            else if( ret & TR_NET_BLOCK )
368            {
369                break;
370            }
371
372            blockSent( peer, ret );
373            tr_rcTransferred( tor->upload, ret );
374            tr_rcTransferred( tor->globalUpload, ret );
375
376            tor->uploaded  += ret;
377            peer->outTotal += ret;
378            peer->outDate   = tr_date();
379
380            /* In case this block is done, you may have messages
381               pending. Send them before we start the next block */
382            goto writeBegin;
383        }
384writeEnd:
385
386        /* Ask for a block whenever possible */
387        if( !tr_cpIsSeeding( tor->completion ) &&
388            !peer->amInterested && tor->peerCount > TR_MAX_PEER_COUNT - 2 )
389        {
390            /* This peer is no use to us, and it seems there are
391               more */
392            peer_dbg( "not interesting" );
393            tr_peerRem( tor, i );
394            continue;
395        }
396
397        if( peer->amInterested && !peer->peerChoking )
398        {
399            int block;
400            while( peer->inRequestCount < OUR_REQUEST_COUNT )
401            {
402                block = chooseBlock( tor, peer );
403                if( block < 0 )
404                {
405                    break;
406                }
407                sendRequest( tor, peer, block );
408            }
409        }
410       
411        i++;
412        continue;
413
414dropPeer:
415        tr_peerRem( tor, i );
416    }
417}
418
419/***********************************************************************
420 * tr_peerIsConnected
421 ***********************************************************************
422 *
423 **********************************************************************/
424int tr_peerIsConnected( tr_peer_t * peer )
425{
426    return peer->status & PEER_STATUS_CONNECTED;
427}
428
429/***********************************************************************
430 * tr_peerIsUploading
431 ***********************************************************************
432 *
433 **********************************************************************/
434int tr_peerIsUploading( tr_peer_t * peer )
435{
436    return ( peer->inRequestCount > 0 );
437}
438
439/***********************************************************************
440 * tr_peerIsDownloading
441 ***********************************************************************
442 *
443 **********************************************************************/
444int tr_peerIsDownloading( tr_peer_t * peer )
445{
446    return peer->outBlockSending;
447}
448
449/***********************************************************************
450 * tr_peerBitfield
451 ***********************************************************************
452 *
453 **********************************************************************/
454uint8_t * tr_peerBitfield( tr_peer_t * peer )
455{
456    return peer->bitfield;
457}
Note: See TracBrowser for help on using the repository browser.