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

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

more fucking around with the speed measurements.

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