source: trunk/libtransmission/peer-io.c @ 4608

Last change on this file since 4608 was 4608, checked in by charles, 14 years ago

follow the spec's suggestion that new connections be 3x as likely for optimistic unchoke

  • Property svn:keywords set to Date Rev Author Id
File size: 12.7 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 Charles Kerr <charles@rebelbase.com>
3 *
4 * This file is licensed by the GPL version 2.  Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
9 *
10 * $Id: peer-io.c 4608 2008-01-11 02:09:20Z charles $
11 */
12
13#include <assert.h>
14#include <string.h>
15#include <stdio.h>
16#include <unistd.h>
17
18#ifdef WIN32
19#include <winsock2.h>
20#else
21#include <netinet/in.h> /* struct in_addr */
22#include <arpa/inet.h> /* inet_ntoa */
23#endif
24
25#include <event.h>
26
27#include "transmission.h"
28#include "crypto.h"
29#include "net.h"
30#include "peer-io.h"
31#include "ratecontrol.h"
32#include "trevent.h"
33#include "utils.h"
34
35#define IO_TIMEOUT_SECS 8
36
37/* arbitrary */
38#define TR_RDBUF (1024*8)
39
40/**
41***
42**/
43
44struct tr_extensions
45{
46    unsigned int extendedProtocolSupported : 1;
47    unsigned int fastPeersSupported : 1;
48};
49
50struct tr_peerIo
51{
52    struct tr_handle * handle;
53
54    struct in_addr in_addr;
55    int port;
56    int socket;
57    int encryptionMode;
58    int timeout;
59    struct bufferevent * bufev;
60    uint8_t peerId[20];
61    time_t timeCreated;
62
63    tr_extensions extensions;
64
65    unsigned int isEncrypted : 1;
66    unsigned int isIncoming : 1;
67    unsigned int peerIdIsSet : 1;
68
69    tr_can_read_cb     canRead;
70    tr_did_write_cb    didWrite;
71    tr_net_error_cb    gotError;
72    void             * userData;
73
74    tr_crypto * crypto;
75};
76
77/**
78***
79**/
80
81static void
82didWriteWrapper( struct bufferevent * e, void * userData )
83{
84    tr_peerIo * c = (tr_peerIo *) userData;
85    if( c->didWrite != NULL )
86        (*c->didWrite)( e, c->userData );
87}
88
89static void
90canReadWrapper( struct bufferevent * e, void * userData )
91{
92    int done = 0;
93    tr_peerIo * c = userData;
94    tr_handle * handle = c->handle;
95
96    if( c->canRead == NULL )
97        return;
98
99    tr_globalLock( handle );
100
101    while( !done )
102    {
103        const int ret = (*c->canRead)( e, c->userData );
104
105        switch( ret )
106        {
107            case READ_AGAIN:
108                if( EVBUFFER_LENGTH( e->input ) )
109                    continue;
110            case READ_MORE:
111            case READ_DONE:
112                done = 1;
113        }
114    }
115
116    tr_globalUnlock( handle );
117}
118
119static void
120gotErrorWrapper( struct bufferevent * e, short what, void * userData )
121{
122    tr_peerIo * c = userData;
123    if( c->gotError != NULL )
124        (*c->gotError)( e, what, c->userData );
125}
126
127/**
128***
129**/
130
131void bufferevent_setwatermark(struct bufferevent *, short, size_t, size_t);
132
133static tr_peerIo*
134tr_peerIoNew( struct tr_handle     * handle,
135              const struct in_addr * in_addr,
136              uint16_t               port,
137              const uint8_t        * torrentHash,
138              int                    isIncoming,
139              int                    socket )
140{
141    tr_peerIo * c;
142    c = tr_new0( tr_peerIo, 1 );
143    c->crypto = tr_cryptoNew( torrentHash, isIncoming );
144    c->handle = handle;
145    c->in_addr = *in_addr;
146    c->port = port;
147    c->socket = socket;
148    c->isIncoming = isIncoming ? 1 : 0;
149    c->timeout = IO_TIMEOUT_SECS;
150    c->timeCreated = time( NULL );
151    c->bufev = bufferevent_new( c->socket,
152                                canReadWrapper,
153                                didWriteWrapper,
154                                gotErrorWrapper,
155                                c );
156    bufferevent_settimeout( c->bufev, c->timeout, c->timeout );
157    bufferevent_enable( c->bufev, EV_READ|EV_WRITE );
158    bufferevent_setwatermark( c->bufev, EV_READ, 0, TR_RDBUF );
159
160    return c;
161}
162
163tr_peerIo*
164tr_peerIoNewIncoming( struct tr_handle      * handle,
165                      const struct in_addr  * in_addr,
166                      uint16_t                port,
167                      int                     socket )
168{
169    assert( handle != NULL );
170    assert( in_addr != NULL );
171    assert( socket >= 0 );
172
173    return tr_peerIoNew( handle, in_addr, port,
174                         NULL, 1,
175                         socket );
176}
177
178tr_peerIo*
179tr_peerIoNewOutgoing( struct tr_handle      * handle,
180                      const struct in_addr  * in_addr,
181                      int                     port,
182                      const uint8_t         * torrentHash )
183{
184    int socket;
185
186    assert( handle != NULL );
187    assert( in_addr != NULL );
188    assert( port >= 0 );
189    assert( torrentHash != NULL );
190
191    socket = tr_netOpenTCP( in_addr, port, 0 );
192
193    return socket < 0
194        ? NULL 
195        : tr_peerIoNew( handle, in_addr, port, torrentHash, 0, socket );
196}
197
198static void
199io_dtor( void * vio )
200{
201    tr_peerIo * io = vio;
202
203    bufferevent_free( io->bufev );
204    tr_netClose( io->socket );
205    tr_cryptoFree( io->crypto );
206    tr_free( io );
207}
208
209void
210tr_peerIoFree( tr_peerIo * io )
211{
212    if( io != NULL )
213    {
214        io->canRead = NULL;
215        io->didWrite = NULL;
216        io->gotError = NULL;
217        tr_runInEventThread( io->handle, io_dtor, io );
218    }
219}
220
221tr_handle*
222tr_peerIoGetHandle( tr_peerIo * io )
223{
224    assert( io != NULL );
225    assert( io->handle != NULL );
226
227    return io->handle;
228}
229
230const struct in_addr*
231tr_peerIoGetAddress( const tr_peerIo * io, uint16_t * port )
232{
233    assert( io != NULL );
234
235    if( port != NULL )
236       *port = io->port;
237
238    return &io->in_addr;
239}
240
241const char*
242tr_peerIoAddrStr( const struct in_addr * addr, uint16_t port )
243{
244    static char buf[512];
245    snprintf( buf, sizeof(buf), "%s:%u", inet_ntoa( *addr ), (unsigned int)port );
246    return buf;
247}
248
249const char*
250tr_peerIoGetAddrStr( const tr_peerIo * io )
251{
252    return tr_peerIoAddrStr( &io->in_addr, io->port );
253}
254
255void
256tr_peerIoTryRead( tr_peerIo * io )
257{
258    if( EVBUFFER_LENGTH( io->bufev->input ) )
259        canReadWrapper( io->bufev, io );
260}
261
262void 
263tr_peerIoSetIOFuncs( tr_peerIo          * io,
264                     tr_can_read_cb       readcb,
265                     tr_did_write_cb      writecb,
266                     tr_net_error_cb      errcb,
267                     void               * userData )
268{
269    io->canRead = readcb;
270    io->didWrite = writecb;
271    io->gotError = errcb;
272    io->userData = userData;
273
274    tr_peerIoTryRead( io );
275}
276
277int
278tr_peerIoIsIncoming( const tr_peerIo * c )
279{
280    return c->isIncoming ? 1 : 0;
281}
282
283int
284tr_peerIoReconnect( tr_peerIo * io )
285{
286    assert( !tr_peerIoIsIncoming( io ) );
287
288    if( io->socket >= 0 )
289        tr_netClose( io->socket );
290
291    io->socket = tr_netOpenTCP( &io->in_addr, io->port, 0 );
292 
293    if( io->socket >= 0 )
294    {
295        bufferevent_free( io->bufev );
296
297        io->bufev = bufferevent_new( io->socket,
298                                     canReadWrapper,
299                                     didWriteWrapper,
300                                     gotErrorWrapper,
301                                     io );
302        bufferevent_settimeout( io->bufev, io->timeout, io->timeout );
303        bufferevent_enable( io->bufev, EV_READ|EV_WRITE );
304        bufferevent_setwatermark( io->bufev, EV_READ, 0, TR_RDBUF );
305
306        return 0;
307    }
308 
309    return -1;
310}
311
312void
313tr_peerIoSetTimeoutSecs( tr_peerIo * io, int secs )
314{
315    io->timeout = secs;
316    bufferevent_settimeout( io->bufev, io->timeout, io->timeout );
317}
318
319/**
320***
321**/
322
323void
324tr_peerIoSetTorrentHash( tr_peerIo     * io,
325                         const uint8_t * hash )
326{
327    assert( io != NULL );
328
329    tr_cryptoSetTorrentHash( io->crypto, hash );
330}
331
332const uint8_t*
333tr_peerIoGetTorrentHash( tr_peerIo * io )
334{
335    assert( io != NULL );
336    assert( io->crypto != NULL );
337
338    return tr_cryptoGetTorrentHash( io->crypto );
339}
340
341int
342tr_peerIoHasTorrentHash( const tr_peerIo * io )
343{
344    assert( io != NULL );
345    assert( io->crypto != NULL );
346
347    return tr_cryptoHasTorrentHash( io->crypto );
348}
349
350/**
351***
352**/
353
354void
355tr_peerIoSetPeersId( tr_peerIo     * io,
356                     const uint8_t * peer_id )
357{
358    assert( io != NULL );
359
360    if(( io->peerIdIsSet = peer_id != NULL ))
361        memcpy( io->peerId, peer_id, 20 );
362    else
363        memset( io->peerId, 0, 20 );
364}
365
366const uint8_t* 
367tr_peerIoGetPeersId( const tr_peerIo * io )
368{
369    assert( io != NULL );
370    assert( io->peerIdIsSet );
371
372    return io->peerId;
373}
374
375/**
376***
377**/
378
379void
380tr_peerIoEnableLTEP( tr_peerIo * io, int flag )
381{
382    assert( io != NULL );
383    assert( flag==0 || flag==1 );
384   
385    io->extensions.extendedProtocolSupported = flag;
386}
387
388void
389tr_peerIoEnableFEXT( tr_peerIo * io, int flag )
390{
391    assert( io != NULL );
392    assert( flag==0 || flag==1 );
393   
394    io->extensions.fastPeersSupported = flag;
395}
396
397int
398tr_peerIoSupportsLTEP( const tr_peerIo * io )
399{
400    assert( io != NULL );
401   
402    return io->extensions.extendedProtocolSupported;
403}
404
405int
406tr_peerIoSupportsFEXT( const tr_peerIo * io )
407{
408    assert( io != NULL );
409   
410    return io->extensions.fastPeersSupported;
411}
412/**
413***
414**/
415
416size_t
417tr_peerIoWriteBytesWaiting( const tr_peerIo * io )
418{
419    return EVBUFFER_LENGTH( EVBUFFER_OUTPUT( io->bufev ) );
420}
421 
422void
423tr_peerIoWrite( tr_peerIo   * io,
424                const void  * writeme,
425                int           writeme_len )
426{
427    assert( tr_amInEventThread( io->handle ) );
428    bufferevent_write( io->bufev, writeme, writeme_len );
429}
430
431void
432tr_peerIoWriteBuf( tr_peerIo       * io,
433                   struct evbuffer * buf )
434{
435    const size_t n = EVBUFFER_LENGTH( buf );
436    tr_peerIoWrite( io, EVBUFFER_DATA(buf), n );
437    evbuffer_drain( buf, n );
438}
439
440/**
441***
442**/
443
444tr_crypto* 
445tr_peerIoGetCrypto( tr_peerIo * c )
446{
447    return c->crypto;
448}
449
450void 
451tr_peerIoSetEncryption( tr_peerIo * io,
452                        int         encryptionMode )
453{
454    assert( io != NULL );
455    assert( encryptionMode==PEER_ENCRYPTION_NONE || encryptionMode==PEER_ENCRYPTION_RC4 );
456
457    io->encryptionMode = encryptionMode;
458}
459
460int
461tr_peerIoIsEncrypted( const tr_peerIo * io )
462{
463    return io!=NULL && io->encryptionMode==PEER_ENCRYPTION_RC4;
464}
465
466/**
467***
468**/
469
470void
471tr_peerIoWriteBytes( tr_peerIo        * io,
472                     struct evbuffer  * outbuf,
473                     const void       * bytes,
474                     size_t             byteCount )
475{
476    uint8_t * tmp;
477
478    switch( io->encryptionMode )
479    {
480        case PEER_ENCRYPTION_NONE:
481            evbuffer_add( outbuf, bytes, byteCount );
482            break;
483
484        case PEER_ENCRYPTION_RC4:
485            tmp = tr_new( uint8_t, byteCount );
486            tr_cryptoEncrypt( io->crypto, byteCount, bytes, tmp );
487            evbuffer_add( outbuf, tmp, byteCount );
488            tr_free( tmp );
489            break;
490
491        default:
492            assert( 0 );
493    }
494}
495
496void
497tr_peerIoWriteUint8( tr_peerIo        * io,
498                     struct evbuffer  * outbuf,
499                     uint8_t            writeme )
500{
501    tr_peerIoWriteBytes( io, outbuf, &writeme, sizeof(uint8_t) );
502}
503
504void
505tr_peerIoWriteUint16( tr_peerIo        * io,
506                      struct evbuffer  * outbuf,
507                      uint16_t           writeme )
508{
509    uint16_t tmp = htons( writeme );
510    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint16_t) );
511}
512
513void
514tr_peerIoWriteUint32( tr_peerIo        * io,
515                      struct evbuffer  * outbuf,
516                      uint32_t           writeme )
517{
518    uint32_t tmp = htonl( writeme );
519    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint32_t) );
520}
521
522/***
523****
524***/
525
526void
527tr_peerIoReadBytes( tr_peerIo        * io,
528                    struct evbuffer  * inbuf,
529                    void             * bytes,
530                    size_t             byteCount )
531{
532    assert( EVBUFFER_LENGTH( inbuf ) >= byteCount );
533
534    switch( io->encryptionMode )
535    {
536        case PEER_ENCRYPTION_NONE:
537            evbuffer_remove( inbuf, bytes, byteCount );
538            break;
539
540        case PEER_ENCRYPTION_RC4:
541            evbuffer_remove( inbuf, bytes, byteCount );
542            tr_cryptoDecrypt( io->crypto, byteCount, bytes, bytes );
543            break;
544
545        default:
546            assert( 0 );
547    }
548}
549
550void
551tr_peerIoReadUint8( tr_peerIo         * io,
552                    struct evbuffer   * inbuf,
553                    uint8_t           * setme )
554{
555    tr_peerIoReadBytes( io, inbuf, setme, sizeof(uint8_t) );
556}
557
558void
559tr_peerIoReadUint16( tr_peerIo         * io,
560                     struct evbuffer   * inbuf,
561                     uint16_t          * setme )
562{
563    uint16_t tmp;
564    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint16_t) );
565    *setme = ntohs( tmp );
566}
567
568void
569tr_peerIoReadUint32( tr_peerIo         * io,
570                     struct evbuffer   * inbuf,
571                     uint32_t          * setme )
572{
573    uint32_t tmp;
574    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint32_t) );
575    *setme = ntohl( tmp );
576}
577
578void
579tr_peerIoDrain( tr_peerIo        * io,
580                struct evbuffer  * inbuf,
581                size_t             byteCount )
582{
583    uint8_t * tmp = tr_new( uint8_t, byteCount );
584    tr_peerIoReadBytes( io, inbuf, tmp, byteCount );
585    tr_free( tmp );
586}
587
588int
589tr_peerGetAge( const tr_peerIo * io )
590{
591    return time( NULL ) - io->timeCreated;
592}
Note: See TracBrowser for help on using the repository browser.