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

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

(libT) low-hanging fruit discovered from softwareelves' shark profile.

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