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

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

commit the next step of tiennou's fastpeers code.

  • Property svn:keywords set to Date Rev Author Id
File size: 12.8 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 3227 2007-09-28 16:40:21Z 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              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                      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                      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        tr_bufferevent_free( c->handle, 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_peerIoGetAddrStr( const tr_peerIo * io )
208{
209    static char buf[512];
210    assert( io != NULL );
211    snprintf( buf, sizeof(buf), "%s:%u", inet_ntoa( io->in_addr ), (unsigned int)io->port );
212    return buf;
213}
214
215void 
216tr_peerIoSetIOFuncs( tr_peerIo          * io,
217                     tr_can_read_cb       readcb,
218                     tr_did_write_cb      writecb,
219                     tr_net_error_cb      errcb,
220                     void               * userData )
221{
222    io->canRead = readcb;
223    io->didWrite = writecb;
224    io->gotError = errcb;
225    io->userData = userData;
226
227    if( EVBUFFER_LENGTH( io->bufev->input ) )
228        canReadWrapper( io->bufev, io );
229}
230
231void
232tr_peerIoSetIOMode( tr_peerIo * c, short enable, short disable )
233{
234    tr_setBufferEventMode( c->handle, c->bufev, enable, disable );
235}
236
237int
238tr_peerIoIsIncoming( const tr_peerIo * c )
239{
240    return c->isIncoming ? 1 : 0;
241}
242
243int
244tr_peerIoReconnect( tr_peerIo * io )
245{
246    assert( !tr_peerIoIsIncoming( io ) );
247
248    if( io->socket >= 0 )
249        tr_netClose( io->socket );
250
251    io->socket = tr_netOpenTCP( &io->in_addr, io->port, 0 );
252 
253    if( io->socket >= 0 )
254    {
255        bufferevent_free( io->bufev );
256
257        io->bufev = bufferevent_new( io->socket,
258                                     canReadWrapper,
259                                     didWriteWrapper,
260                                     gotErrorWrapper,
261                                     io );
262        bufferevent_enable( io->bufev, EV_READ|EV_WRITE );
263
264        return 0;
265    }
266 
267    return -1;
268}
269
270/**
271***
272**/
273
274void
275tr_peerIoSetTorrentHash( tr_peerIo     * io,
276                         const uint8_t * hash )
277{
278    assert( io != NULL );
279
280    tr_cryptoSetTorrentHash( io->crypto, hash );
281}
282
283const uint8_t*
284tr_peerIoGetTorrentHash( tr_peerIo * io )
285{
286    assert( io != NULL );
287    assert( io->crypto != NULL );
288
289    return tr_cryptoGetTorrentHash( io->crypto );
290}
291
292int
293tr_peerIoHasTorrentHash( const tr_peerIo * io )
294{
295    assert( io != NULL );
296    assert( io->crypto != NULL );
297
298    return tr_cryptoHasTorrentHash( io->crypto );
299}
300
301/**
302***
303**/
304
305void
306tr_peerIoSetPeersId( tr_peerIo     * io,
307                     const uint8_t * peer_id )
308{
309    assert( io != NULL );
310
311    if(( io->peerIdIsSet = peer_id != NULL ))
312        memcpy( io->peerId, peer_id, 20 );
313    else
314        memset( io->peerId, 0, 20 );
315}
316
317const uint8_t* 
318tr_peerIoGetPeersId( const tr_peerIo * io )
319{
320    assert( io != NULL );
321    assert( io->peerIdIsSet );
322
323    return io->peerId;
324}
325
326/**
327***
328**/
329
330void
331tr_peerIoEnableAZMP( tr_peerIo * io, int flag )
332{
333    assert( io != NULL );
334    assert( flag==0 || flag==1 );
335   
336    io->extensions.azureusProtocolSupported = flag;
337}
338
339void
340tr_peerIoEnableLTEP( tr_peerIo * io, int flag )
341{
342    assert( io != NULL );
343    assert( flag==0 || flag==1 );
344   
345    io->extensions.extendedProtocolSupported = flag;
346}
347
348void
349tr_peerIoEnableFEXT( tr_peerIo * io, int flag )
350{
351    assert( io != NULL );
352    assert( flag==0 || flag==1 );
353   
354    io->extensions.fastPeersSupported = flag;
355}
356
357int
358tr_peerIoSupportsAZMP( const tr_peerIo * io )
359{
360    assert( io != NULL );
361   
362    return io->extensions.azureusProtocolSupported;
363}
364
365int
366tr_peerIoSupportsLTEP( const tr_peerIo * io )
367{
368    assert( io != NULL );
369   
370    return io->extensions.extendedProtocolSupported;
371}
372
373int
374tr_peerIoSupportsFEXT( const tr_peerIo * io )
375{
376    assert( io != NULL );
377   
378    return io->extensions.fastPeersSupported;
379}
380/**
381***
382**/
383
384size_t
385tr_peerIoWriteBytesWaiting( const tr_peerIo * io )
386{
387    return EVBUFFER_LENGTH( EVBUFFER_OUTPUT( io->bufev ) );
388}
389 
390void
391tr_peerIoWrite( tr_peerIo   * io,
392                const void  * writeme,
393                int           writeme_len )
394{
395    tr_bufferevent_write( io->handle, io->bufev, writeme, writeme_len );
396    tr_rcTransferred( io->rateToPeer, writeme_len );
397}
398
399void
400tr_peerIoWriteBuf( tr_peerIo       * io,
401                   struct evbuffer * buf )
402{
403    tr_peerIoWrite( io, EVBUFFER_DATA(buf), EVBUFFER_LENGTH(buf) );
404    evbuffer_drain( buf, ~0 );
405}
406
407/**
408***
409**/
410
411tr_crypto* 
412tr_peerIoGetCrypto( tr_peerIo * c )
413{
414    return c->crypto;
415}
416
417void 
418tr_peerIoSetEncryption( tr_peerIo * io,
419                        int         encryptionMode )
420{
421    assert( io != NULL );
422    assert( encryptionMode==PEER_ENCRYPTION_NONE || encryptionMode==PEER_ENCRYPTION_RC4 );
423
424    io->encryptionMode = encryptionMode;
425}
426
427int
428tr_peerIoIsEncrypted( const tr_peerIo * io )
429{
430    return io!=NULL && io->encryptionMode==PEER_ENCRYPTION_RC4;
431}
432
433void
434tr_peerIoWriteBytes( tr_peerIo        * io,
435                     struct evbuffer  * outbuf,
436                     const void       * bytes,
437                     int                byteCount )
438{
439    uint8_t * tmp;
440
441    switch( io->encryptionMode )
442    {
443        case PEER_ENCRYPTION_NONE:
444            /*fprintf( stderr, "writing %d plaintext bytes to outbuf...\n", byteCount );*/
445            evbuffer_add( outbuf, bytes, byteCount );
446            break;
447
448        case PEER_ENCRYPTION_RC4:
449            /*fprintf( stderr, "encrypting and writing %d bytes to outbuf...\n", byteCount );*/
450            tmp = tr_new( uint8_t, byteCount );
451            tr_cryptoEncrypt( io->crypto, byteCount, bytes, tmp );
452            evbuffer_add( outbuf, tmp, byteCount );
453            tr_free( tmp );
454            break;
455
456        default:
457            assert( 0 );
458    }
459}
460
461void
462tr_peerIoWriteUint16( tr_peerIo        * io,
463                      struct evbuffer  * outbuf,
464                      uint16_t           writeme )
465{
466    uint16_t tmp = htons( writeme );
467    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint16_t) );
468}
469
470void
471tr_peerIoWriteUint8( tr_peerIo        * io,
472                     struct evbuffer  * outbuf,
473                     uint8_t            writeme )
474{
475    tr_peerIoWriteBytes( io, outbuf, &writeme, sizeof(uint8_t) );
476}
477
478void
479tr_peerIoWriteUint32( tr_peerIo        * io,
480                      struct evbuffer  * outbuf,
481                      uint32_t           writeme )
482{
483    uint32_t tmp = htonl( writeme );
484    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint32_t) );
485}
486
487void
488tr_peerIoReadBytes( tr_peerIo        * io,
489                    struct evbuffer  * inbuf,
490                    void             * bytes,
491                    int                byteCount )
492{
493    assert( (int)EVBUFFER_LENGTH( inbuf ) >= byteCount );
494
495    switch( io->encryptionMode )
496    {
497        case PEER_ENCRYPTION_NONE:
498            /*fprintf( stderr, "reading %d plaintext bytes from inbuf...\n", byteCount );*/
499            evbuffer_remove(  inbuf, bytes, byteCount );
500            tr_rcTransferred( io->rateToClient, byteCount );
501            break;
502
503        case PEER_ENCRYPTION_RC4:
504            /*fprintf( stderr, "reading AND DECRYPTING %d bytes from inbuf...\n", byteCount );*/
505            evbuffer_remove(  inbuf, bytes, byteCount );
506            tr_cryptoDecrypt( io->crypto, byteCount, bytes, bytes );
507            tr_rcTransferred( io->rateToClient, byteCount );
508            break;
509
510        default:
511            assert( 0 );
512    }
513}
514
515void
516tr_peerIoReadUint16( tr_peerIo         * io,
517                     struct evbuffer   * inbuf,
518                     uint16_t          * setme )
519{
520    uint16_t tmp;
521    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint16_t) );
522    *setme = ntohs( tmp );
523}
524
525void
526tr_peerIoReadUint8( tr_peerIo         * io,
527                    struct evbuffer   * inbuf,
528                    uint8_t           * setme )
529{
530    tr_peerIoReadBytes( io, inbuf, setme, sizeof(uint8_t) );
531}
532
533void
534tr_peerIoReadUint32( tr_peerIo         * io,
535                     struct evbuffer   * inbuf,
536                     uint32_t          * setme )
537{
538    uint32_t tmp;
539    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint32_t) );
540    *setme = ntohl( tmp );
541}
542
543void
544tr_peerIoDrain( tr_peerIo        * io,
545                struct evbuffer  * inbuf,
546                int                byteCount )
547{
548    uint8_t * tmp = tr_new( uint8_t, byteCount );
549    tr_peerIoReadBytes( io, inbuf, tmp, byteCount );
550    tr_free( tmp );
551}
552
553/**
554***
555**/
556
557float
558tr_peerIoGetRateToClient( const tr_peerIo * io )
559{
560    return io==NULL ? 0.0f : tr_rcRate( io->rateToClient );
561
562}
563
564float
565tr_peerIoGetRateToPeer( const tr_peerIo * io )
566{
567    return io==NULL ? 0.0f : tr_rcRate( io->rateToPeer );
568}
569
Note: See TracBrowser for help on using the repository browser.