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

Last change on this file since 6425 was 6425, checked in by charles, 13 years ago

minor text cleanup

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