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

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