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

Last change on this file since 7055 was 7055, checked in by charles, 10 years ago

update NEWS

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