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

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

threads. gotta love 'em.

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