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

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

(libT) more win32 work copied from spry's code:
(1) add #define for {read,write,strncasecmp} -> {_read,_write,_strnicmp}
(2) fix a couple more variadic macros that didn't get fixed in the last commit
(3) use evutil_strtoll() instead of strtoll()

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