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

Last change on this file since 7137 was 7137, checked in by charles, 13 years ago

(libT) #1468: speed display is very jumpy

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