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

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

fix OpenBSD build error.

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