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

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

Try out some of SoftwareElves?' suggestions for faster startup connections

  • Property svn:keywords set to Date Rev Author Id
File size: 12.4 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 3361 2007-10-11 02:50:05Z 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
290/**
291***
292**/
293
294void
295tr_peerIoSetTorrentHash( tr_peerIo     * io,
296                         const uint8_t * hash )
297{
298    assert( io != NULL );
299
300    tr_cryptoSetTorrentHash( io->crypto, hash );
301}
302
303const uint8_t*
304tr_peerIoGetTorrentHash( tr_peerIo * io )
305{
306    assert( io != NULL );
307    assert( io->crypto != NULL );
308
309    return tr_cryptoGetTorrentHash( io->crypto );
310}
311
312int
313tr_peerIoHasTorrentHash( const tr_peerIo * io )
314{
315    assert( io != NULL );
316    assert( io->crypto != NULL );
317
318    return tr_cryptoHasTorrentHash( io->crypto );
319}
320
321/**
322***
323**/
324
325void
326tr_peerIoSetPeersId( tr_peerIo     * io,
327                     const uint8_t * peer_id )
328{
329    assert( io != NULL );
330
331    if(( io->peerIdIsSet = peer_id != NULL ))
332        memcpy( io->peerId, peer_id, 20 );
333    else
334        memset( io->peerId, 0, 20 );
335}
336
337const uint8_t* 
338tr_peerIoGetPeersId( const tr_peerIo * io )
339{
340    assert( io != NULL );
341    assert( io->peerIdIsSet );
342
343    return io->peerId;
344}
345
346/**
347***
348**/
349
350void
351tr_peerIoEnableAZMP( tr_peerIo * io, int flag )
352{
353    assert( io != NULL );
354    assert( flag==0 || flag==1 );
355   
356    io->extensions.azureusProtocolSupported = flag;
357}
358
359void
360tr_peerIoEnableLTEP( tr_peerIo * io, int flag )
361{
362    assert( io != NULL );
363    assert( flag==0 || flag==1 );
364   
365    io->extensions.extendedProtocolSupported = flag;
366}
367
368void
369tr_peerIoEnableFEXT( tr_peerIo * io, int flag )
370{
371    assert( io != NULL );
372    assert( flag==0 || flag==1 );
373   
374    io->extensions.fastPeersSupported = flag;
375}
376
377int
378tr_peerIoSupportsAZMP( const tr_peerIo * io )
379{
380    assert( io != NULL );
381   
382    return io->extensions.azureusProtocolSupported;
383}
384
385int
386tr_peerIoSupportsLTEP( const tr_peerIo * io )
387{
388    assert( io != NULL );
389   
390    return io->extensions.extendedProtocolSupported;
391}
392
393int
394tr_peerIoSupportsFEXT( const tr_peerIo * io )
395{
396    assert( io != NULL );
397   
398    return io->extensions.fastPeersSupported;
399}
400/**
401***
402**/
403
404size_t
405tr_peerIoWriteBytesWaiting( const tr_peerIo * io )
406{
407    return EVBUFFER_LENGTH( EVBUFFER_OUTPUT( io->bufev ) );
408}
409 
410void
411tr_peerIoWrite( tr_peerIo   * io,
412                const void  * writeme,
413                int           writeme_len )
414{
415    tr_bufferevent_write( io->handle, io->bufev, writeme, writeme_len );
416}
417
418void
419tr_peerIoWriteBuf( tr_peerIo       * io,
420                   struct evbuffer * buf )
421{
422    tr_peerIoWrite( io, EVBUFFER_DATA(buf), EVBUFFER_LENGTH(buf) );
423    evbuffer_drain( buf, ~0 );
424}
425
426/**
427***
428**/
429
430tr_crypto* 
431tr_peerIoGetCrypto( tr_peerIo * c )
432{
433    return c->crypto;
434}
435
436void 
437tr_peerIoSetEncryption( tr_peerIo * io,
438                        int         encryptionMode )
439{
440    assert( io != NULL );
441    assert( encryptionMode==PEER_ENCRYPTION_NONE || encryptionMode==PEER_ENCRYPTION_RC4 );
442
443    io->encryptionMode = encryptionMode;
444}
445
446int
447tr_peerIoIsEncrypted( const tr_peerIo * io )
448{
449    return io!=NULL && io->encryptionMode==PEER_ENCRYPTION_RC4;
450}
451
452void
453tr_peerIoWriteBytes( tr_peerIo        * io,
454                     struct evbuffer  * outbuf,
455                     const void       * bytes,
456                     int                byteCount )
457{
458    uint8_t * tmp;
459
460    switch( io->encryptionMode )
461    {
462        case PEER_ENCRYPTION_NONE:
463            evbuffer_add( outbuf, bytes, byteCount );
464            break;
465
466        case PEER_ENCRYPTION_RC4:
467            tmp = tr_new( uint8_t, byteCount );
468            tr_cryptoEncrypt( io->crypto, byteCount, bytes, tmp );
469            evbuffer_add( outbuf, tmp, byteCount );
470            tr_free( tmp );
471            break;
472
473        default:
474            assert( 0 );
475    }
476}
477
478void
479tr_peerIoWriteUint16( tr_peerIo        * io,
480                      struct evbuffer  * outbuf,
481                      uint16_t           writeme )
482{
483    uint16_t tmp = htons( writeme );
484    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint16_t) );
485}
486
487void
488tr_peerIoWriteUint8( tr_peerIo        * io,
489                     struct evbuffer  * outbuf,
490                     uint8_t            writeme )
491{
492    tr_peerIoWriteBytes( io, outbuf, &writeme, sizeof(uint8_t) );
493}
494
495void
496tr_peerIoWriteUint32( tr_peerIo        * io,
497                      struct evbuffer  * outbuf,
498                      uint32_t           writeme )
499{
500    uint32_t tmp = htonl( writeme );
501    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint32_t) );
502}
503
504void
505tr_peerIoReadBytes( tr_peerIo        * io,
506                    struct evbuffer  * inbuf,
507                    void             * bytes,
508                    int                byteCount )
509{
510    assert( (int)EVBUFFER_LENGTH( inbuf ) >= byteCount );
511
512    switch( io->encryptionMode )
513    {
514        case PEER_ENCRYPTION_NONE:
515            evbuffer_remove(  inbuf, bytes, byteCount );
516            break;
517
518        case PEER_ENCRYPTION_RC4:
519            evbuffer_remove(  inbuf, bytes, byteCount );
520            tr_cryptoDecrypt( io->crypto, byteCount, bytes, bytes );
521            break;
522
523        default:
524            assert( 0 );
525    }
526}
527
528void
529tr_peerIoReadUint16( tr_peerIo         * io,
530                     struct evbuffer   * inbuf,
531                     uint16_t          * setme )
532{
533    uint16_t tmp;
534    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint16_t) );
535    *setme = ntohs( tmp );
536}
537
538void
539tr_peerIoReadUint8( tr_peerIo         * io,
540                    struct evbuffer   * inbuf,
541                    uint8_t           * setme )
542{
543    tr_peerIoReadBytes( io, inbuf, setme, sizeof(uint8_t) );
544}
545
546void
547tr_peerIoReadUint32( tr_peerIo         * io,
548                     struct evbuffer   * inbuf,
549                     uint32_t          * setme )
550{
551    uint32_t tmp;
552    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint32_t) );
553    *setme = ntohl( tmp );
554}
555
556void
557tr_peerIoDrain( tr_peerIo        * io,
558                struct evbuffer  * inbuf,
559                int                byteCount )
560{
561    uint8_t * tmp = tr_new( uint8_t, byteCount );
562    tr_peerIoReadBytes( io, inbuf, tmp, byteCount );
563    tr_free( tmp );
564}
Note: See TracBrowser for help on using the repository browser.