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

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

fix some memory issues.

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