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

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

don't log BT protocol messages in UL/DL speed -- only log piece data transfers.

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