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

Last change on this file since 3365 was 3365, checked in by charles, 15 years ago

8 second timeout during handshake, 2.5 minute handshake afterwards

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