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

Last change on this file since 7133 was 7133, checked in by charles, 14 years ago

(libT) define peer connections' sockets' so_sndbuf size in the tr_session struct.

  • Property svn:keywords set to Date Rev Author Id
File size: 20.9 KB
Line 
1/*
2 * This file Copyright (C) 2007-2008 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 7133 2008-11-21 16:32:55Z charles $
11 */
12
13#include <assert.h>
14#include <limits.h> /* INT_MAX */
15#include <string.h>
16#include <stdio.h>
17#include <unistd.h>
18
19#ifdef WIN32
20 #include <winsock2.h>
21#else
22 #include <netinet/in.h> /* struct in_addr */
23 #include <arpa/inet.h> /* inet_ntoa */
24#endif
25
26#include <event.h>
27
28#include "transmission.h"
29#include "crypto.h"
30#include "list.h"
31#include "net.h"
32#include "peer-io.h"
33#include "ratecontrol.h"
34#include "trevent.h"
35#include "utils.h"
36
37#define IO_TIMEOUT_SECS 8
38
39static size_t
40addPacketOverhead( size_t d )
41{
42    /**
43     * http://sd.wareonearth.com/~phil/net/overhead/
44     *
45     * TCP over Ethernet:
46     * Assuming no header compression (e.g. not PPP)
47     * Add 20 IPv4 header or 40 IPv6 header (no options)
48     * Add 20 TCP header
49     * Add 12 bytes optional TCP timestamps
50     * Max TCP Payload data rates over ethernet are thus:
51     *  (1500-40)/(38+1500) = 94.9285 %  IPv4, minimal headers
52     *  (1500-52)/(38+1500) = 94.1482 %  IPv4, TCP timestamps
53     *  (1500-52)/(42+1500) = 93.9040 %  802.1q, IPv4, TCP timestamps
54     *  (1500-60)/(38+1500) = 93.6281 %  IPv6, minimal headers
55     *  (1500-72)/(38+1500) = 92.8479 %  IPv6, TCP timestamps
56     *  (1500-72)/(42+1500) = 92.6070 %  802.1q, IPv6, ICP timestamps
57     */
58    static const double assumed_payload_data_rate = 94.0;
59
60    return (size_t)( d * ( 100.0 / assumed_payload_data_rate ) );
61}
62
63/**
64***
65**/
66
67#define dbgmsg( io, ... ) \
68    do { \
69        if( tr_deepLoggingIsActive( ) ) \
70            tr_deepLog( __FILE__, __LINE__, tr_peerIoGetAddrStr( io ), __VA_ARGS__ ); \
71    } while( 0 )
72
73struct tr_bandwidth
74{
75    unsigned int    isUnlimited : 1;
76    size_t          bytesUsed;
77    size_t          bytesLeft;
78};
79
80struct tr_datatype
81{
82    unsigned int    isPieceData : 1;
83    size_t          length;
84};
85
86struct tr_peerIo
87{
88    unsigned int           isEncrypted               : 1;
89    unsigned int           isIncoming                : 1;
90    unsigned int           peerIdIsSet               : 1;
91    unsigned int           extendedProtocolSupported : 1;
92    unsigned int           fastPeersSupported        : 1;
93
94    uint8_t                encryptionMode;
95    uint8_t                timeout;
96    uint16_t               port;
97    int                    socket;
98
99    uint8_t                peerId[20];
100    time_t                 timeCreated;
101
102    tr_session           * session;
103
104    struct in_addr         in_addr;
105    struct bufferevent   * bufev;
106    struct evbuffer      * output;
107    tr_list              * output_datatypes; /* struct tr_datatype */
108
109    tr_can_read_cb         canRead;
110    tr_did_write_cb        didWrite;
111    tr_net_error_cb        gotError;
112    void *                 userData;
113
114    size_t                 bufferSize[2];
115
116    struct tr_bandwidth    bandwidth[2];
117
118    tr_crypto *            crypto;
119};
120
121/**
122***
123**/
124
125static void
126adjustOutputBuffer( tr_peerIo * io )
127{
128    struct evbuffer * live = EVBUFFER_OUTPUT( io->bufev );
129
130    if( io->bandwidth[TR_UP].isUnlimited )
131    {
132        bufferevent_write_buffer( io->bufev, io->output );
133    }
134    else if( io->bandwidth[TR_UP].bytesLeft > EVBUFFER_LENGTH( live ) )
135    {
136        /* there's free space in bufev's output buffer;
137           try to fill it up */
138        const size_t desiredLength = io->bandwidth[TR_UP].bytesLeft;
139        const size_t under = desiredLength - EVBUFFER_LENGTH( live );
140        const size_t n = MIN( under, EVBUFFER_LENGTH( io->output ) );
141        bufferevent_write( io->bufev, EVBUFFER_DATA( io->output ), n );
142        evbuffer_drain( io->output, n );
143    }
144    else if( io->bandwidth[TR_UP].bytesLeft < EVBUFFER_LENGTH( live ) )
145    {
146        /* bufev's output buffer exceeds our bandwidth allocation;
147           move the excess out of bufev so it can't be sent yet */
148        const size_t      desiredLength = io->bandwidth[TR_UP].bytesLeft;
149        const size_t      over = EVBUFFER_LENGTH( live ) - desiredLength;
150        struct evbuffer * buf = evbuffer_new( );
151        evbuffer_add( buf, EVBUFFER_DATA( live ) + desiredLength, over );
152        evbuffer_add_buffer( buf, io->output );
153        evbuffer_free( io->output );
154        io->output = buf;
155        EVBUFFER_LENGTH( live ) = desiredLength;
156    }
157
158    if( EVBUFFER_LENGTH( live ) )
159    {
160        bufferevent_enable( io->bufev, EV_WRITE );
161    }
162
163    io->bufferSize[TR_UP] = EVBUFFER_LENGTH( live );
164
165    dbgmsg( io, "after adjusting the output buffer, its size is now %zu",
166            io->bufferSize[TR_UP] );
167}
168
169static void
170adjustInputBuffer( tr_peerIo * io )
171{
172    if( io->bandwidth[TR_DOWN].isUnlimited )
173    {
174        dbgmsg( io, "unlimited reading..." );
175        bufferevent_setwatermark( io->bufev, EV_READ, 0, 0 );
176        bufferevent_enable( io->bufev, EV_READ );
177    }
178    else
179    {
180        const size_t n = io->bandwidth[TR_DOWN].bytesLeft;
181        if( n == 0 )
182        {
183            dbgmsg( io, "disabling reads because we've hit our limit" );
184            bufferevent_disable( io->bufev, EV_READ );
185        }
186        else
187        {
188            dbgmsg( io, "enabling reading of %zu more bytes", n );
189            bufferevent_setwatermark( io->bufev, EV_READ, 0, n );
190            bufferevent_enable( io->bufev, EV_READ );
191        }
192    }
193}
194
195/***
196****
197***/
198
199static void
200didWriteWrapper( struct bufferevent * e,
201                 void *               vio )
202{
203    tr_peerIo *  io = vio;
204    const size_t len = EVBUFFER_LENGTH( EVBUFFER_OUTPUT( e ) );
205
206    dbgmsg( io, "didWrite... io->outputBufferSize was %zu, is now %zu",
207            io->bufferSize[TR_UP], len );
208
209    if( len < io->bufferSize[TR_UP] )
210    {
211        size_t payload = io->bufferSize[TR_UP] - len;
212
213        while( payload )
214        {
215            struct tr_datatype * next = io->output_datatypes->data;
216            const size_t chunk_length = MIN( next->length, payload );
217            const size_t n = addPacketOverhead( chunk_length );
218
219            if( next->isPieceData )
220            {
221                struct tr_bandwidth * b = &io->bandwidth[TR_UP];
222                b->bytesLeft -= MIN( b->bytesLeft, n );
223                b->bytesUsed += n;
224            }
225
226            if( io->didWrite )
227                io->didWrite( io, n, next->isPieceData, io->userData );
228
229            payload -= chunk_length;
230            next->length -= chunk_length;
231            if( !next->length )
232                tr_free( tr_list_pop_front( &io->output_datatypes ) );
233        }
234    }
235
236    adjustOutputBuffer( io );
237
238}
239
240static void
241canReadWrapper( struct bufferevent * e,
242                void *               vio )
243{
244    int          done = 0;
245    int          err = 0;
246    tr_peerIo *  io = vio;
247    tr_session * session = io->session;
248    const size_t len = EVBUFFER_LENGTH( EVBUFFER_INPUT( e ) );
249
250    dbgmsg( io, "canRead" );
251
252    /* if the input buffer has grown, record the bytes that were read */
253    if( len > io->bufferSize[TR_DOWN] )
254    {
255        const size_t payload = len - io->bufferSize[TR_DOWN];
256        const size_t n = addPacketOverhead( payload );
257        struct tr_bandwidth * b = io->bandwidth + TR_DOWN;
258        b->bytesLeft -= MIN( b->bytesLeft, (size_t)n );
259        b->bytesUsed += n;
260        dbgmsg( io, "%zu new input bytes. bytesUsed is %zu, bytesLeft is %zu", n, b->bytesUsed, b->bytesLeft );
261
262        adjustInputBuffer( io );
263    }
264
265    /* try to consume the input buffer */
266    if( io->canRead )
267    {
268        tr_globalLock( session );
269
270        while( !done && !err )
271        {
272            const int ret = io->canRead( e, io->userData );
273
274            switch( ret )
275            {
276                case READ_NOW:
277                    if( EVBUFFER_LENGTH( e->input ) )
278                        continue;
279                    done = 1;
280                    break;
281
282                case READ_LATER:
283                    done = 1;
284                    break;
285
286                case READ_ERR:
287                    err = 1;
288                    break;
289            }
290        }
291
292        tr_globalUnlock( session );
293    }
294
295    if( !err )
296        io->bufferSize[TR_DOWN] = EVBUFFER_LENGTH( EVBUFFER_INPUT( e ) );
297}
298
299static void
300gotErrorWrapper( struct bufferevent * e,
301                 short                what,
302                 void *               userData )
303{
304    tr_peerIo * c = userData;
305
306    if( c->gotError )
307        c->gotError( e, what, c->userData );
308}
309
310/**
311***
312**/
313
314static void
315bufevNew( tr_peerIo * io )
316{
317    io->bufev = bufferevent_new( io->socket,
318                                 canReadWrapper,
319                                 didWriteWrapper,
320                                 gotErrorWrapper,
321                                 io );
322
323    /* tell libevent to call didWriteWrapper after every write,
324     * not just when the write buffer is empty */
325    bufferevent_setwatermark( io->bufev, EV_WRITE, INT_MAX, 0 );
326
327    bufferevent_settimeout( io->bufev, io->timeout, io->timeout );
328
329    bufferevent_enable( io->bufev, EV_READ | EV_WRITE );
330}
331
332static tr_peerIo*
333tr_peerIoNew( tr_session *           session,
334              const struct in_addr * in_addr,
335              uint16_t               port,
336              const uint8_t *        torrentHash,
337              int                    isIncoming,
338              int                    socket )
339{
340    tr_peerIo * io;
341
342    if( socket >= 0 )
343        tr_netSetTOS( socket, session->peerSocketTOS );
344
345    io = tr_new0( tr_peerIo, 1 );
346    io->crypto = tr_cryptoNew( torrentHash, isIncoming );
347    io->session = session;
348    io->in_addr = *in_addr;
349    io->port = port;
350    io->socket = socket;
351    io->isIncoming = isIncoming != 0;
352    io->timeout = IO_TIMEOUT_SECS;
353    io->timeCreated = time( NULL );
354    io->output = evbuffer_new( );
355    io->bandwidth[TR_UP].isUnlimited = 1;
356    io->bandwidth[TR_DOWN].isUnlimited = 1;
357    bufevNew( io );
358    return io;
359}
360
361tr_peerIo*
362tr_peerIoNewIncoming( tr_session *           session,
363                      const struct in_addr * in_addr,
364                      uint16_t               port,
365                      int                    socket )
366{
367    assert( session );
368    assert( in_addr );
369    assert( socket >= 0 );
370
371    return tr_peerIoNew( session, in_addr, port,
372                         NULL, 1,
373                         socket );
374}
375
376tr_peerIo*
377tr_peerIoNewOutgoing( tr_session *           session,
378                      const struct in_addr * in_addr,
379                      int                    port,
380                      const uint8_t *        torrentHash )
381{
382    int socket;
383
384    assert( session );
385    assert( in_addr );
386    assert( port >= 0 );
387    assert( torrentHash );
388
389    socket = tr_netOpenTCP( session, in_addr, port );
390
391    return socket < 0
392           ? NULL
393           : tr_peerIoNew( session, in_addr, port, torrentHash, 0, socket );
394}
395
396static void
397io_dtor( void * vio )
398{
399    tr_peerIo * io = vio;
400
401    evbuffer_free( io->output );
402    bufferevent_free( io->bufev );
403    tr_netClose( io->socket );
404    tr_cryptoFree( io->crypto );
405    tr_list_free( &io->output_datatypes, tr_free );
406    tr_free( io );
407}
408
409void
410tr_peerIoFree( tr_peerIo * io )
411{
412    if( io )
413    {
414        io->canRead = NULL;
415        io->didWrite = NULL;
416        io->gotError = NULL;
417        tr_runInEventThread( io->session, io_dtor, io );
418    }
419}
420
421tr_session*
422tr_peerIoGetSession( tr_peerIo * io )
423{
424    assert( io );
425    assert( io->session );
426
427    return io->session;
428}
429
430const struct in_addr*
431tr_peerIoGetAddress( const tr_peerIo * io,
432                           uint16_t * port )
433{
434    assert( io );
435
436    if( port )
437        *port = io->port;
438
439    return &io->in_addr;
440}
441
442const char*
443tr_peerIoAddrStr( const struct in_addr * addr,
444                  uint16_t               port )
445{
446    static char buf[512];
447
448    tr_snprintf( buf, sizeof( buf ), "%s:%u", inet_ntoa( *addr ),
449                ntohs( port ) );
450    return buf;
451}
452
453const char*
454tr_peerIoGetAddrStr( const tr_peerIo * io )
455{
456    return tr_peerIoAddrStr( &io->in_addr, io->port );
457}
458
459static void
460tr_peerIoTryRead( tr_peerIo * io )
461{
462    if( EVBUFFER_LENGTH( io->bufev->input ) )
463        canReadWrapper( io->bufev, io );
464}
465
466void
467tr_peerIoSetIOFuncs( tr_peerIo *     io,
468                     tr_can_read_cb  readcb,
469                     tr_did_write_cb writecb,
470                     tr_net_error_cb errcb,
471                     void *          userData )
472{
473    io->canRead = readcb;
474    io->didWrite = writecb;
475    io->gotError = errcb;
476    io->userData = userData;
477
478    tr_peerIoTryRead( io );
479}
480
481int
482tr_peerIoIsIncoming( const tr_peerIo * c )
483{
484    return c->isIncoming ? 1 : 0;
485}
486
487int
488tr_peerIoReconnect( tr_peerIo * io )
489{
490    assert( !tr_peerIoIsIncoming( io ) );
491
492    if( io->socket >= 0 )
493        tr_netClose( io->socket );
494
495    io->socket = tr_netOpenTCP( io->session, &io->in_addr, io->port );
496
497    if( io->socket >= 0 )
498    {
499        tr_netSetTOS( io->socket, io->session->peerSocketTOS );
500
501        bufferevent_free( io->bufev );
502        bufevNew( io );
503        return 0;
504    }
505
506    return -1;
507}
508
509void
510tr_peerIoSetTimeoutSecs( tr_peerIo * io,
511                         int         secs )
512{
513    io->timeout = secs;
514    bufferevent_settimeout( io->bufev, io->timeout, io->timeout );
515    bufferevent_enable( io->bufev, EV_READ | EV_WRITE );
516}
517
518/**
519***
520**/
521
522void
523tr_peerIoSetTorrentHash( tr_peerIo *     io,
524                         const uint8_t * hash )
525{
526    assert( io );
527
528    tr_cryptoSetTorrentHash( io->crypto, hash );
529}
530
531const uint8_t*
532tr_peerIoGetTorrentHash( tr_peerIo * io )
533{
534    assert( io );
535    assert( io->crypto );
536
537    return tr_cryptoGetTorrentHash( io->crypto );
538}
539
540int
541tr_peerIoHasTorrentHash( const tr_peerIo * io )
542{
543    assert( io );
544    assert( io->crypto );
545
546    return tr_cryptoHasTorrentHash( io->crypto );
547}
548
549/**
550***
551**/
552
553void
554tr_peerIoSetPeersId( tr_peerIo *     io,
555                     const uint8_t * peer_id )
556{
557    assert( io );
558
559    if( ( io->peerIdIsSet = peer_id != NULL ) )
560        memcpy( io->peerId, peer_id, 20 );
561    else
562        memset( io->peerId, 0, 20 );
563}
564
565const uint8_t*
566tr_peerIoGetPeersId( const tr_peerIo * io )
567{
568    assert( io );
569    assert( io->peerIdIsSet );
570
571    return io->peerId;
572}
573
574/**
575***
576**/
577
578void
579tr_peerIoEnableLTEP( tr_peerIo * io,
580                     int         flag )
581{
582    assert( io );
583    assert( flag == 0 || flag == 1 );
584
585    io->extendedProtocolSupported = flag;
586}
587
588void
589tr_peerIoEnableFEXT( tr_peerIo * io,
590                     int         flag )
591{
592    assert( io );
593    assert( flag == 0 || flag == 1 );
594
595    io->fastPeersSupported = flag;
596}
597
598int
599tr_peerIoSupportsLTEP( const tr_peerIo * io )
600{
601    assert( io );
602
603    return io->extendedProtocolSupported;
604}
605
606int
607tr_peerIoSupportsFEXT( const tr_peerIo * io )
608{
609    assert( io );
610
611    return io->fastPeersSupported;
612}
613
614/**
615***
616**/
617
618size_t
619tr_peerIoGetBandwidthUsed( const tr_peerIo * io,
620                           tr_direction      direction )
621{
622    assert( io );
623    assert( direction == TR_UP || direction == TR_DOWN );
624    return io->bandwidth[direction].bytesUsed;
625}
626
627size_t
628tr_peerIoGetWriteBufferSpace( const tr_peerIo * io )
629{
630    const size_t desiredBufferLen = 4096;
631    const size_t currentLiveLen = EVBUFFER_LENGTH( EVBUFFER_OUTPUT( io->bufev ) );
632
633    const size_t currentLbufLen = EVBUFFER_LENGTH( io->output );
634    const size_t desiredLiveLen = io->bandwidth[TR_UP].isUnlimited
635                                ? INT_MAX
636                                : io->bandwidth[TR_UP].bytesLeft;
637
638    const size_t currentLen = currentLiveLen + currentLbufLen;
639    const size_t desiredLen = desiredBufferLen + desiredLiveLen;
640
641    size_t       freeSpace = 0;
642
643    if( desiredLen > currentLen )
644        freeSpace = desiredLen - currentLen;
645    else
646        freeSpace = 0;
647
648    return freeSpace;
649}
650
651void
652tr_peerIoSetBandwidth( tr_peerIo *  io,
653                       tr_direction direction,
654                       size_t       bytesLeft )
655{
656    struct tr_bandwidth * b;
657
658    assert( io );
659    assert( direction == TR_UP || direction == TR_DOWN );
660
661    b = io->bandwidth + direction;
662    b->isUnlimited = 0;
663    b->bytesUsed = 0;
664    b->bytesLeft = bytesLeft;
665
666    adjustOutputBuffer( io );
667    adjustInputBuffer( io );
668}
669
670void
671tr_peerIoSetBandwidthUnlimited( tr_peerIo *  io,
672                                tr_direction direction )
673{
674    struct tr_bandwidth * b;
675
676    assert( io );
677    assert( direction == TR_UP || direction == TR_DOWN );
678
679    b = io->bandwidth + direction;
680    b->isUnlimited = 1;
681    b->bytesUsed = 0;
682    b->bytesLeft = 0;
683
684    adjustInputBuffer( io );
685    adjustOutputBuffer( io );
686}
687
688/**
689***
690**/
691
692tr_crypto*
693tr_peerIoGetCrypto( tr_peerIo * c )
694{
695    return c->crypto;
696}
697
698void
699tr_peerIoSetEncryption( tr_peerIo * io,
700                        int         encryptionMode )
701{
702    assert( io );
703    assert( encryptionMode == PEER_ENCRYPTION_NONE
704          || encryptionMode == PEER_ENCRYPTION_RC4 );
705
706    io->encryptionMode = encryptionMode;
707}
708
709int
710tr_peerIoIsEncrypted( const tr_peerIo * io )
711{
712    return io != NULL && io->encryptionMode == PEER_ENCRYPTION_RC4;
713}
714
715/**
716***
717**/
718
719void
720tr_peerIoWrite( tr_peerIo   * io,
721                const void  * writeme,
722                size_t        writemeLen,
723                int           isPieceData )
724{
725    struct tr_datatype * datatype;
726    assert( tr_amInEventThread( io->session ) );
727    dbgmsg( io, "adding %zu bytes into io->output", writemeLen );
728
729    if( io->bandwidth[TR_UP].isUnlimited )
730        bufferevent_write( io->bufev, writeme, writemeLen );
731    else
732        evbuffer_add( io->output, writeme, writemeLen );
733
734    datatype = tr_new( struct tr_datatype, 1 );
735    datatype->isPieceData = isPieceData != 0;
736    datatype->length = writemeLen;
737    tr_list_append( &io->output_datatypes, datatype );
738
739    adjustOutputBuffer( io );
740}
741
742void
743tr_peerIoWriteBuf( tr_peerIo         * io,
744                   struct evbuffer   * buf,
745                   int                 isPieceData )
746{
747    const size_t n = EVBUFFER_LENGTH( buf );
748
749    tr_peerIoWrite( io, EVBUFFER_DATA( buf ), n, isPieceData );
750    evbuffer_drain( buf, n );
751}
752
753/**
754***
755**/
756
757void
758tr_peerIoWriteBytes( tr_peerIo *       io,
759                     struct evbuffer * outbuf,
760                     const void *      bytes,
761                     size_t            byteCount )
762{
763    uint8_t * tmp;
764
765    switch( io->encryptionMode )
766    {
767        case PEER_ENCRYPTION_NONE:
768            evbuffer_add( outbuf, bytes, byteCount );
769            break;
770
771        case PEER_ENCRYPTION_RC4:
772            tmp = tr_new( uint8_t, byteCount );
773            tr_cryptoEncrypt( io->crypto, byteCount, bytes, tmp );
774            evbuffer_add( outbuf, tmp, byteCount );
775            tr_free( tmp );
776            break;
777
778        default:
779            assert( 0 );
780    }
781}
782
783void
784tr_peerIoWriteUint8( tr_peerIo *       io,
785                     struct evbuffer * outbuf,
786                     uint8_t           writeme )
787{
788    tr_peerIoWriteBytes( io, outbuf, &writeme, sizeof( uint8_t ) );
789}
790
791void
792tr_peerIoWriteUint16( tr_peerIo *       io,
793                      struct evbuffer * outbuf,
794                      uint16_t          writeme )
795{
796    uint16_t tmp = htons( writeme );
797
798    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof( uint16_t ) );
799}
800
801void
802tr_peerIoWriteUint32( tr_peerIo *       io,
803                      struct evbuffer * outbuf,
804                      uint32_t          writeme )
805{
806    uint32_t tmp = htonl( writeme );
807
808    tr_peerIoWriteBytes( io, outbuf, &tmp, sizeof( uint32_t ) );
809}
810
811/***
812****
813***/
814
815void
816tr_peerIoReadBytes( tr_peerIo *       io,
817                    struct evbuffer * inbuf,
818                    void *            bytes,
819                    size_t            byteCount )
820{
821    assert( EVBUFFER_LENGTH( inbuf ) >= byteCount );
822
823    switch( io->encryptionMode )
824    {
825        case PEER_ENCRYPTION_NONE:
826            evbuffer_remove( inbuf, bytes, byteCount );
827            break;
828
829        case PEER_ENCRYPTION_RC4:
830            evbuffer_remove( inbuf, bytes, byteCount );
831            tr_cryptoDecrypt( io->crypto, byteCount, bytes, bytes );
832            break;
833
834        default:
835            assert( 0 );
836    }
837}
838
839void
840tr_peerIoReadUint8( tr_peerIo *       io,
841                    struct evbuffer * inbuf,
842                    uint8_t *         setme )
843{
844    tr_peerIoReadBytes( io, inbuf, setme, sizeof( uint8_t ) );
845}
846
847void
848tr_peerIoReadUint16( tr_peerIo *       io,
849                     struct evbuffer * inbuf,
850                     uint16_t *        setme )
851{
852    uint16_t tmp;
853
854    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof( uint16_t ) );
855    *setme = ntohs( tmp );
856}
857
858void
859tr_peerIoReadUint32( tr_peerIo *       io,
860                     struct evbuffer * inbuf,
861                     uint32_t *        setme )
862{
863    uint32_t tmp;
864
865    tr_peerIoReadBytes( io, inbuf, &tmp, sizeof( uint32_t ) );
866    *setme = ntohl( tmp );
867}
868
869void
870tr_peerIoDrain( tr_peerIo *       io,
871                struct evbuffer * inbuf,
872                size_t            byteCount )
873{
874    uint8_t * tmp = tr_new( uint8_t, byteCount );
875
876    tr_peerIoReadBytes( io, inbuf, tmp, byteCount );
877    tr_free( tmp );
878}
879
880int
881tr_peerIoGetAge( const tr_peerIo * io )
882{
883    return time( NULL ) - io->timeCreated;
884}
885
Note: See TracBrowser for help on using the repository browser.