source: branches/encryption/libtransmission/peer-io.c @ 2963

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

get per-peer ul/dl rate measurement working again.

  • Property svn:keywords set to Date Rev Author Id
File size: 10.5 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 2963 2007-09-01 03:17:40Z 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_peerIo
32{
33    struct tr_handle * handle;
34
35    struct in_addr in_addr;
36    int port;
37    int socket;
38    int extensions;
39    int encryptionMode;
40    struct bufferevent * bufev;
41    uint8_t peerId[20];
42
43    unsigned int isEncrypted : 1;
44    unsigned int isIncoming : 1;
45    unsigned int peerIdIsSet : 1;
46
47    tr_ratecontrol   * rateToPeer;
48    tr_ratecontrol   * rateToClient;
49
50    tr_can_read_cb     canRead;
51    tr_did_write_cb    didWrite;
52    tr_net_error_cb    gotError;
53    void             * userData;
54
55    tr_crypto * crypto;
56};
57
58/**
59***
60**/
61
62static void
63didWriteWrapper( struct bufferevent * e, void * userData )
64{
65    tr_peerIo * c = (tr_peerIo *) userData;
66    assert( c->didWrite != NULL );
67    (*c->didWrite)( e, c->userData );
68}
69
70static void
71canReadWrapper( struct bufferevent * e, void * userData )
72{
73    tr_peerIo * c = (tr_peerIo *) userData;
74
75    assert( c->canRead != NULL );
76
77    for( ;; ) {
78        const int ret = (*c->canRead)( e, c->userData );
79        switch( ret ) {
80            case READ_AGAIN: if( EVBUFFER_LENGTH( e->input ) ) continue; /* note fall-through */
81            case READ_MORE: fprintf( stderr, "waiting for bytes from peer...\n" );
82                            tr_peerIoSetIOMode( c, EV_READ, 0 ); return; break;
83            case READ_DONE: return; fprintf( stderr, "READ_DONE\n"); break;
84        }
85    }
86}
87
88static void
89gotErrorWrapper( struct bufferevent * e, short what, void * userData )
90{
91    tr_peerIo * c = (tr_peerIo *) userData;
92    assert( c->gotError != NULL );
93    (*c->gotError)( e, what, c->userData );
94}
95
96/**
97***
98**/
99
100static tr_peerIo*
101tr_peerIoNew( struct tr_handle  * handle,
102              struct in_addr    * in_addr,
103              const uint8_t     * torrentHash,
104              int                 isIncoming,
105              int                 socket )
106{
107    tr_peerIo * c;
108    c = tr_new0( tr_peerIo, 1 );
109    c->crypto = tr_cryptoNew( torrentHash, isIncoming );
110    c->handle = handle;
111    c->in_addr = *in_addr;
112    c->socket = socket;
113    c->rateToPeer = tr_rcInit( );
114    c->rateToClient = tr_rcInit( );
115    c->bufev = bufferevent_new( c->socket,
116                                canReadWrapper,
117                                didWriteWrapper,
118                                gotErrorWrapper,
119                                c );
120    return c;
121}
122
123tr_peerIo*
124tr_peerIoNewIncoming( struct tr_handle  * handle,
125                      struct in_addr    * in_addr,
126                      int                 socket )
127{
128    tr_peerIo * c =
129        tr_peerIoNew( handle, in_addr, NULL, 1, socket );
130    c->port = -1;
131    return c;
132}
133
134tr_peerIo*
135tr_peerIoNewOutgoing( struct tr_handle  * handle,
136                      struct in_addr    * in_addr,
137                      int                 port,
138                      const uint8_t     * torrentHash )
139{
140    tr_peerIo * c;
141
142    assert( handle != NULL );
143    assert( in_addr != NULL );
144    assert( port >= 0 );
145    assert( torrentHash != NULL );
146
147    c = tr_peerIoNew( handle, in_addr, torrentHash, 0,
148                              tr_netOpenTCP( in_addr, port, 0 ) );
149    c->port = port;
150    return c;
151}
152
153void
154tr_peerIoFree( tr_peerIo * c )
155{
156    bufferevent_free( c->bufev );
157    tr_rcClose( c->rateToClient );
158    tr_rcClose( c->rateToPeer );
159    tr_netClose( c->socket );
160    tr_cryptoFree( c->crypto );
161    tr_free( c );
162}
163
164tr_handle*
165tr_peerIoGetHandle( tr_peerIo * io )
166{
167    assert( io != NULL );
168    assert( io->handle != NULL );
169
170    return io->handle;
171}
172
173const struct in_addr*
174tr_peerIoGetAddress( const tr_peerIo * io, uint16_t * port )
175{
176    assert( io != NULL );
177
178    if( port != NULL )
179       *port = io->port;
180
181    return &io->in_addr;
182}
183
184void 
185tr_peerIoSetIOFuncs( tr_peerIo          * io,
186                     tr_can_read_cb       readcb,
187                     tr_did_write_cb      writecb,
188                     tr_net_error_cb      errcb,
189                     void               * userData )
190{
191    io->canRead = readcb;
192    io->didWrite = writecb;
193    io->gotError = errcb;
194    io->userData = userData;
195
196    if( EVBUFFER_LENGTH( io->bufev->input ) )
197        canReadWrapper( io->bufev, io );
198}
199
200void
201tr_peerIoSetIOMode( tr_peerIo * c, short enable, short disable )
202{
203    tr_setBufferEventMode( c->handle, c->bufev, enable, disable );
204}
205
206void
207tr_peerIoReadOrWait( tr_peerIo * c )
208{
209    if( EVBUFFER_LENGTH( c->bufev->input ) )
210        canReadWrapper( c->bufev, c );
211    else
212        tr_peerIoSetIOMode( c, EV_READ, EV_WRITE );
213}
214
215int
216tr_peerIoIsIncoming( const tr_peerIo * c )
217{
218    return c->isIncoming;
219}
220
221int
222tr_peerIoReconnect( tr_peerIo * io )
223{
224    assert( !tr_peerIoIsIncoming( io ) );
225
226    if( io->socket >= 0 )
227        tr_netClose( io->socket );
228
229    io->socket = tr_netOpenTCP( &io->in_addr,
230                                        io->port, 0 );
231
232    return io->socket >= 0 ? 0 : -1;
233}
234
235/**
236***
237**/
238
239void
240tr_peerIoSetTorrentHash( tr_peerIo     * io,
241                         const uint8_t * hash )
242{
243    tr_cryptoSetTorrentHash( io->crypto, hash );
244}
245
246const uint8_t*
247tr_peerIoGetTorrentHash( tr_peerIo * io )
248{
249    return tr_cryptoGetTorrentHash( io->crypto );
250}
251
252/**
253***
254**/
255
256void
257tr_peerIoSetPeersId( tr_peerIo     * io,
258                     const uint8_t * peer_id )
259{
260    assert( io != NULL );
261
262    if(( io->peerIdIsSet = peer_id != NULL ))
263        memcpy( io->peerId, peer_id, 20 );
264    else
265        memset( io->peerId, 0, 20 );
266}
267
268const uint8_t* 
269tr_peerIoGetPeersId( const tr_peerIo * io )
270{
271    assert( io != NULL );
272    assert( io->peerIdIsSet );
273
274    return io->peerId;
275}
276
277/**
278***
279**/
280
281void
282tr_peerIoSetExtension( tr_peerIo   * io,
283                       int           extensions )
284{
285    assert( io != NULL );
286    assert( ( extensions == LT_EXTENSIONS_NONE )
287         || ( extensions == LT_EXTENSIONS_LTEP )
288         || ( extensions == LT_EXTENSIONS_AZMP ) );
289
290    io->extensions = extensions;
291}
292
293int
294tr_peerIoGetExtension( const tr_peerIo * io )
295{
296    assert( io != NULL );
297
298    return io->extensions;
299}
300
301/**
302***
303**/
304 
305void
306tr_peerIoWrite( tr_peerIo   * io,
307                const void  * writeme,
308                int           writeme_len )
309{
310    tr_bufferevent_write( io->handle, io->bufev, writeme, writeme_len );
311    tr_rcTransferred( io->rateToPeer, writeme_len );
312}
313
314void
315tr_peerIoWriteBuf( tr_peerIo             * io,
316                   const struct evbuffer * buf )
317{
318    tr_peerIoWrite( io, EVBUFFER_DATA(buf), EVBUFFER_LENGTH(buf) );
319}
320
321/**
322***
323**/
324
325tr_crypto* 
326tr_peerIoGetCrypto( tr_peerIo * c )
327{
328    return c->crypto;
329}
330
331void 
332tr_peerIoSetEncryption( tr_peerIo * io,
333                        int         encryptionMode )
334{
335    assert( io != NULL );
336    assert( encryptionMode==PEER_ENCRYPTION_PLAINTEXT || encryptionMode==PEER_ENCRYPTION_RC4 );
337
338    io->encryptionMode = encryptionMode;
339}
340
341void
342tr_peerIoWriteBytes( tr_peerIo        * io,
343                     struct evbuffer  * outbuf,
344                     const void       * bytes,
345                     int                byteCount )
346{
347    uint8_t * tmp;
348
349    switch( io->encryptionMode )
350    {
351        case PEER_ENCRYPTION_PLAINTEXT:
352            fprintf( stderr, "writing %d plaintext bytes to outbuf...\n", byteCount );
353            evbuffer_add( outbuf, bytes, byteCount );
354            break;
355
356        case PEER_ENCRYPTION_RC4:
357            fprintf( stderr, "encrypting and writing %d bytes to outbuf...\n", byteCount );
358            tmp = tr_new( uint8_t, byteCount );
359            tr_cryptoEncrypt( io->crypto, byteCount, bytes, tmp );
360            tr_bufferevent_write( io->handle, io->bufev, tmp, byteCount );
361            tr_free( tmp );
362            break;
363
364        default:
365            assert( 0 );
366    }
367}
368
369void
370tr_peerIoWriteUint16( tr_peerIo        * io,
371                      struct evbuffer  * outbuf,
372                      uint16_t           writeme )
373{
374    uint16_t tmp = htons( writeme );
375    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint16_t) );
376}
377
378void
379tr_peerIoWriteUint32( tr_peerIo        * io,
380                      struct evbuffer  * outbuf,
381                      uint32_t           writeme )
382{
383    uint32_t tmp = htonl( writeme );
384    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof(uint32_t) );
385}
386
387void
388tr_peerIoReadBytes( tr_peerIo        * io,
389                    struct evbuffer  * inbuf,
390                    void             * bytes,
391                    int                byteCount )
392{
393    assert( (int)EVBUFFER_LENGTH( inbuf ) >= byteCount );
394
395    switch( io->encryptionMode )
396    {
397        case PEER_ENCRYPTION_PLAINTEXT:
398            fprintf( stderr, "reading %d plaintext bytes from inbuf...\n", byteCount );
399            evbuffer_remove(  inbuf, bytes, byteCount );
400            tr_rcTransferred( io->rateToClient, byteCount );
401            break;
402
403        case PEER_ENCRYPTION_RC4:
404            fprintf( stderr, "reading and decrypting %d bytes from inbuf...\n", byteCount );
405            evbuffer_remove(  inbuf, bytes, byteCount );
406            tr_cryptoDecrypt( io->crypto, byteCount, bytes, bytes );
407            tr_rcTransferred( io->rateToClient, byteCount );
408            break;
409
410        default:
411            assert( 0 );
412    }
413}
414
415void
416tr_peerIoReadUint16( tr_peerIo         * io,
417                     struct evbuffer   * inbuf,
418                     uint16_t          * setme )
419{
420    uint16_t tmp;
421    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint16_t) );
422    *setme = ntohs( tmp );
423}
424
425void
426tr_peerIoReadUint32( tr_peerIo         * io,
427                     struct evbuffer   * inbuf,
428                     uint32_t          * setme )
429{
430    uint32_t tmp;
431    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof(uint32_t) );
432    *setme = ntohl( tmp );
433}
434
435void
436tr_peerIoDrain( tr_peerIo        * io,
437                struct evbuffer  * inbuf,
438                int                byteCount )
439{
440    uint8_t * tmp = tr_new( uint8_t, byteCount );
441    tr_peerIoReadBytes( io, inbuf, tmp, byteCount );
442    tr_free( tmp );
443}
444
445/**
446***
447**/
448
449float
450tr_peerIoGetRateToClient( const tr_peerIo * io )
451{
452    return io==NULL ? 0.0f : tr_rcRate( io->rateToClient );
453
454}
455
456float
457tr_peerIoGetRateToPeer( const tr_peerIo * io )
458{
459    return io==NULL ? 0.0f : tr_rcRate( io->rateToPeer );
460}
461
Note: See TracBrowser for help on using the repository browser.