2007-09-20 16:32:01 +00:00
/*
2010-01-04 21:00:47 +00:00
* This file Copyright ( C ) 2007 - 2010 Mnemosyne LLC
2007-09-20 16:32:01 +00:00
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2 ( b )
2008-09-23 19:11:04 +00:00
* so that the bulk of its code can remain under the MIT license .
2007-09-20 16:32:01 +00:00
* This exemption does not extend to derived works not owned by
* the Transmission project .
*
* $ Id $
*/
2007-11-09 20:07:52 +00:00
# include <assert.h>
2009-01-10 02:22:13 +00:00
# include <errno.h>
2008-09-17 19:44:24 +00:00
# include <limits.h> /* INT_MAX */
2007-09-20 16:32:01 +00:00
# include <string.h>
# include <stdio.h>
# include <unistd.h>
2008-01-10 19:52:56 +00:00
# ifdef WIN32
2008-09-23 19:11:04 +00:00
# include <winsock2.h>
2008-01-10 19:52:56 +00:00
# else
2008-09-23 19:11:04 +00:00
# include <arpa/inet.h> /* inet_ntoa */
2008-01-10 19:52:56 +00:00
# endif
2007-10-25 14:34:20 +00:00
2007-09-20 16:32:01 +00:00
# include <event.h>
2007-10-25 14:34:20 +00:00
2007-09-20 16:32:01 +00:00
# include "transmission.h"
2008-12-23 17:27:15 +00:00
# include "session.h"
2008-11-24 04:21:23 +00:00
# include "bandwidth.h"
2007-09-20 16:32:01 +00:00
# include "crypto.h"
2008-11-17 04:00:57 +00:00
# include "list.h"
2007-09-20 16:32:01 +00:00
# include "net.h"
# include "peer-io.h"
2008-12-29 19:01:47 +00:00
# include "platform.h" /* MAX_STACK_ARRAY_SIZE */
2009-12-10 05:52:46 +00:00
# include "trevent.h" /* tr_runInEventThread() */
2007-09-20 16:32:01 +00:00
# include "utils.h"
2008-11-25 21:35:17 +00:00
# define MAGIC_NUMBER 206745
2007-10-11 02:50:05 +00:00
2008-11-06 02:56:51 +00:00
static size_t
2009-04-21 16:18:51 +00:00
guessPacketOverhead ( size_t d )
2008-11-06 02:56:51 +00:00
{
/**
* http : //sd.wareonearth.com/~phil/net/overhead/
*
* TCP over Ethernet :
* Assuming no header compression ( e . g . not PPP )
* Add 20 IPv4 header or 40 IPv6 header ( no options )
* Add 20 TCP header
* Add 12 bytes optional TCP timestamps
* Max TCP Payload data rates over ethernet are thus :
* ( 1500 - 40 ) / ( 38 + 1500 ) = 94.9285 % IPv4 , minimal headers
* ( 1500 - 52 ) / ( 38 + 1500 ) = 94.1482 % IPv4 , TCP timestamps
* ( 1500 - 52 ) / ( 42 + 1500 ) = 93.9040 % 802.1 q , IPv4 , TCP timestamps
* ( 1500 - 60 ) / ( 38 + 1500 ) = 93.6281 % IPv6 , minimal headers
* ( 1500 - 72 ) / ( 38 + 1500 ) = 92.8479 % IPv6 , TCP timestamps
* ( 1500 - 72 ) / ( 42 + 1500 ) = 92.6070 % 802.1 q , IPv6 , ICP timestamps
*/
2010-01-20 18:48:52 +00:00
const double assumed_payload_data_rate = 94.0 ;
2008-11-06 02:56:51 +00:00
2008-11-26 15:58:26 +00:00
return ( size_t ) ( d * ( 100.0 / assumed_payload_data_rate ) - d ) ;
2008-11-06 02:56:51 +00:00
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2008-10-14 01:00:15 +00:00
# define dbgmsg( io, ... ) \
2008-10-26 15:39:04 +00:00
do { \
if ( tr_deepLoggingIsActive ( ) ) \
tr_deepLog ( __FILE__ , __LINE__ , tr_peerIoGetAddrStr ( io ) , __VA_ARGS__ ) ; \
} while ( 0 )
2008-09-17 19:44:24 +00:00
2008-11-17 04:00:57 +00:00
struct tr_datatype
{
2008-11-28 22:11:41 +00:00
tr_bool isPieceData ;
size_t length ;
2008-12-22 19:16:06 +00:00
struct __tr_list head ;
2008-11-17 04:00:57 +00:00
} ;
2008-09-17 19:44:24 +00:00
/***
* * * *
* * */
static void
2008-12-20 22:19:34 +00:00
didWriteWrapper ( tr_peerIo * io , size_t bytes_transferred )
2007-12-01 23:08:34 +00:00
{
2009-02-13 18:23:56 +00:00
while ( bytes_transferred & & tr_isPeerIo ( io ) )
{
2009-01-10 02:22:13 +00:00
struct tr_datatype * next = __tr_list_entry ( io - > outbuf_datatypes . next , struct tr_datatype , head ) ;
2008-11-26 15:58:26 +00:00
const size_t payload = MIN ( next - > length , bytes_transferred ) ;
2009-04-21 16:18:51 +00:00
const size_t overhead = guessPacketOverhead ( payload ) ;
2008-11-17 04:00:57 +00:00
2009-01-02 19:56:06 +00:00
tr_bandwidthUsed ( & io - > bandwidth , TR_UP , payload , next - > isPieceData ) ;
2008-11-26 15:58:26 +00:00
if ( overhead > 0 )
2009-01-02 19:56:06 +00:00
tr_bandwidthUsed ( & io - > bandwidth , TR_UP , overhead , FALSE ) ;
2008-11-17 04:00:57 +00:00
2008-11-25 21:35:17 +00:00
if ( io - > didWrite )
2008-11-26 15:58:26 +00:00
io - > didWrite ( io , payload , next - > isPieceData , io - > userData ) ;
2009-08-10 20:04:08 +00:00
2009-02-13 18:23:56 +00:00
if ( tr_isPeerIo ( io ) )
{
bytes_transferred - = payload ;
next - > length - = payload ;
if ( ! next - > length ) {
__tr_list_remove ( io - > outbuf_datatypes . next ) ;
tr_free ( next ) ;
}
}
2008-09-17 19:44:24 +00:00
}
2007-12-01 23:08:34 +00:00
}
2007-09-20 16:32:01 +00:00
static void
2008-12-20 22:19:34 +00:00
canReadWrapper ( tr_peerIo * io )
2007-09-20 16:32:01 +00:00
{
2008-12-20 22:19:34 +00:00
tr_bool err = 0 ;
2009-10-10 17:37:34 +00:00
tr_bool done = 0 ;
tr_session * session ;
2007-09-20 16:32:01 +00:00
2008-09-17 19:44:24 +00:00
dbgmsg ( io , " canRead " ) ;
2007-09-20 16:32:01 +00:00
2009-10-10 17:37:34 +00:00
assert ( tr_isPeerIo ( io ) ) ;
assert ( tr_isSession ( io - > session ) ) ;
2009-01-05 04:27:54 +00:00
tr_peerIoRef ( io ) ;
2009-10-10 17:37:34 +00:00
session = io - > session ;
2008-09-17 19:44:24 +00:00
/* try to consume the input buffer */
if ( io - > canRead )
2007-10-02 02:59:07 +00:00
{
2010-01-04 09:05:02 +00:00
tr_sessionLock ( session ) ;
2007-10-02 02:59:07 +00:00
2008-09-19 17:03:25 +00:00
while ( ! done & & ! err )
2007-10-02 02:59:07 +00:00
{
2008-11-25 21:35:17 +00:00
size_t piece = 0 ;
2008-12-16 22:08:17 +00:00
const size_t oldLen = EVBUFFER_LENGTH ( io - > inbuf ) ;
const int ret = io - > canRead ( io , io - > userData , & piece ) ;
2008-11-25 21:35:17 +00:00
2008-12-20 22:19:34 +00:00
const size_t used = oldLen - EVBUFFER_LENGTH ( io - > inbuf ) ;
2008-12-30 03:45:12 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2009-01-02 19:56:06 +00:00
if ( piece )
tr_bandwidthUsed ( & io - > bandwidth , TR_DOWN , piece , TRUE ) ;
2008-12-20 22:19:34 +00:00
2009-01-02 19:56:06 +00:00
if ( used ! = piece )
tr_bandwidthUsed ( & io - > bandwidth , TR_DOWN , used - piece , FALSE ) ;
2008-09-17 19:44:24 +00:00
switch ( ret )
{
2008-09-19 17:03:25 +00:00
case READ_NOW :
2008-12-16 22:08:17 +00:00
if ( EVBUFFER_LENGTH ( io - > inbuf ) )
2008-09-17 19:44:24 +00:00
continue ;
done = 1 ;
2008-09-19 17:03:25 +00:00
break ;
2008-09-23 19:11:04 +00:00
2008-09-19 17:03:25 +00:00
case READ_LATER :
done = 1 ;
break ;
2008-09-23 19:11:04 +00:00
2008-09-19 17:03:25 +00:00
case READ_ERR :
err = 1 ;
break ;
2008-09-17 19:44:24 +00:00
}
2009-10-10 17:37:34 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2007-09-20 16:32:01 +00:00
}
2008-09-17 19:44:24 +00:00
2010-01-04 09:05:02 +00:00
tr_sessionUnlock ( session ) ;
2007-09-20 16:32:01 +00:00
}
2009-01-05 04:27:54 +00:00
2009-06-25 04:02:07 +00:00
/* keep the iobuf's excess capacity from growing too large */
if ( EVBUFFER_LENGTH ( io - > inbuf ) = = 0 ) {
evbuffer_free ( io - > inbuf ) ;
io - > inbuf = evbuffer_new ( ) ;
}
2009-10-10 17:37:34 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2009-01-05 04:27:54 +00:00
tr_peerIoUnref ( io ) ;
2007-09-20 16:32:01 +00:00
}
2008-12-21 18:15:00 +00:00
tr_bool
tr_isPeerIo ( const tr_peerIo * io )
2008-12-20 22:19:34 +00:00
{
return ( io ! = NULL )
& & ( io - > magicNumber = = MAGIC_NUMBER )
2009-01-24 17:37:28 +00:00
& & ( io - > refCount > = 0 )
2009-01-02 19:56:06 +00:00
& & ( tr_isBandwidth ( & io - > bandwidth ) )
2009-01-08 04:43:00 +00:00
& & ( tr_isAddress ( & io - > addr ) ) ;
2008-12-20 22:19:34 +00:00
}
2007-09-20 16:32:01 +00:00
static void
2008-12-20 22:19:34 +00:00
event_read_cb ( int fd , short event UNUSED , void * vio )
2007-09-20 16:32:01 +00:00
{
2008-12-20 22:19:34 +00:00
int res ;
2008-12-24 02:50:08 +00:00
int e ;
2008-12-20 22:19:34 +00:00
tr_peerIo * io = vio ;
2008-12-23 17:11:31 +00:00
/* Limit the input buffer to 256K, so it doesn't grow too large */
2008-12-23 17:23:07 +00:00
size_t howmuch ;
2008-12-20 22:19:34 +00:00
const tr_direction dir = TR_DOWN ;
2008-12-23 17:23:07 +00:00
const size_t max = 256 * 1024 ;
2009-01-05 18:20:47 +00:00
size_t curlen ;
2008-12-23 17:23:07 +00:00
2009-01-05 18:20:47 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2009-01-19 13:55:41 +00:00
io - > hasFinishedConnecting = TRUE ;
2009-01-24 14:49:35 +00:00
io - > pendingEvents & = ~ EV_READ ;
2009-01-19 13:55:41 +00:00
2009-01-05 18:20:47 +00:00
curlen = EVBUFFER_LENGTH ( io - > inbuf ) ;
2008-12-23 17:23:07 +00:00
howmuch = curlen > = max ? 0 : max - curlen ;
2009-01-02 19:56:06 +00:00
howmuch = tr_bandwidthClamp ( & io - > bandwidth , TR_DOWN , howmuch ) ;
2008-09-23 19:11:04 +00:00
2008-12-20 22:19:34 +00:00
dbgmsg ( io , " libevent says this peer is ready to read " ) ;
/* if we don't have any bandwidth left, stop reading */
if ( howmuch < 1 ) {
tr_peerIoSetEnabled ( io , dir , FALSE ) ;
return ;
}
2008-12-24 02:50:08 +00:00
errno = 0 ;
2008-12-20 22:19:34 +00:00
res = evbuffer_read ( io - > inbuf , fd , howmuch ) ;
2008-12-24 02:50:08 +00:00
e = errno ;
2008-12-20 22:19:34 +00:00
2008-12-22 04:55:07 +00:00
if ( res > 0 )
{
tr_peerIoSetEnabled ( io , dir , TRUE ) ;
2008-12-20 22:19:34 +00:00
2008-12-22 04:55:07 +00:00
/* Invoke the user callback - must always be called last */
canReadWrapper ( io ) ;
}
else
{
short what = EVBUFFER_READ ;
if ( res = = 0 ) /* EOF */
what | = EVBUFFER_EOF ;
else if ( res = = - 1 ) {
2008-12-24 02:50:08 +00:00
if ( e = = EAGAIN | | e = = EINTR ) {
2008-12-22 04:55:07 +00:00
tr_peerIoSetEnabled ( io , dir , TRUE ) ;
return ;
}
what | = EVBUFFER_ERROR ;
}
2008-12-20 22:19:34 +00:00
2008-12-24 02:50:08 +00:00
dbgmsg ( io , " event_read_cb got an error. res is %d, what is %hd, errno is %d (%s) " , res , what , e , strerror ( e ) ) ;
2008-12-22 04:55:07 +00:00
if ( io - > gotError ! = NULL )
io - > gotError ( io , what , io - > userData ) ;
}
2007-09-20 16:32:01 +00:00
}
2008-12-20 22:19:34 +00:00
2009-01-19 14:05:43 +00:00
static int
2008-12-20 22:19:34 +00:00
tr_evbuffer_write ( tr_peerIo * io , int fd , size_t howmuch )
{
2008-12-24 02:50:08 +00:00
int e ;
2009-01-19 14:05:43 +00:00
int n ;
2009-01-03 04:57:40 +00:00
struct evbuffer * buffer = io - > outbuf ;
howmuch = MIN ( EVBUFFER_LENGTH ( buffer ) , howmuch ) ;
2008-12-20 22:19:34 +00:00
2008-12-24 02:50:08 +00:00
errno = 0 ;
2008-12-20 22:19:34 +00:00
# ifdef WIN32
2009-01-19 14:05:43 +00:00
n = ( int ) send ( fd , buffer - > buffer , howmuch , 0 ) ;
2008-12-20 22:19:34 +00:00
# else
2009-01-19 14:05:43 +00:00
n = ( int ) write ( fd , buffer - > buffer , howmuch ) ;
2008-12-16 22:08:17 +00:00
# endif
2008-12-24 02:50:08 +00:00
e = errno ;
2009-01-19 14:05:43 +00:00
dbgmsg ( io , " wrote %d to peer (%s) " , n , ( n = = - 1 ? strerror ( e ) : " " ) ) ;
2007-09-20 16:32:01 +00:00
2009-01-03 04:57:40 +00:00
if ( n > 0 )
evbuffer_drain ( buffer , n ) ;
2008-12-20 22:19:34 +00:00
2009-07-01 00:46:30 +00:00
/* keep the iobuf's excess capacity from growing too large */
2009-07-18 01:09:56 +00:00
if ( EVBUFFER_LENGTH ( io - > outbuf ) = = 0 ) {
evbuffer_free ( io - > outbuf ) ;
io - > outbuf = evbuffer_new ( ) ;
2009-07-01 00:46:30 +00:00
}
2008-12-20 22:19:34 +00:00
return n ;
}
2007-09-20 16:32:01 +00:00
2008-09-17 19:44:24 +00:00
static void
2008-12-20 22:19:34 +00:00
event_write_cb ( int fd , short event UNUSED , void * vio )
2008-09-17 19:44:24 +00:00
{
2008-12-20 22:19:34 +00:00
int res = 0 ;
2008-12-24 02:50:08 +00:00
int e ;
2008-12-20 22:19:34 +00:00
short what = EVBUFFER_WRITE ;
tr_peerIo * io = vio ;
size_t howmuch ;
const tr_direction dir = TR_UP ;
2008-09-17 19:44:24 +00:00
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2008-12-20 22:19:34 +00:00
2009-01-19 13:55:41 +00:00
io - > hasFinishedConnecting = TRUE ;
2009-01-24 14:49:35 +00:00
io - > pendingEvents & = ~ EV_WRITE ;
2009-01-19 13:55:41 +00:00
2008-12-20 22:19:34 +00:00
dbgmsg ( io , " libevent says this peer is ready to write " ) ;
2008-12-23 17:11:31 +00:00
/* Write as much as possible, since the socket is non-blocking, write() will
* return if it can ' t write any more data without blocking */
2009-01-02 19:56:06 +00:00
howmuch = tr_bandwidthClamp ( & io - > bandwidth , dir , EVBUFFER_LENGTH ( io - > outbuf ) ) ;
2008-12-20 22:19:34 +00:00
/* if we don't have any bandwidth left, stop writing */
if ( howmuch < 1 ) {
tr_peerIoSetEnabled ( io , dir , FALSE ) ;
return ;
}
2008-12-24 02:50:08 +00:00
errno = 0 ;
2008-12-20 22:19:34 +00:00
res = tr_evbuffer_write ( io , fd , howmuch ) ;
2008-12-24 02:50:08 +00:00
e = errno ;
2008-12-20 22:19:34 +00:00
if ( res = = - 1 ) {
# ifndef WIN32
/*todo. evbuffer uses WriteFile when WIN32 is set. WIN32 system calls do not
* * set errno . thus this error checking is not portable */
2008-12-24 02:50:08 +00:00
if ( e = = EAGAIN | | e = = EINTR | | e = = EINPROGRESS )
2008-12-20 22:19:34 +00:00
goto reschedule ;
/* error case */
what | = EVBUFFER_ERROR ;
# else
goto reschedule ;
2008-12-16 22:08:17 +00:00
# endif
2008-09-17 19:44:24 +00:00
2008-12-20 22:19:34 +00:00
} else if ( res = = 0 ) {
/* eof case */
what | = EVBUFFER_EOF ;
}
if ( res < = 0 )
goto error ;
if ( EVBUFFER_LENGTH ( io - > outbuf ) )
tr_peerIoSetEnabled ( io , dir , TRUE ) ;
didWriteWrapper ( io , res ) ;
return ;
reschedule :
if ( EVBUFFER_LENGTH ( io - > outbuf ) )
tr_peerIoSetEnabled ( io , dir , TRUE ) ;
return ;
error :
2008-12-24 02:50:08 +00:00
dbgmsg ( io , " event_write_cb got an error. res is %d, what is %hd, errno is %d (%s) " , res , what , e , strerror ( e ) ) ;
2008-12-21 00:05:54 +00:00
if ( io - > gotError ! = NULL )
io - > gotError ( io , what , io - > userData ) ;
2008-09-17 19:44:24 +00:00
}
2007-11-16 20:40:03 +00:00
2008-12-20 22:19:34 +00:00
/**
* * *
* */
2007-09-20 16:32:01 +00:00
static tr_peerIo *
2008-12-02 03:41:58 +00:00
tr_peerIoNew ( tr_session * session ,
2009-01-02 19:56:06 +00:00
tr_bandwidth * parent ,
2008-12-02 03:41:58 +00:00
const tr_address * addr ,
tr_port port ,
const uint8_t * torrentHash ,
2009-12-02 05:30:46 +00:00
tr_bool isIncoming ,
tr_bool isSeed ,
2008-12-02 03:41:58 +00:00
int socket )
2007-09-20 16:32:01 +00:00
{
2008-09-17 19:44:24 +00:00
tr_peerIo * io ;
2008-04-12 00:29:49 +00:00
2009-01-28 19:35:39 +00:00
assert ( session ! = NULL ) ;
assert ( session - > events ! = NULL ) ;
2009-12-02 05:30:46 +00:00
assert ( tr_isBool ( isIncoming ) ) ;
assert ( tr_isBool ( isSeed ) ) ;
2009-01-28 19:35:39 +00:00
assert ( tr_amInEventThread ( session ) ) ;
2008-04-12 00:29:49 +00:00
if ( socket > = 0 )
2008-09-17 19:44:24 +00:00
tr_netSetTOS ( socket , session - > peerSocketTOS ) ;
io = tr_new0 ( tr_peerIo , 1 ) ;
2008-11-25 21:35:17 +00:00
io - > magicNumber = MAGIC_NUMBER ;
2009-01-05 04:27:54 +00:00
io - > refCount = 1 ;
2008-09-17 19:44:24 +00:00
io - > crypto = tr_cryptoNew ( torrentHash , isIncoming ) ;
io - > session = session ;
2008-12-02 03:41:58 +00:00
io - > addr = * addr ;
2009-12-28 23:24:00 +00:00
io - > isSeed = isSeed ;
2008-09-17 19:44:24 +00:00
io - > port = port ;
io - > socket = socket ;
io - > isIncoming = isIncoming ! = 0 ;
2009-01-19 13:55:41 +00:00
io - > hasFinishedConnecting = FALSE ;
2009-11-26 18:47:08 +00:00
io - > timeCreated = tr_time ( ) ;
2008-12-16 22:08:17 +00:00
io - > inbuf = evbuffer_new ( ) ;
io - > outbuf = evbuffer_new ( ) ;
2009-01-02 19:56:06 +00:00
tr_bandwidthConstruct ( & io - > bandwidth , session , parent ) ;
tr_bandwidthSetPeer ( & io - > bandwidth , io ) ;
dbgmsg ( io , " bandwidth is %p; its parent is %p " , & io - > bandwidth , parent ) ;
2008-12-22 19:16:06 +00:00
2008-12-20 22:19:34 +00:00
event_set ( & io - > event_read , io - > socket , EV_READ , event_read_cb , io ) ;
event_set ( & io - > event_write , io - > socket , EV_WRITE , event_write_cb , io ) ;
2008-12-22 19:16:06 +00:00
__tr_list_init ( & io - > outbuf_datatypes ) ;
2008-09-17 19:44:24 +00:00
return io ;
2007-09-20 16:32:01 +00:00
}
tr_peerIo *
2009-01-02 19:56:06 +00:00
tr_peerIoNewIncoming ( tr_session * session ,
tr_bandwidth * parent ,
const tr_address * addr ,
tr_port port ,
2009-12-02 05:30:46 +00:00
int fd )
2007-09-20 16:32:01 +00:00
{
2008-09-17 19:44:24 +00:00
assert ( session ) ;
2008-12-22 04:55:07 +00:00
assert ( tr_isAddress ( addr ) ) ;
2009-12-02 05:30:46 +00:00
assert ( fd > = 0 ) ;
2007-09-20 16:32:01 +00:00
2009-12-02 05:30:46 +00:00
return tr_peerIoNew ( session , parent , addr , port , NULL , TRUE , FALSE , fd ) ;
2007-09-20 16:32:01 +00:00
}
tr_peerIo *
2009-01-02 19:56:06 +00:00
tr_peerIoNewOutgoing ( tr_session * session ,
tr_bandwidth * parent ,
const tr_address * addr ,
tr_port port ,
2009-12-02 05:30:46 +00:00
const uint8_t * torrentHash ,
tr_bool isSeed )
2007-09-20 16:32:01 +00:00
{
2009-12-02 05:30:46 +00:00
int fd ;
2007-12-15 04:26:31 +00:00
2008-09-17 19:44:24 +00:00
assert ( session ) ;
2008-12-22 04:55:07 +00:00
assert ( tr_isAddress ( addr ) ) ;
2008-08-01 16:43:22 +00:00
assert ( torrentHash ) ;
2007-09-20 16:32:01 +00:00
2009-12-15 17:39:19 +00:00
fd = tr_netOpenPeerSocket ( session , addr , port , isSeed ) ;
dbgmsg ( NULL , " tr_netOpenPeerSocket returned fd %d " , fd ) ;
2007-12-15 04:26:31 +00:00
2009-12-02 05:30:46 +00:00
return fd < 0 ? NULL
: tr_peerIoNew ( session , parent , addr , port , torrentHash , FALSE , isSeed , fd ) ;
2007-09-20 16:32:01 +00:00
}
2010-01-17 19:21:04 +00:00
/***
* * * *
* * */
static void
event_enable ( tr_peerIo * io , short event )
{
assert ( tr_amInEventThread ( io - > session ) ) ;
assert ( io - > session ! = NULL ) ;
assert ( io - > session - > events ! = NULL ) ;
assert ( event_initialized ( & io - > event_read ) ) ;
assert ( event_initialized ( & io - > event_write ) ) ;
if ( ( event & EV_READ ) & & ! ( io - > pendingEvents & EV_READ ) )
{
dbgmsg ( io , " enabling libevent ready-to-read polling " ) ;
event_add ( & io - > event_read , NULL ) ;
io - > pendingEvents | = EV_READ ;
}
if ( ( event & EV_WRITE ) & & ! ( io - > pendingEvents & EV_WRITE ) )
{
dbgmsg ( io , " enabling libevent ready-to-write polling " ) ;
event_add ( & io - > event_write , NULL ) ;
io - > pendingEvents | = EV_WRITE ;
}
}
static void
event_disable ( struct tr_peerIo * io , short event )
{
assert ( tr_amInEventThread ( io - > session ) ) ;
assert ( io - > session ! = NULL ) ;
assert ( io - > session - > events ! = NULL ) ;
assert ( event_initialized ( & io - > event_read ) ) ;
assert ( event_initialized ( & io - > event_write ) ) ;
if ( ( event & EV_READ ) & & ( io - > pendingEvents & EV_READ ) )
{
dbgmsg ( io , " disabling libevent ready-to-read polling " ) ;
event_del ( & io - > event_read ) ;
io - > pendingEvents & = ~ EV_READ ;
}
if ( ( event & EV_WRITE ) & & ( io - > pendingEvents & EV_WRITE ) )
{
dbgmsg ( io , " disabling libevent ready-to-write polling " ) ;
event_del ( & io - > event_write ) ;
io - > pendingEvents & = ~ EV_WRITE ;
}
}
void
tr_peerIoSetEnabled ( tr_peerIo * io ,
tr_direction dir ,
tr_bool isEnabled )
{
const short event = dir = = TR_UP ? EV_WRITE : EV_READ ;
assert ( tr_isPeerIo ( io ) ) ;
assert ( tr_isDirection ( dir ) ) ;
assert ( tr_amInEventThread ( io - > session ) ) ;
assert ( io - > session - > events ! = NULL ) ;
if ( isEnabled )
event_enable ( io , event ) ;
else
event_disable ( io , event ) ;
}
/***
* * * *
* * */
2008-12-22 19:16:06 +00:00
static void
trDatatypeFree ( void * data )
{
struct tr_datatype * dt = __tr_list_entry ( data , struct tr_datatype , head ) ;
tr_free ( dt ) ;
}
2007-10-02 16:12:44 +00:00
static void
io_dtor ( void * vio )
2007-09-20 16:32:01 +00:00
{
2007-10-02 16:12:44 +00:00
tr_peerIo * io = vio ;
2009-01-26 02:51:50 +00:00
2009-01-24 16:21:34 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2009-01-26 02:51:50 +00:00
assert ( tr_amInEventThread ( io - > session ) ) ;
assert ( io - > session - > events ! = NULL ) ;
2007-09-20 16:32:01 +00:00
2009-01-24 16:21:34 +00:00
dbgmsg ( io , " in tr_peerIo destructor " ) ;
2010-01-18 19:26:46 +00:00
event_disable ( io , EV_READ | EV_WRITE ) ;
2009-01-02 19:56:06 +00:00
tr_bandwidthDestruct ( & io - > bandwidth ) ;
2008-12-16 22:08:17 +00:00
evbuffer_free ( io - > outbuf ) ;
evbuffer_free ( io - > inbuf ) ;
2009-10-23 03:41:36 +00:00
tr_netClose ( io - > session , io - > socket ) ;
2007-10-02 16:12:44 +00:00
tr_cryptoFree ( io - > crypto ) ;
2008-12-22 19:16:06 +00:00
__tr_list_destroy ( & io - > outbuf_datatypes , trDatatypeFree ) ;
2008-11-25 21:35:17 +00:00
2009-08-10 20:04:08 +00:00
memset ( io , ~ 0 , sizeof ( tr_peerIo ) ) ;
2007-10-02 16:12:44 +00:00
tr_free ( io ) ;
}
2007-09-20 16:32:01 +00:00
2009-01-05 04:27:54 +00:00
static void
2007-10-02 16:12:44 +00:00
tr_peerIoFree ( tr_peerIo * io )
{
2008-08-01 16:43:22 +00:00
if ( io )
2007-10-02 16:12:44 +00:00
{
2009-01-24 16:21:34 +00:00
dbgmsg ( io , " in tr_peerIoFree " ) ;
2007-10-02 16:12:44 +00:00
io - > canRead = NULL ;
2007-12-01 23:08:34 +00:00
io - > didWrite = NULL ;
2007-10-02 16:12:44 +00:00
io - > gotError = NULL ;
2008-09-17 19:44:24 +00:00
tr_runInEventThread ( io - > session , io_dtor , io ) ;
2007-09-20 16:32:01 +00:00
}
}
2009-01-05 04:27:54 +00:00
void
2009-01-24 17:20:07 +00:00
tr_peerIoRefImpl ( const char * file , int line , tr_peerIo * io )
2009-01-05 04:27:54 +00:00
{
assert ( tr_isPeerIo ( io ) ) ;
2009-01-24 17:37:28 +00:00
dbgmsg ( io , " %s:%d is incrementing the IO's refcount from %d to %d " ,
2009-01-24 17:20:07 +00:00
file , line , io - > refCount , io - > refCount + 1 ) ;
2009-01-05 04:27:54 +00:00
+ + io - > refCount ;
}
void
2009-01-24 17:20:07 +00:00
tr_peerIoUnrefImpl ( const char * file , int line , tr_peerIo * io )
2009-01-05 04:27:54 +00:00
{
assert ( tr_isPeerIo ( io ) ) ;
2009-01-24 17:37:28 +00:00
dbgmsg ( io , " %s:%d is decrementing the IO's refcount from %d to %d " ,
file , line , io - > refCount , io - > refCount - 1 ) ;
2009-01-24 17:20:07 +00:00
2009-01-05 04:27:54 +00:00
if ( ! - - io - > refCount )
tr_peerIoFree ( io ) ;
}
2008-12-02 03:41:58 +00:00
const tr_address *
2009-01-24 17:20:07 +00:00
tr_peerIoGetAddress ( const tr_peerIo * io , tr_port * port )
2007-09-20 16:32:01 +00:00
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2007-09-20 16:32:01 +00:00
2008-08-01 16:43:22 +00:00
if ( port )
2008-09-23 19:11:04 +00:00
* port = io - > port ;
2007-09-20 16:32:01 +00:00
2008-12-02 03:41:58 +00:00
return & io - > addr ;
2007-09-20 16:32:01 +00:00
}
const char *
2008-12-22 00:52:44 +00:00
tr_peerIoAddrStr ( const tr_address * addr , tr_port port )
2007-09-20 16:32:01 +00:00
{
static char buf [ 512 ] ;
2008-09-23 19:11:04 +00:00
2009-08-10 20:04:08 +00:00
if ( addr - > type = = TR_AF_INET )
tr_snprintf ( buf , sizeof ( buf ) , " %s:%u " , tr_ntop_non_ts ( addr ) , ntohs ( port ) ) ;
else
tr_snprintf ( buf , sizeof ( buf ) , " [%s]:%u " , tr_ntop_non_ts ( addr ) , ntohs ( port ) ) ;
2007-09-20 16:32:01 +00:00
return buf ;
}
2008-09-23 19:11:04 +00:00
void
2008-12-20 22:19:34 +00:00
tr_peerIoSetIOFuncs ( tr_peerIo * io ,
tr_can_read_cb readcb ,
tr_did_write_cb writecb ,
tr_net_error_cb errcb ,
void * userData )
2007-09-20 16:32:01 +00:00
{
io - > canRead = readcb ;
2007-12-01 23:08:34 +00:00
io - > didWrite = writecb ;
2007-09-20 16:32:01 +00:00
io - > gotError = errcb ;
io - > userData = userData ;
}
2009-01-05 18:20:47 +00:00
void
tr_peerIoClear ( tr_peerIo * io )
{
tr_peerIoSetIOFuncs ( io , NULL , NULL , NULL , NULL ) ;
tr_peerIoSetEnabled ( io , TR_UP , FALSE ) ;
tr_peerIoSetEnabled ( io , TR_DOWN , FALSE ) ;
}
2007-09-20 16:32:01 +00:00
int
tr_peerIoReconnect ( tr_peerIo * io )
{
2010-01-17 19:21:04 +00:00
int pendingEvents ;
2009-10-23 03:41:36 +00:00
tr_session * session ;
assert ( tr_isPeerIo ( io ) ) ;
2007-09-20 16:32:01 +00:00
assert ( ! tr_peerIoIsIncoming ( io ) ) ;
2009-10-23 03:41:36 +00:00
session = tr_peerIoGetSession ( io ) ;
2010-01-17 19:21:04 +00:00
pendingEvents = io - > pendingEvents ;
2010-01-18 19:26:46 +00:00
event_disable ( io , EV_READ | EV_WRITE ) ;
2010-01-17 19:21:04 +00:00
2007-09-20 16:32:01 +00:00
if ( io - > socket > = 0 )
2009-10-23 03:41:36 +00:00
tr_netClose ( session , io - > socket ) ;
2007-09-20 16:32:01 +00:00
2009-12-15 17:39:19 +00:00
io - > socket = tr_netOpenPeerSocket ( session , & io - > addr , io - > port , io - > isSeed ) ;
2010-01-17 19:21:04 +00:00
event_set ( & io - > event_read , io - > socket , EV_READ , event_read_cb , io ) ;
event_set ( & io - > event_write , io - > socket , EV_WRITE , event_write_cb , io ) ;
event_enable ( io , pendingEvents ) ;
2007-09-20 16:32:01 +00:00
if ( io - > socket > = 0 )
{
2009-10-23 03:41:36 +00:00
tr_netSetTOS ( io - > socket , session - > peerSocketTOS ) ;
2007-09-20 16:32:01 +00:00
return 0 ;
}
2008-09-23 19:11:04 +00:00
2007-09-20 16:32:01 +00:00
return - 1 ;
}
/**
* * *
* */
void
2008-09-23 19:11:04 +00:00
tr_peerIoSetTorrentHash ( tr_peerIo * io ,
2007-09-20 16:32:01 +00:00
const uint8_t * hash )
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2007-09-20 16:32:01 +00:00
tr_cryptoSetTorrentHash ( io - > crypto , hash ) ;
}
const uint8_t *
tr_peerIoGetTorrentHash ( tr_peerIo * io )
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2008-08-01 16:43:22 +00:00
assert ( io - > crypto ) ;
2007-09-20 16:32:01 +00:00
return tr_cryptoGetTorrentHash ( io - > crypto ) ;
}
int
tr_peerIoHasTorrentHash ( const tr_peerIo * io )
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2008-08-01 16:43:22 +00:00
assert ( io - > crypto ) ;
2007-09-20 16:32:01 +00:00
return tr_cryptoHasTorrentHash ( io - > crypto ) ;
}
/**
* * *
* */
void
2008-09-23 19:11:04 +00:00
tr_peerIoSetPeersId ( tr_peerIo * io ,
2007-09-20 16:32:01 +00:00
const uint8_t * peer_id )
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2007-09-20 16:32:01 +00:00
2008-09-23 19:11:04 +00:00
if ( ( io - > peerIdIsSet = peer_id ! = NULL ) )
2007-09-20 16:32:01 +00:00
memcpy ( io - > peerId , peer_id , 20 ) ;
else
memset ( io - > peerId , 0 , 20 ) ;
}
/**
* * *
* */
2008-12-02 17:10:54 +00:00
void
tr_peerIoEnableFEXT ( tr_peerIo * io ,
2008-12-05 22:56:19 +00:00
tr_bool flag )
2008-12-02 17:10:54 +00:00
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2009-01-02 19:56:06 +00:00
assert ( tr_isBool ( flag ) ) ;
2008-12-02 17:10:54 +00:00
2008-12-22 04:55:07 +00:00
dbgmsg ( io , " setting FEXT support flag to %d " , ( flag ! = 0 ) ) ;
2008-12-02 17:10:54 +00:00
io - > fastExtensionSupported = flag ;
}
2007-09-21 14:50:29 +00:00
void
2008-12-05 22:56:19 +00:00
tr_peerIoEnableLTEP ( tr_peerIo * io ,
tr_bool flag )
2007-09-21 14:50:29 +00:00
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2009-01-02 19:56:06 +00:00
assert ( tr_isBool ( flag ) ) ;
2008-09-23 19:11:04 +00:00
2008-12-22 04:55:07 +00:00
dbgmsg ( io , " setting LTEP support flag to %d " , ( flag ! = 0 ) ) ;
2008-05-23 18:56:42 +00:00
io - > extendedProtocolSupported = flag ;
2007-09-21 14:50:29 +00:00
}
2009-05-19 18:38:26 +00:00
void
tr_peerIoEnableDHT ( tr_peerIo * io , tr_bool flag )
{
assert ( tr_isPeerIo ( io ) ) ;
assert ( tr_isBool ( flag ) ) ;
dbgmsg ( io , " setting DHT support flag to %d " , ( flag ! = 0 ) ) ;
io - > dhtSupported = flag ;
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2008-11-28 16:00:29 +00:00
static size_t
2009-01-05 04:27:54 +00:00
getDesiredOutputBufferSize ( const tr_peerIo * io , uint64_t now )
2008-11-28 16:00:29 +00:00
{
/* this is all kind of arbitrary, but what seems to work well is
2008-12-15 21:22:08 +00:00
* being large enough to hold the next 20 seconds ' worth of input ,
* or a few blocks , whichever is bigger .
2008-11-28 16:00:29 +00:00
* It ' s okay to tweak this as needed */
const double maxBlockSize = 16 * 1024 ; /* 16 KiB is from BT spec */
2009-01-05 04:27:54 +00:00
const double currentSpeed = tr_bandwidthGetPieceSpeed ( & io - > bandwidth , now , TR_UP ) ;
2009-06-03 22:52:08 +00:00
const double period = 15 ; /* arbitrary */
const double numBlocks = 3.5 ; /* the 3 is arbitrary; the .5 is to leave room for messages */
2008-12-20 22:19:34 +00:00
return MAX ( maxBlockSize * numBlocks , currentSpeed * 1024 * period ) ;
2008-11-28 16:00:29 +00:00
}
2008-09-17 19:44:24 +00:00
size_t
2009-01-05 04:27:54 +00:00
tr_peerIoGetWriteBufferSpace ( const tr_peerIo * io , uint64_t now )
2008-09-17 19:44:24 +00:00
{
2009-01-05 04:27:54 +00:00
const size_t desiredLen = getDesiredOutputBufferSize ( io , now ) ;
2008-12-16 22:08:17 +00:00
const size_t currentLen = EVBUFFER_LENGTH ( io - > outbuf ) ;
2008-11-24 04:21:23 +00:00
size_t freeSpace = 0 ;
2008-09-17 19:44:24 +00:00
if ( desiredLen > currentLen )
freeSpace = desiredLen - currentLen ;
return freeSpace ;
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2008-09-23 19:11:04 +00:00
void
2007-09-20 16:32:01 +00:00
tr_peerIoSetEncryption ( tr_peerIo * io ,
int encryptionMode )
{
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2008-09-23 19:11:04 +00:00
assert ( encryptionMode = = PEER_ENCRYPTION_NONE
2009-01-02 19:56:06 +00:00
| | encryptionMode = = PEER_ENCRYPTION_RC4 ) ;
2007-09-20 16:32:01 +00:00
io - > encryptionMode = encryptionMode ;
}
2007-11-17 17:49:30 +00:00
/**
* * *
* */
2008-09-17 19:44:24 +00:00
void
2008-11-17 04:00:57 +00:00
tr_peerIoWrite ( tr_peerIo * io ,
2009-01-22 14:32:29 +00:00
const void * bytes ,
size_t byteCount ,
tr_bool isPieceData )
2008-09-17 19:44:24 +00:00
{
2009-06-02 18:21:23 +00:00
/* FIXME(libevent2): this implementation snould be moved to tr_peerIoWriteBuf. This function should be implemented as evbuffer_new() + evbuffer_add_reference() + a call to tr_peerIoWriteBuf() + evbuffer_free() */
2008-11-17 04:00:57 +00:00
struct tr_datatype * datatype ;
2008-12-22 04:55:07 +00:00
2008-09-17 19:44:24 +00:00
assert ( tr_amInEventThread ( io - > session ) ) ;
2009-01-22 14:32:29 +00:00
dbgmsg ( io , " adding %zu bytes into io->output " , byteCount ) ;
2008-09-17 19:44:24 +00:00
2008-11-17 04:00:57 +00:00
datatype = tr_new ( struct tr_datatype , 1 ) ;
datatype - > isPieceData = isPieceData ! = 0 ;
2009-01-22 14:32:29 +00:00
datatype - > length = byteCount ;
2008-12-22 19:16:06 +00:00
__tr_list_init ( & datatype - > head ) ;
__tr_list_append ( & io - > outbuf_datatypes , & datatype - > head ) ;
2008-11-17 04:00:57 +00:00
2007-09-20 16:32:01 +00:00
switch ( io - > encryptionMode )
{
2009-01-22 14:32:29 +00:00
case PEER_ENCRYPTION_RC4 :
{
2009-06-02 18:21:23 +00:00
/* FIXME(libevent2): use evbuffer_reserve_space() and evbuffer_commit_space() instead of tmp */
2009-01-22 14:32:29 +00:00
uint8_t tmp [ MAX_STACK_ARRAY_SIZE ] ;
2009-01-04 04:37:26 +00:00
const uint8_t * walk = bytes ;
2009-01-22 14:32:29 +00:00
evbuffer_expand ( io - > outbuf , byteCount ) ;
while ( byteCount > 0 )
{
2008-12-29 19:01:47 +00:00
const size_t thisPass = MIN ( byteCount , sizeof ( tmp ) ) ;
2009-01-04 04:37:26 +00:00
tr_cryptoEncrypt ( io - > crypto , thisPass , walk , tmp ) ;
2009-01-22 14:32:29 +00:00
evbuffer_add ( io - > outbuf , tmp , thisPass ) ;
2009-01-04 04:37:26 +00:00
walk + = thisPass ;
2008-12-29 19:01:47 +00:00
byteCount - = thisPass ;
}
2007-09-20 16:32:01 +00:00
break ;
2009-01-04 04:37:26 +00:00
}
2007-09-20 16:32:01 +00:00
2009-01-22 14:32:29 +00:00
case PEER_ENCRYPTION_NONE :
evbuffer_add ( io - > outbuf , bytes , byteCount ) ;
break ;
2007-09-20 16:32:01 +00:00
default :
assert ( 0 ) ;
2009-01-22 14:32:29 +00:00
break ;
2007-09-20 16:32:01 +00:00
}
}
2009-01-22 14:32:29 +00:00
void
tr_peerIoWriteBuf ( tr_peerIo * io ,
struct evbuffer * buf ,
tr_bool isPieceData )
{
2009-06-02 18:21:23 +00:00
/* FIXME(libevent2): loop through calls to evbuffer_get_contiguous_space() + evbuffer_drain() */
2009-01-22 14:32:29 +00:00
const size_t n = EVBUFFER_LENGTH ( buf ) ;
tr_peerIoWrite ( io , EVBUFFER_DATA ( buf ) , n , isPieceData ) ;
evbuffer_drain ( buf , n ) ;
}
2007-11-17 17:49:30 +00:00
/***
* * * *
* * */
2007-09-20 16:32:01 +00:00
void
2008-12-22 04:55:07 +00:00
tr_peerIoReadBytes ( tr_peerIo * io ,
2008-09-23 19:11:04 +00:00
struct evbuffer * inbuf ,
2008-12-22 04:55:07 +00:00
void * bytes ,
2008-09-23 19:11:04 +00:00
size_t byteCount )
2007-09-20 16:32:01 +00:00
{
2009-01-02 06:28:22 +00:00
assert ( tr_isPeerIo ( io ) ) ;
2009-06-02 18:21:23 +00:00
/* FIXME(libevent2): use evbuffer_get_length() */
2007-11-19 04:44:14 +00:00
assert ( EVBUFFER_LENGTH ( inbuf ) > = byteCount ) ;
2007-09-20 16:32:01 +00:00
switch ( io - > encryptionMode )
{
case PEER_ENCRYPTION_NONE :
2008-08-08 22:44:32 +00:00
evbuffer_remove ( inbuf , bytes , byteCount ) ;
2007-09-20 16:32:01 +00:00
break ;
case PEER_ENCRYPTION_RC4 :
2009-06-02 18:21:23 +00:00
/* FIXME(libevent2): loop through calls to evbuffer_get_contiguous_space() + evbuffer_drain() */
2009-04-12 14:52:17 +00:00
tr_cryptoDecrypt ( io - > crypto , byteCount , EVBUFFER_DATA ( inbuf ) , bytes ) ;
evbuffer_drain ( inbuf , byteCount ) ;
2007-09-20 16:32:01 +00:00
break ;
default :
assert ( 0 ) ;
}
}
void
2008-12-22 04:55:07 +00:00
tr_peerIoDrain ( tr_peerIo * io ,
2008-09-23 19:11:04 +00:00
struct evbuffer * inbuf ,
size_t byteCount )
2007-09-20 16:32:01 +00:00
{
2008-12-29 19:01:47 +00:00
uint8_t tmp [ MAX_STACK_ARRAY_SIZE ] ;
2008-12-21 18:15:00 +00:00
2008-12-29 19:01:47 +00:00
while ( byteCount > 0 )
{
const size_t thisPass = MIN ( byteCount , sizeof ( tmp ) ) ;
tr_peerIoReadBytes ( io , inbuf , tmp , thisPass ) ;
byteCount - = thisPass ;
}
2007-09-20 16:32:01 +00:00
}
2008-01-11 02:09:20 +00:00
2008-12-16 22:08:17 +00:00
/***
* * * *
* * */
2009-01-19 14:05:43 +00:00
static int
2008-12-16 22:08:17 +00:00
tr_peerIoTryRead ( tr_peerIo * io , size_t howmuch )
{
2009-01-19 14:05:43 +00:00
int res = 0 ;
2008-12-16 22:08:17 +00:00
2009-01-02 19:56:06 +00:00
if ( ( howmuch = tr_bandwidthClamp ( & io - > bandwidth , TR_DOWN , howmuch ) ) )
2008-12-24 02:50:08 +00:00
{
int e ;
errno = 0 ;
res = evbuffer_read ( io - > inbuf , io - > socket , howmuch ) ;
e = errno ;
2008-12-16 22:08:17 +00:00
2009-01-19 14:05:43 +00:00
dbgmsg ( io , " read %d from peer (%s) " , res , ( res = = - 1 ? strerror ( e ) : " " ) ) ;
2008-12-16 22:08:17 +00:00
2008-12-24 02:50:08 +00:00
if ( EVBUFFER_LENGTH ( io - > inbuf ) )
canReadWrapper ( io ) ;
2008-12-16 22:08:17 +00:00
2008-12-24 02:50:08 +00:00
if ( ( res < = 0 ) & & ( io - > gotError ) & & ( e ! = EAGAIN ) & & ( e ! = EINTR ) & & ( e ! = EINPROGRESS ) )
{
short what = EVBUFFER_READ | EVBUFFER_ERROR ;
if ( res = = 0 )
what | = EVBUFFER_EOF ;
2009-01-19 14:05:43 +00:00
dbgmsg ( io , " tr_peerIoTryRead got an error. res is %d, what is %hd, errno is %d (%s) " , res , what , e , strerror ( e ) ) ;
2008-12-24 02:50:08 +00:00
io - > gotError ( io , what , io - > userData ) ;
}
2008-12-16 22:08:17 +00:00
}
return res ;
}
2009-01-19 14:05:43 +00:00
static int
2008-12-16 22:08:17 +00:00
tr_peerIoTryWrite ( tr_peerIo * io , size_t howmuch )
{
2009-01-19 14:05:43 +00:00
int n = 0 ;
2008-12-16 22:08:17 +00:00
2009-01-02 19:56:06 +00:00
if ( ( howmuch = tr_bandwidthClamp ( & io - > bandwidth , TR_UP , howmuch ) ) )
2008-12-24 02:50:08 +00:00
{
int e ;
errno = 0 ;
2009-01-03 04:57:40 +00:00
n = tr_evbuffer_write ( io , io - > socket , howmuch ) ;
2008-12-24 02:50:08 +00:00
e = errno ;
2008-12-16 22:08:17 +00:00
2008-12-24 02:50:08 +00:00
if ( n > 0 )
didWriteWrapper ( io , n ) ;
2008-12-16 22:08:17 +00:00
2008-12-24 02:50:08 +00:00
if ( ( n < 0 ) & & ( io - > gotError ) & & ( e ! = EPIPE ) & & ( e ! = EAGAIN ) & & ( e ! = EINTR ) & & ( e ! = EINPROGRESS ) )
{
const short what = EVBUFFER_WRITE | EVBUFFER_ERROR ;
2009-01-19 14:05:43 +00:00
dbgmsg ( io , " tr_peerIoTryWrite got an error. res is %d, what is %hd, errno is %d (%s) " , n , what , e , strerror ( e ) ) ;
2008-12-24 02:50:08 +00:00
io - > gotError ( io , what , io - > userData ) ;
}
2008-12-16 22:08:17 +00:00
}
return n ;
}
2009-01-19 14:05:43 +00:00
int
2008-12-16 22:08:17 +00:00
tr_peerIoFlush ( tr_peerIo * io , tr_direction dir , size_t limit )
{
2009-01-20 02:43:21 +00:00
int bytesUsed = 0 ;
2008-12-16 22:08:17 +00:00
2008-12-21 18:15:00 +00:00
assert ( tr_isPeerIo ( io ) ) ;
assert ( tr_isDirection ( dir ) ) ;
2008-12-16 22:08:17 +00:00
2009-01-19 13:55:41 +00:00
if ( io - > hasFinishedConnecting )
{
if ( dir = = TR_DOWN )
bytesUsed = tr_peerIoTryRead ( io , limit ) ;
else
bytesUsed = tr_peerIoTryWrite ( io , limit ) ;
}
2008-12-16 22:08:17 +00:00
2009-01-24 03:17:59 +00:00
dbgmsg ( io , " flushing peer-io, hasFinishedConnecting %d, direction %d, limit %zu, bytesUsed %d " , ( int ) io - > hasFinishedConnecting , ( int ) dir , limit , bytesUsed ) ;
2009-01-02 19:56:06 +00:00
return bytesUsed ;
2008-12-16 22:08:17 +00:00
}
2009-04-21 16:18:51 +00:00
int
tr_peerIoFlushOutgoingProtocolMsgs ( tr_peerIo * io )
{
size_t byteCount = 0 ;
struct __tr_list * walk ;
struct __tr_list * fencepost = & io - > outbuf_datatypes ;
/* count up how many bytes are used by non-piece-data messages
at the front of our outbound queue */
for ( walk = fencepost - > next ; walk ! = fencepost ; walk = walk - > next ) {
struct tr_datatype * d = __tr_list_entry ( walk , struct tr_datatype , head ) ;
if ( d - > isPieceData )
break ;
byteCount + = d - > length ;
}
return tr_peerIoFlush ( io , TR_UP , byteCount ) ;
}