2007-09-20 16:32:01 +00:00
/*
2009-01-10 23:09:07 +00:00
* This file Copyright ( C ) 2007 - 2009 Charles Kerr < charles @ transmissionbt . com >
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>
2007-10-11 03:36:09 +00:00
# include <errno.h>
2008-04-19 19:39:39 +00:00
# include <limits.h> /* INT_MAX */
2007-09-20 16:32:01 +00:00
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <event.h>
# include "transmission.h"
2008-12-23 17:27:15 +00:00
# include "session.h"
2007-09-20 16:32:01 +00:00
# include "bencode.h"
# include "completion.h"
2008-08-16 21:06:57 +00:00
# include "crypto.h"
2007-09-20 16:32:01 +00:00
# include "inout.h"
2008-10-10 02:14:51 +00:00
# ifdef WIN32
# include "net.h" /* for ECONN */
# endif
2007-09-20 16:32:01 +00:00
# include "peer-io.h"
# include "peer-mgr.h"
# include "peer-msgs.h"
2008-12-30 00:56:10 +00:00
# include "platform.h" /* MAX_STACK_ARRAY_SIZE */
2007-09-20 16:32:01 +00:00
# include "ratecontrol.h"
2009-01-04 16:29:44 +00:00
# include "request-list.h"
2007-11-21 20:03:53 +00:00
# include "stats.h"
2007-12-25 05:37:32 +00:00
# include "torrent.h"
2009-05-19 18:38:26 +00:00
# include "tr-dht.h"
2007-09-20 16:32:01 +00:00
# include "trevent.h"
# include "utils.h"
2009-04-13 19:04:21 +00:00
# include "version.h"
2007-09-20 16:32:01 +00:00
/**
* * *
* */
enum
{
2007-09-26 15:14:37 +00:00
BT_CHOKE = 0 ,
BT_UNCHOKE = 1 ,
BT_INTERESTED = 2 ,
BT_NOT_INTERESTED = 3 ,
BT_HAVE = 4 ,
BT_BITFIELD = 5 ,
BT_REQUEST = 6 ,
BT_PIECE = 7 ,
BT_CANCEL = 8 ,
BT_PORT = 9 ,
2008-12-02 17:10:54 +00:00
BT_FEXT_SUGGEST = 13 ,
BT_FEXT_HAVE_ALL = 14 ,
BT_FEXT_HAVE_NONE = 15 ,
BT_FEXT_REJECT = 16 ,
BT_FEXT_ALLOWED_FAST = 17 ,
2007-09-26 15:14:37 +00:00
BT_LTEP = 20 ,
LTEP_HANDSHAKE = 0 ,
2007-11-22 06:48:08 +00:00
TR_LTEP_PEX = 1 ,
2007-09-26 15:14:37 +00:00
2008-12-02 17:10:54 +00:00
2008-09-23 19:11:04 +00:00
MIN_CHOKE_PERIOD_SEC = ( 10 ) ,
2007-09-26 15:14:37 +00:00
2007-11-09 01:22:15 +00:00
/* idle seconds before we send a keepalive */
2008-05-31 00:16:26 +00:00
KEEPALIVE_INTERVAL_SECS = 100 ,
2007-11-09 01:22:15 +00:00
2008-09-23 19:11:04 +00:00
PEX_INTERVAL = ( 90 * 1000 ) , /* msec between sendPex() calls */
2008-12-30 08:25:39 +00:00
MAX_BLOCK_SIZE = ( 1024 * 16 ) ,
2007-11-20 17:29:56 +00:00
2008-03-18 17:46:29 +00:00
/* how long an unsent request can stay queued before it's returned
back to the peer - mgr ' s pool of requests */
2008-02-10 04:03:19 +00:00
QUEUED_REQUEST_TTL_SECS = 20 ,
2008-03-18 17:46:29 +00:00
/* how long a sent request can stay queued before it's returned
back to the peer - mgr ' s pool of requests */
2008-08-14 20:17:55 +00:00
SENT_REQUEST_TTL_SECS = 240 ,
2008-05-31 00:16:26 +00:00
/* used in lowering the outMessages queue period */
IMMEDIATE_PRIORITY_INTERVAL_SECS = 0 ,
2008-07-27 14:10:32 +00:00
HIGH_PRIORITY_INTERVAL_SECS = 2 ,
2008-08-16 21:06:57 +00:00
LOW_PRIORITY_INTERVAL_SECS = 20 ,
/* number of pieces to remove from the bitfield when
* lazy bitfields are turned on */
2008-12-02 17:10:54 +00:00
LAZY_PIECE_COUNT = 26 ,
/* number of pieces we'll allow in our fast set */
MAX_FAST_SET_SIZE = 3
2007-09-20 16:32:01 +00:00
} ;
2009-01-02 23:28:57 +00:00
enum
{
AWAITING_BT_LENGTH ,
AWAITING_BT_ID ,
AWAITING_BT_MESSAGE ,
AWAITING_BT_PIECE
} ;
2008-03-01 14:09:18 +00:00
/**
* * *
* */
2007-11-16 20:40:03 +00:00
/* this is raw, unchanged data from the peer regarding
* the current message that it ' s sending us . */
struct tr_incoming
{
2009-01-02 23:28:57 +00:00
uint8_t id ;
uint32_t length ; /* includes the +1 for id length */
struct peer_request blockReq ; /* metadata for incoming blocks */
struct evbuffer * block ; /* piece data for incoming blocks */
2007-11-16 20:40:03 +00:00
} ;
2008-12-11 17:02:34 +00:00
/**
* Low - level communication state information about a connected peer .
*
* This structure remembers the low - level protocol states that we ' re
* in with this peer , such as active requests , pex messages , and so on .
* Its fields are all private to peer - msgs . c .
*
* Data not directly involved with sending & receiving messages is
* stored in tr_peer , where it can be accessed by both peermsgs and
* the peer manager .
*
* @ see struct peer_atom
* @ see tr_peer
*/
2007-09-20 16:32:01 +00:00
struct tr_peermsgs
{
2008-11-28 22:11:41 +00:00
tr_bool peerSupportsPex ;
tr_bool clientSentLtepHandshake ;
tr_bool peerSentLtepHandshake ;
2009-06-03 04:56:53 +00:00
/*tr_bool haveFastSet;*/
2008-09-23 19:11:04 +00:00
2009-01-02 23:28:57 +00:00
uint8_t state ;
2008-09-23 19:11:04 +00:00
uint8_t ut_pex_id ;
uint16_t pexCount ;
2008-12-15 00:17:08 +00:00
uint16_t pexCount6 ;
2008-09-23 19:11:04 +00:00
uint16_t maxActiveRequests ;
2008-03-01 14:09:18 +00:00
2009-06-03 04:56:53 +00:00
#if 0
2008-12-02 17:10:54 +00:00
size_t fastsetSize ;
tr_piece_index_t fastset [ MAX_FAST_SET_SIZE ] ;
2009-06-03 04:56:53 +00:00
# endif
2008-12-02 17:10:54 +00:00
2008-07-27 14:10:32 +00:00
/* how long the outMessages batch should be allowed to grow before
* it ' s flushed - - some messages ( like requests > : ) should be sent
* very quickly ; others aren ' t as urgent . */
2008-09-23 19:11:04 +00:00
int outMessagesBatchPeriod ;
2008-07-27 14:10:32 +00:00
2008-12-12 02:44:21 +00:00
tr_peer * peer ;
2007-09-20 16:32:01 +00:00
2008-09-23 19:11:04 +00:00
tr_session * session ;
tr_torrent * torrent ;
2007-09-20 16:32:01 +00:00
2008-12-29 18:10:07 +00:00
tr_publisher publisher ;
2007-09-20 16:32:01 +00:00
2008-10-08 03:58:21 +00:00
struct evbuffer * outMessages ; /* all the non-piece messages */
2008-03-01 14:09:18 +00:00
2008-09-23 19:11:04 +00:00
struct request_list peerAskedFor ;
struct request_list clientAskedFor ;
struct request_list clientWillAskFor ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
tr_timer * pexTimer ;
tr_pex * pex ;
2008-12-15 00:17:08 +00:00
tr_pex * pex6 ;
2007-09-20 16:32:01 +00:00
2009-06-03 04:56:53 +00:00
/*time_t clientSentPexAt;*/
2008-09-23 19:11:04 +00:00
time_t clientSentAnythingAt ;
2008-05-31 00:16:26 +00:00
/* when we started batching the outMessages */
2008-09-23 19:11:04 +00:00
time_t outMessagesBatchedAt ;
struct tr_incoming incoming ;
2007-11-16 20:40:03 +00:00
2008-12-08 20:23:10 +00:00
/* if the peer supports the Extension Protocol in BEP 10 and
supplied a reqq argument , it ' s stored here . otherwise the
value is zero and should be ignored . */
int64_t reqq ;
2007-09-20 16:32:01 +00:00
} ;
/**
* * *
* */
static void
2008-12-05 22:56:19 +00:00
myDebug ( const char * file , int line ,
2007-10-03 16:42:43 +00:00
const struct tr_peermsgs * msgs ,
2008-12-05 22:56:19 +00:00
const char * fmt , . . . )
2007-09-20 16:32:01 +00:00
{
2007-09-20 23:33:46 +00:00
FILE * fp = tr_getLog ( ) ;
2008-09-23 19:11:04 +00:00
2008-08-01 16:43:22 +00:00
if ( fp )
2007-09-20 23:33:46 +00:00
{
2008-09-23 19:11:04 +00:00
va_list args ;
char timestr [ 64 ] ;
2008-12-30 20:32:00 +00:00
struct evbuffer * buf = tr_getBuffer ( ) ;
2008-10-14 03:39:16 +00:00
char * base = tr_basename ( file ) ;
2007-10-22 18:52:36 +00:00
2007-11-01 13:47:32 +00:00
evbuffer_add_printf ( buf , " [%s] %s - %s [%s]: " ,
2008-09-23 19:11:04 +00:00
tr_getLogTimeStr ( timestr , sizeof ( timestr ) ) ,
2007-11-01 13:47:32 +00:00
msgs - > torrent - > info . name ,
2008-12-12 02:44:21 +00:00
tr_peerIoGetAddrStr ( msgs - > peer - > io ) ,
msgs - > peer - > client ) ;
2007-09-20 23:33:46 +00:00
va_start ( args , fmt ) ;
evbuffer_add_vprintf ( buf , fmt , args ) ;
va_end ( args ) ;
2008-10-14 03:39:16 +00:00
evbuffer_add_printf ( buf , " (%s:%d) \n " , base , line ) ;
2009-06-02 18:21:23 +00:00
/* FIXME(libevent2) tr_getLog() should return an fd, then use evbuffer_write() here */
2008-09-23 19:11:04 +00:00
fwrite ( EVBUFFER_DATA ( buf ) , 1 , EVBUFFER_LENGTH ( buf ) , fp ) ;
2007-10-22 18:52:36 +00:00
2008-10-14 03:39:16 +00:00
tr_free ( base ) ;
2008-12-30 20:32:00 +00:00
tr_releaseBuffer ( buf ) ;
2007-09-20 23:33:46 +00:00
}
2007-09-20 16:32:01 +00:00
}
2008-11-23 16:30:09 +00:00
# define dbgmsg( msgs, ... ) \
do { \
if ( tr_deepLoggingIsActive ( ) ) \
myDebug ( __FILE__ , __LINE__ , msgs , __VA_ARGS__ ) ; \
} while ( 0 )
2007-10-06 18:20:52 +00:00
/**
* * *
* */
2008-05-31 00:16:26 +00:00
static void
2008-09-23 19:11:04 +00:00
pokeBatchPeriod ( tr_peermsgs * msgs ,
int interval )
2008-05-31 00:16:26 +00:00
{
if ( msgs - > outMessagesBatchPeriod > interval )
{
msgs - > outMessagesBatchPeriod = interval ;
dbgmsg ( msgs , " lowering batch interval to %d seconds " , interval ) ;
}
}
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2008-12-02 17:10:54 +00:00
dbgOutMessageLen ( tr_peermsgs * msgs )
{
dbgmsg ( msgs , " outMessage size is now %zu " , EVBUFFER_LENGTH ( msgs - > outMessages ) ) ;
}
static void
protocolSendReject ( tr_peermsgs * msgs , const struct peer_request * req )
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2008-12-02 17:10:54 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-12-12 02:44:21 +00:00
assert ( tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ) ;
2008-12-02 17:10:54 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) + 3 * sizeof ( uint32_t ) ) ;
tr_peerIoWriteUint8 ( io , out , BT_FEXT_REJECT ) ;
tr_peerIoWriteUint32 ( io , out , req - > index ) ;
tr_peerIoWriteUint32 ( io , out , req - > offset ) ;
tr_peerIoWriteUint32 ( io , out , req - > length ) ;
dbgmsg ( msgs , " rejecting %u:%u->%u... " , req - > index , req - > offset , req - > length ) ;
dbgOutMessageLen ( msgs ) ;
}
2007-10-06 18:20:52 +00:00
static void
2008-12-22 00:52:44 +00:00
protocolSendRequest ( tr_peermsgs * msgs ,
2008-09-23 19:11:04 +00:00
const struct peer_request * req )
2007-10-06 18:20:52 +00:00
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2007-10-06 18:20:52 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-09-23 19:11:04 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) + 3 * sizeof ( uint32_t ) ) ;
2007-10-06 18:20:52 +00:00
tr_peerIoWriteUint8 ( io , out , BT_REQUEST ) ;
tr_peerIoWriteUint32 ( io , out , req - > index ) ;
tr_peerIoWriteUint32 ( io , out , req - > offset ) ;
tr_peerIoWriteUint32 ( io , out , req - > length ) ;
2008-12-02 17:10:54 +00:00
dbgmsg ( msgs , " requesting %u:%u->%u... " , req - > index , req - > offset , req - > length ) ;
dbgOutMessageLen ( msgs ) ;
2008-12-08 20:36:36 +00:00
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
2007-10-06 18:20:52 +00:00
}
static void
2008-12-22 00:52:44 +00:00
protocolSendCancel ( tr_peermsgs * msgs ,
2008-09-23 19:11:04 +00:00
const struct peer_request * req )
2007-10-06 18:20:52 +00:00
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2007-10-06 18:20:52 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-09-23 19:11:04 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) + 3 * sizeof ( uint32_t ) ) ;
2007-10-06 18:20:52 +00:00
tr_peerIoWriteUint8 ( io , out , BT_CANCEL ) ;
tr_peerIoWriteUint32 ( io , out , req - > index ) ;
tr_peerIoWriteUint32 ( io , out , req - > offset ) ;
tr_peerIoWriteUint32 ( io , out , req - > length ) ;
2008-12-02 17:10:54 +00:00
dbgmsg ( msgs , " cancelling %u:%u->%u... " , req - > index , req - > offset , req - > length ) ;
dbgOutMessageLen ( msgs ) ;
2008-05-31 00:16:26 +00:00
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
2007-10-06 18:20:52 +00:00
}
2009-05-19 18:38:26 +00:00
static void
protocolSendPort ( tr_peermsgs * msgs , uint16_t port )
{
tr_peerIo * io = msgs - > peer - > io ;
struct evbuffer * out = msgs - > outMessages ;
dbgmsg ( msgs , " sending Port %u " , port ) ;
tr_peerIoWriteUint32 ( io , out , 3 ) ;
tr_peerIoWriteUint8 ( io , out , BT_PORT ) ;
tr_peerIoWriteUint16 ( io , out , port ) ;
}
2007-10-06 18:20:52 +00:00
static void
2008-09-23 19:11:04 +00:00
protocolSendHave ( tr_peermsgs * msgs ,
uint32_t index )
2007-10-06 18:20:52 +00:00
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2007-10-06 18:20:52 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-12-02 17:10:54 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) + sizeof ( uint32_t ) ) ;
2007-10-06 18:20:52 +00:00
tr_peerIoWriteUint8 ( io , out , BT_HAVE ) ;
tr_peerIoWriteUint32 ( io , out , index ) ;
2008-12-02 17:10:54 +00:00
2008-12-22 00:52:44 +00:00
dbgmsg ( msgs , " sending Have %u " , index ) ;
2008-12-02 17:10:54 +00:00
dbgOutMessageLen ( msgs ) ;
2008-05-31 00:16:26 +00:00
pokeBatchPeriod ( msgs , LOW_PRIORITY_INTERVAL_SECS ) ;
2007-10-06 18:20:52 +00:00
}
2008-12-02 18:24:26 +00:00
#if 0
2008-12-02 17:10:54 +00:00
static void
protocolSendAllowedFast ( tr_peermsgs * msgs , uint32_t pieceIndex )
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2008-12-02 17:10:54 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-12-12 02:44:21 +00:00
assert ( tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ) ;
2008-12-02 17:10:54 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) + sizeof ( uint32_t ) ) ;
tr_peerIoWriteUint8 ( io , out , BT_FEXT_ALLOWED_FAST ) ;
tr_peerIoWriteUint32 ( io , out , pieceIndex ) ;
dbgmsg ( msgs , " sending Allowed Fast %u... " , pieceIndex ) ;
dbgOutMessageLen ( msgs ) ;
}
2008-12-02 18:24:26 +00:00
# endif
2008-12-02 17:10:54 +00:00
2007-10-06 18:20:52 +00:00
static void
2008-09-23 19:11:04 +00:00
protocolSendChoke ( tr_peermsgs * msgs ,
int choke )
2007-10-06 18:20:52 +00:00
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2007-10-06 18:20:52 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-09-23 19:11:04 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) ) ;
2007-10-06 18:20:52 +00:00
tr_peerIoWriteUint8 ( io , out , choke ? BT_CHOKE : BT_UNCHOKE ) ;
2008-12-02 17:10:54 +00:00
dbgmsg ( msgs , " sending %s... " , choke ? " Choke " : " Unchoke " ) ;
dbgOutMessageLen ( msgs ) ;
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
}
static void
protocolSendHaveAll ( tr_peermsgs * msgs )
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2008-12-02 17:10:54 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-12-12 02:44:21 +00:00
assert ( tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ) ;
2008-12-02 17:10:54 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) ) ;
tr_peerIoWriteUint8 ( io , out , BT_FEXT_HAVE_ALL ) ;
dbgmsg ( msgs , " sending HAVE_ALL... " ) ;
dbgOutMessageLen ( msgs ) ;
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
}
static void
protocolSendHaveNone ( tr_peermsgs * msgs )
{
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2008-12-02 17:10:54 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-12-12 02:44:21 +00:00
assert ( tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ) ;
2008-12-02 17:10:54 +00:00
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) ) ;
tr_peerIoWriteUint8 ( io , out , BT_FEXT_HAVE_NONE ) ;
dbgmsg ( msgs , " sending HAVE_NONE... " ) ;
dbgOutMessageLen ( msgs ) ;
2008-05-31 00:16:26 +00:00
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
2007-10-06 18:20:52 +00:00
}
2007-09-20 16:32:01 +00:00
/**
* * * EVENTS
* */
2008-12-02 19:46:51 +00:00
static const tr_peer_event blankEvent = { 0 , 0 , 0 , 0 , 0.0f , 0 , 0 , 0 } ;
2007-09-20 16:32:01 +00:00
static void
2008-12-05 22:56:19 +00:00
publish ( tr_peermsgs * msgs , tr_peer_event * e )
2007-09-20 23:07:36 +00:00
{
2008-12-12 02:44:21 +00:00
assert ( msgs - > peer ) ;
assert ( msgs - > peer - > msgs = = msgs ) ;
2008-12-02 19:06:08 +00:00
2008-12-29 18:10:07 +00:00
tr_publisherPublish ( & msgs - > publisher , msgs - > peer , e ) ;
2007-09-20 23:07:36 +00:00
}
2007-11-13 05:36:43 +00:00
static void
2008-12-05 22:56:19 +00:00
fireError ( tr_peermsgs * msgs , int err )
2007-11-13 05:36:43 +00:00
{
2008-06-07 21:26:41 +00:00
tr_peer_event e = blankEvent ;
e . eventType = TR_PEER_ERROR ;
2008-01-18 19:13:32 +00:00
e . err = err ;
2007-09-20 23:07:36 +00:00
publish ( msgs , & e ) ;
2007-09-20 16:32:01 +00:00
}
static void
2008-12-02 19:46:51 +00:00
fireUploadOnly ( tr_peermsgs * msgs , tr_bool uploadOnly )
2007-09-20 16:32:01 +00:00
{
2008-06-07 21:26:41 +00:00
tr_peer_event e = blankEvent ;
2008-12-02 19:46:51 +00:00
e . eventType = TR_PEER_UPLOAD_ONLY ;
e . uploadOnly = uploadOnly ;
publish ( msgs , & e ) ;
}
2008-09-23 19:11:04 +00:00
2009-02-11 16:34:35 +00:00
static void
fireNeedReq ( tr_peermsgs * msgs )
{
tr_peer_event e = blankEvent ;
e . eventType = TR_PEER_NEED_REQ ;
publish ( msgs , & e ) ;
}
2007-09-20 23:07:36 +00:00
static void
firePeerProgress ( tr_peermsgs * msgs )
{
2008-06-07 21:26:41 +00:00
tr_peer_event e = blankEvent ;
e . eventType = TR_PEER_PEER_PROGRESS ;
2008-12-12 02:44:21 +00:00
e . progress = msgs - > peer - > progress ;
2007-09-20 23:07:36 +00:00
publish ( msgs , & e ) ;
2007-09-20 16:32:01 +00:00
}
static void
2008-12-05 22:56:19 +00:00
fireGotBlock ( tr_peermsgs * msgs , const struct peer_request * req )
2007-09-20 16:32:01 +00:00
{
2008-06-07 21:26:41 +00:00
tr_peer_event e = blankEvent ;
e . eventType = TR_PEER_CLIENT_GOT_BLOCK ;
e . pieceIndex = req - > index ;
e . offset = req - > offset ;
e . length = req - > length ;
2007-09-20 23:07:36 +00:00
publish ( msgs , & e ) ;
2007-09-20 16:32:01 +00:00
}
static void
2008-09-23 19:11:04 +00:00
fireClientGotData ( tr_peermsgs * msgs ,
2008-11-17 04:00:57 +00:00
uint32_t length ,
int wasPieceData )
2007-09-20 16:32:01 +00:00
{
2008-06-07 21:26:41 +00:00
tr_peer_event e = blankEvent ;
2008-09-23 19:11:04 +00:00
2008-06-07 21:26:41 +00:00
e . length = length ;
e . eventType = TR_PEER_CLIENT_GOT_DATA ;
2008-11-17 04:00:57 +00:00
e . wasPieceData = wasPieceData ;
2007-09-20 23:07:36 +00:00
publish ( msgs , & e ) ;
2007-09-20 16:32:01 +00:00
}
2008-12-02 17:10:54 +00:00
static void
fireClientGotSuggest ( tr_peermsgs * msgs , uint32_t pieceIndex )
{
tr_peer_event e = blankEvent ;
e . eventType = TR_PEER_CLIENT_GOT_SUGGEST ;
e . pieceIndex = pieceIndex ;
publish ( msgs , & e ) ;
}
static void
fireClientGotAllowedFast ( tr_peermsgs * msgs , uint32_t pieceIndex )
{
tr_peer_event e = blankEvent ;
e . eventType = TR_PEER_CLIENT_GOT_ALLOWED_FAST ;
e . pieceIndex = pieceIndex ;
publish ( msgs , & e ) ;
}
2008-01-05 18:17:56 +00:00
static void
2008-11-17 04:00:57 +00:00
firePeerGotData ( tr_peermsgs * msgs ,
uint32_t length ,
int wasPieceData )
2008-01-05 18:17:56 +00:00
{
2008-06-07 21:26:41 +00:00
tr_peer_event e = blankEvent ;
2008-09-23 19:11:04 +00:00
2008-06-07 21:26:41 +00:00
e . length = length ;
e . eventType = TR_PEER_PEER_GOT_DATA ;
2008-11-17 04:00:57 +00:00
e . wasPieceData = wasPieceData ;
2008-01-05 18:17:56 +00:00
publish ( msgs , & e ) ;
}
2007-10-06 18:20:52 +00:00
static void
2008-10-11 04:07:50 +00:00
fireCancelledReq ( tr_peermsgs * msgs , const struct peer_request * req )
2007-10-06 18:20:52 +00:00
{
2008-06-07 21:26:41 +00:00
tr_peer_event e = blankEvent ;
e . eventType = TR_PEER_CANCEL ;
2008-10-11 04:07:50 +00:00
e . pieceIndex = req - > index ;
e . offset = req - > offset ;
e . length = req - > length ;
2007-10-06 18:20:52 +00:00
publish ( msgs , & e ) ;
}
2008-12-02 17:10:54 +00:00
/**
* * * ALLOWED FAST SET
* * * For explanation , see http : //www.bittorrent.org/beps/bep_0006.html
* */
size_t
tr_generateAllowedSet ( tr_piece_index_t * setmePieces ,
size_t desiredSetSize ,
size_t pieceCount ,
const uint8_t * infohash ,
const tr_address * addr )
{
size_t setSize = 0 ;
assert ( setmePieces ) ;
assert ( desiredSetSize < = pieceCount ) ;
assert ( desiredSetSize ) ;
assert ( pieceCount ) ;
assert ( infohash ) ;
assert ( addr ) ;
if ( addr - > type = = TR_AF_INET )
{
uint8_t w [ SHA_DIGEST_LENGTH + 4 ] ;
uint8_t x [ SHA_DIGEST_LENGTH ] ;
* ( uint32_t * ) w = ntohl ( htonl ( addr - > addr . addr4 . s_addr ) & 0xffffff00 ) ; /* (1) */
memcpy ( w + 4 , infohash , SHA_DIGEST_LENGTH ) ; /* (2) */
tr_sha1 ( x , w , sizeof ( w ) , NULL ) ; /* (3) */
while ( setSize < desiredSetSize )
{
int i ;
for ( i = 0 ; i < 5 & & setSize < desiredSetSize ; + + i ) /* (4) */
{
size_t k ;
uint32_t j = i * 4 ; /* (5) */
uint32_t y = ntohl ( * ( uint32_t * ) ( x + j ) ) ; /* (6) */
uint32_t index = y % pieceCount ; /* (7) */
for ( k = 0 ; k < setSize ; + + k ) /* (8) */
if ( setmePieces [ k ] = = index )
break ;
if ( k = = setSize )
setmePieces [ setSize + + ] = index ; /* (9) */
}
tr_sha1 ( x , x , sizeof ( x ) , NULL ) ; /* (3) */
}
}
return setSize ;
}
static void
updateFastSet ( tr_peermsgs * msgs UNUSED )
{
#if 0
2008-12-12 02:44:21 +00:00
const tr_bool fext = tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ;
const int peerIsNeedy = msgs - > peer - > progress < 0.10 ;
2008-12-02 17:10:54 +00:00
if ( fext & & peerIsNeedy & & ! msgs - > haveFastSet )
{
size_t i ;
2008-12-12 02:44:21 +00:00
const struct tr_address * addr = tr_peerIoGetAddress ( msgs - > peer - > io , NULL ) ;
2008-12-02 17:10:54 +00:00
const tr_info * inf = & msgs - > torrent - > info ;
const size_t numwant = MIN ( MAX_FAST_SET_SIZE , inf - > pieceCount ) ;
/* build the fast set */
msgs - > fastsetSize = tr_generateAllowedSet ( msgs - > fastset , numwant , inf - > pieceCount , inf - > hash , addr ) ;
msgs - > haveFastSet = 1 ;
/* send it to the peer */
for ( i = 0 ; i < msgs - > fastsetSize ; + + i )
protocolSendAllowedFast ( msgs , msgs - > fastset [ i ] ) ;
}
# endif
}
2007-09-20 16:32:01 +00:00
/**
* * * INTEREST
* */
2009-02-19 21:55:00 +00:00
static tr_bool
2008-12-12 02:44:21 +00:00
isPieceInteresting ( const tr_peermsgs * msgs ,
2008-09-23 19:11:04 +00:00
tr_piece_index_t piece )
2007-09-20 16:32:01 +00:00
{
2008-12-12 02:44:21 +00:00
const tr_torrent * torrent = msgs - > torrent ;
2008-03-01 14:09:18 +00:00
2008-09-23 19:11:04 +00:00
return ( ! torrent - > info . pieces [ piece ] . dnd ) /* we want it */
2009-01-02 17:01:55 +00:00
& & ( ! tr_cpPieceIsComplete ( & torrent - > completion , piece ) ) /* !have */
2008-12-12 02:44:21 +00:00
& & ( tr_bitfieldHas ( msgs - > peer - > have , piece ) ) ; /* peer has it */
2007-09-20 16:32:01 +00:00
}
2007-10-03 16:42:43 +00:00
/* "interested" means we'll ask for piece data if they unchoke us */
2009-02-19 21:55:00 +00:00
static tr_bool
2007-09-20 16:32:01 +00:00
isPeerInteresting ( const tr_peermsgs * msgs )
{
2008-09-23 19:11:04 +00:00
tr_piece_index_t i ;
const tr_torrent * torrent ;
2007-09-30 23:55:49 +00:00
const tr_bitfield * bitfield ;
2008-09-23 19:11:04 +00:00
const int clientIsSeed = tr_torrentIsSeed ( msgs - > torrent ) ;
2007-09-20 16:32:01 +00:00
2007-09-30 23:55:49 +00:00
if ( clientIsSeed )
return FALSE ;
2007-09-20 16:32:01 +00:00
2008-11-07 05:37:59 +00:00
if ( ! tr_torrentIsPieceTransferAllowed ( msgs - > torrent , TR_PEER_TO_CLIENT ) )
2008-11-07 04:10:27 +00:00
return FALSE ;
2007-09-30 23:55:49 +00:00
torrent = msgs - > torrent ;
2009-01-02 17:01:55 +00:00
bitfield = tr_cpPieceBitfield ( & torrent - > completion ) ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
if ( ! msgs - > peer - > have )
2007-09-30 23:55:49 +00:00
return TRUE ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
assert ( bitfield - > byteCount = = msgs - > peer - > have - > byteCount ) ;
2008-06-07 01:44:54 +00:00
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < torrent - > info . pieceCount ; + + i )
2007-09-30 23:55:49 +00:00
if ( isPieceInteresting ( msgs , i ) )
return TRUE ;
return FALSE ;
2007-09-20 16:32:01 +00:00
}
static void
2008-09-23 19:11:04 +00:00
sendInterest ( tr_peermsgs * msgs ,
int weAreInterested )
2007-09-20 16:32:01 +00:00
{
2008-08-16 05:11:28 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-08-01 16:43:22 +00:00
assert ( msgs ) ;
2008-09-23 19:11:04 +00:00
assert ( weAreInterested = = 0 | | weAreInterested = = 1 ) ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
msgs - > peer - > clientIsInterested = weAreInterested ;
2008-12-05 22:56:19 +00:00
dbgmsg ( msgs , " Sending %s " , weAreInterested ? " Interested " : " Not Interested " ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoWriteUint32 ( msgs - > peer - > io , out , sizeof ( uint8_t ) ) ;
tr_peerIoWriteUint8 ( msgs - > peer - > io , out , weAreInterested ? BT_INTERESTED : BT_NOT_INTERESTED ) ;
2008-12-22 00:52:44 +00:00
2008-05-31 00:16:26 +00:00
pokeBatchPeriod ( msgs , HIGH_PRIORITY_INTERVAL_SECS ) ;
2008-12-05 22:56:19 +00:00
dbgOutMessageLen ( msgs ) ;
2007-09-20 16:32:01 +00:00
}
static void
updateInterest ( tr_peermsgs * msgs )
{
const int i = isPeerInteresting ( msgs ) ;
2008-09-23 19:11:04 +00:00
2008-12-12 02:44:21 +00:00
if ( i ! = msgs - > peer - > clientIsInterested )
2007-09-20 16:32:01 +00:00
sendInterest ( msgs , i ) ;
2009-02-11 16:34:35 +00:00
if ( i )
fireNeedReq ( msgs ) ;
2007-09-20 16:32:01 +00:00
}
2009-02-19 21:55:00 +00:00
static tr_bool
2008-12-02 17:10:54 +00:00
popNextRequest ( tr_peermsgs * msgs ,
struct peer_request * setme )
{
return reqListPop ( & msgs - > peerAskedFor , setme ) ;
}
2007-10-27 15:45:03 +00:00
static void
2008-11-29 20:37:34 +00:00
cancelAllRequestsToClient ( tr_peermsgs * msgs )
2007-10-27 15:45:03 +00:00
{
2008-12-02 17:10:54 +00:00
struct peer_request req ;
2008-12-12 02:44:21 +00:00
const int mustSendCancel = tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ;
2008-12-02 17:10:54 +00:00
while ( popNextRequest ( msgs , & req ) )
2008-12-02 19:38:46 +00:00
if ( mustSendCancel )
protocolSendReject ( msgs , & req ) ;
2007-10-27 15:45:03 +00:00
}
2007-10-17 18:23:59 +00:00
void
2008-09-23 19:11:04 +00:00
tr_peerMsgsSetChoke ( tr_peermsgs * msgs ,
int choke )
2007-09-20 16:32:01 +00:00
{
2008-10-27 04:12:42 +00:00
const time_t now = time ( NULL ) ;
const time_t fibrillationTime = now - MIN_CHOKE_PERIOD_SEC ;
2007-10-15 16:01:42 +00:00
2008-08-01 16:43:22 +00:00
assert ( msgs ) ;
2008-12-12 02:44:21 +00:00
assert ( msgs - > peer ) ;
2008-09-23 19:11:04 +00:00
assert ( choke = = 0 | | choke = = 1 ) ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
if ( msgs - > peer - > chokeChangedAt > fibrillationTime )
2007-10-15 16:01:42 +00:00
{
2008-12-05 22:56:19 +00:00
dbgmsg ( msgs , " Not changing choke to %d to avoid fibrillation " , choke ) ;
2007-10-15 16:01:42 +00:00
}
2008-12-12 02:44:21 +00:00
else if ( msgs - > peer - > peerIsChoked ! = choke )
2007-09-20 16:32:01 +00:00
{
2008-12-12 02:44:21 +00:00
msgs - > peer - > peerIsChoked = choke ;
2007-09-28 14:27:56 +00:00
if ( choke )
2008-11-29 20:37:34 +00:00
cancelAllRequestsToClient ( msgs ) ;
2007-10-06 18:20:52 +00:00
protocolSendChoke ( msgs , choke ) ;
2008-12-12 02:44:21 +00:00
msgs - > peer - > chokeChangedAt = now ;
2007-09-20 16:32:01 +00:00
}
}
/**
* * *
* */
void
tr_peerMsgsHave ( tr_peermsgs * msgs ,
2007-10-06 18:20:52 +00:00
uint32_t index )
2007-09-20 16:32:01 +00:00
{
2007-10-06 18:20:52 +00:00
protocolSendHave ( msgs , index ) ;
2007-09-20 16:32:01 +00:00
2007-10-06 18:20:52 +00:00
/* since we have more pieces now, we might not be interested in this peer */
2007-09-20 16:32:01 +00:00
updateInterest ( msgs ) ;
}
2008-09-23 19:11:04 +00:00
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2009-02-18 22:25:13 +00:00
static tr_bool
2008-09-23 19:11:04 +00:00
reqIsValid ( const tr_peermsgs * peer ,
uint32_t index ,
uint32_t offset ,
uint32_t length )
2007-09-25 22:30:41 +00:00
{
2008-06-09 22:53:45 +00:00
return tr_torrentReqIsValid ( peer - > torrent , index , offset , length ) ;
2007-09-25 22:30:41 +00:00
}
2009-02-18 22:25:13 +00:00
static tr_bool
2008-10-11 04:07:50 +00:00
requestIsValid ( const tr_peermsgs * msgs , const struct peer_request * req )
2008-06-09 22:53:45 +00:00
{
2008-10-11 04:07:50 +00:00
return reqIsValid ( msgs , req - > index , req - > offset , req - > length ) ;
2007-09-25 22:30:41 +00:00
}
2007-12-25 17:22:51 +00:00
static void
2008-12-30 08:25:39 +00:00
expireFromList ( tr_peermsgs * msgs ,
struct request_list * list ,
const time_t oldestAllowed )
2007-12-25 17:22:51 +00:00
{
2009-01-04 16:29:44 +00:00
size_t i ;
struct request_list tmp = REQUEST_LIST_INIT ;
2008-12-30 08:25:39 +00:00
2009-01-04 16:29:44 +00:00
/* since the fifo list is sorted by time, the oldest will be first */
2009-01-04 16:48:31 +00:00
if ( ! list - > len | | ( list - > fifo [ 0 ] . time_requested > = oldestAllowed ) )
2009-01-04 16:29:44 +00:00
return ;
2008-12-30 08:25:39 +00:00
/* if we found one too old, start pruning them */
2009-01-04 16:29:44 +00:00
reqListCopy ( & tmp , list ) ;
for ( i = 0 ; i < tmp . len ; + + i ) {
const struct peer_request * req = & tmp . fifo [ i ] ;
if ( req - > time_requested > = oldestAllowed )
break ;
tr_peerMsgsCancel ( msgs , req - > index , req - > offset , req - > length ) ;
2008-12-30 08:25:39 +00:00
}
2009-01-04 16:29:44 +00:00
reqListClear ( & tmp ) ;
2008-12-30 08:25:39 +00:00
}
static void
expireOldRequests ( tr_peermsgs * msgs , const time_t now )
{
2008-12-05 22:56:19 +00:00
time_t oldestAllowed ;
2008-12-12 02:44:21 +00:00
const tr_bool fext = tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ;
2008-12-16 22:08:17 +00:00
dbgmsg ( msgs , " entering `expire old requests' block " ) ;
2008-03-18 17:46:29 +00:00
/* cancel requests that have been queued for too long */
2008-10-27 04:12:42 +00:00
oldestAllowed = now - QUEUED_REQUEST_TTL_SECS ;
2008-12-30 08:25:39 +00:00
expireFromList ( msgs , & msgs - > clientWillAskFor , oldestAllowed ) ;
2008-03-18 17:46:29 +00:00
2008-12-02 17:10:54 +00:00
/* if the peer doesn't support "Reject Request",
* cancel requests that were sent too long ago . */
if ( ! fext ) {
oldestAllowed = now - SENT_REQUEST_TTL_SECS ;
2008-12-30 08:25:39 +00:00
expireFromList ( msgs , & msgs - > clientAskedFor , oldestAllowed ) ;
2008-03-18 17:46:29 +00:00
}
2008-12-16 22:08:17 +00:00
dbgmsg ( msgs , " leaving `expire old requests' block " ) ;
2007-12-25 17:22:51 +00:00
}
2007-10-06 18:20:52 +00:00
static void
2008-10-27 04:12:42 +00:00
pumpRequestQueue ( tr_peermsgs * msgs , const time_t now )
2007-10-06 18:20:52 +00:00
{
2008-09-23 19:11:04 +00:00
const int max = msgs - > maxActiveRequests ;
int sent = 0 ;
2009-01-04 16:29:44 +00:00
int len = msgs - > clientAskedFor . len ;
2008-03-01 14:09:18 +00:00
struct peer_request req ;
2007-10-06 18:20:52 +00:00
2009-01-21 04:02:39 +00:00
dbgmsg ( msgs , " clientIsChoked %d, download allowed %d, len %d, max %d, msgs->clientWillAskFor.len %d " ,
( int ) msgs - > peer - > clientIsChoked ,
( int ) tr_torrentIsPieceTransferAllowed ( msgs - > torrent , TR_PEER_TO_CLIENT ) ,
len , max , msgs - > clientWillAskFor . len ) ;
2008-12-12 02:44:21 +00:00
if ( msgs - > peer - > clientIsChoked )
2007-10-06 18:20:52 +00:00
return ;
2008-11-07 05:37:59 +00:00
if ( ! tr_torrentIsPieceTransferAllowed ( msgs - > torrent , TR_PEER_TO_CLIENT ) )
2008-11-07 04:10:27 +00:00
return ;
2007-10-06 18:20:52 +00:00
2009-01-04 16:29:44 +00:00
while ( ( len < max ) & & reqListPop ( & msgs - > clientWillAskFor , & req ) )
2007-10-06 18:20:52 +00:00
{
2008-12-05 22:56:19 +00:00
const tr_block_index_t block = _tr_block ( msgs - > torrent , req . index , req . offset ) ;
2008-10-08 03:58:21 +00:00
2008-02-29 03:41:50 +00:00
assert ( requestIsValid ( msgs , & req ) ) ;
2008-12-12 02:44:21 +00:00
assert ( tr_bitfieldHas ( msgs - > peer - > have , req . index ) ) ;
2008-02-29 03:41:50 +00:00
2008-10-08 03:58:21 +00:00
/* don't ask for it if we've already got it... this block may have
* come in from a different peer after we cancelled a request for it */
2009-01-02 17:01:55 +00:00
if ( ! tr_cpBlockIsComplete ( & msgs - > torrent - > completion , block ) )
2008-10-08 03:58:21 +00:00
{
protocolSendRequest ( msgs , & req ) ;
req . time_requested = now ;
reqListAppend ( & msgs - > clientAskedFor , & req ) ;
2008-02-29 03:41:50 +00:00
2009-01-04 16:29:44 +00:00
+ + len ;
2008-10-08 03:58:21 +00:00
+ + sent ;
}
2009-01-21 04:02:39 +00:00
else dbgmsg ( msgs , " not asking for it because we've already got it... " ) ;
2007-10-06 18:20:52 +00:00
}
if ( sent )
2008-12-05 22:56:19 +00:00
dbgmsg ( msgs , " pump sent %d requests, now have %d active and %d queued " ,
2009-01-04 16:29:44 +00:00
sent , msgs - > clientAskedFor . len , msgs - > clientWillAskFor . len ) ;
2009-02-11 16:34:35 +00:00
if ( len < max )
fireNeedReq ( msgs ) ;
2007-10-06 18:20:52 +00:00
}
2009-02-19 21:55:00 +00:00
static TR_INLINE tr_bool
2008-06-09 22:53:45 +00:00
requestQueueIsFull ( const tr_peermsgs * msgs )
2007-09-20 16:32:01 +00:00
{
2007-10-06 18:20:52 +00:00
const int req_max = msgs - > maxActiveRequests ;
2009-01-04 16:29:44 +00:00
return msgs - > clientWillAskFor . len > = ( size_t ) req_max ;
2008-06-09 22:53:45 +00:00
}
2008-08-22 16:13:52 +00:00
tr_addreq_t
2008-09-23 19:11:04 +00:00
tr_peerMsgsAddRequest ( tr_peermsgs * msgs ,
2008-10-11 04:07:50 +00:00
uint32_t index ,
uint32_t offset ,
2008-12-22 00:52:44 +00:00
uint32_t length )
2008-06-09 22:53:45 +00:00
{
2008-02-29 03:41:50 +00:00
struct peer_request req ;
2007-09-20 16:32:01 +00:00
2008-08-01 16:43:22 +00:00
assert ( msgs ) ;
assert ( msgs - > torrent ) ;
2007-09-20 16:32:01 +00:00
2007-10-06 18:20:52 +00:00
/**
* * * Reasons to decline the request
* */
/* don't send requests to choked clients */
2008-12-22 00:52:44 +00:00
if ( msgs - > peer - > clientIsChoked ) {
2007-10-06 18:20:52 +00:00
dbgmsg ( msgs , " declining request because they're choking us " ) ;
2007-09-20 16:32:01 +00:00
return TR_ADDREQ_CLIENT_CHOKED ;
2007-10-06 18:20:52 +00:00
}
2007-09-20 16:32:01 +00:00
2007-10-06 18:20:52 +00:00
/* peer's queue is full */
2008-12-22 00:52:44 +00:00
if ( requestQueueIsFull ( msgs ) ) {
2007-10-06 18:20:52 +00:00
dbgmsg ( msgs , " declining request because we're full " ) ;
2007-09-20 16:32:01 +00:00
return TR_ADDREQ_FULL ;
2007-10-06 18:20:52 +00:00
}
2007-09-20 16:32:01 +00:00
2009-02-18 21:27:44 +00:00
/* peer doesn't have this piece */
if ( ! tr_bitfieldHas ( msgs - > peer - > have , index ) )
return TR_ADDREQ_MISSING ;
2007-10-05 00:16:47 +00:00
/* have we already asked for this piece? */
2008-10-11 04:07:50 +00:00
req . index = index ;
req . offset = offset ;
req . length = length ;
2009-01-04 16:29:44 +00:00
if ( reqListHas ( & msgs - > clientAskedFor , & req ) ) {
2008-12-22 00:52:44 +00:00
dbgmsg ( msgs , " declining because it's a duplicate " ) ;
return TR_ADDREQ_DUPLICATE ;
}
2009-01-04 16:29:44 +00:00
if ( reqListHas ( & msgs - > clientWillAskFor , & req ) ) {
2008-12-22 00:52:44 +00:00
dbgmsg ( msgs , " declining because it's a duplicate " ) ;
return TR_ADDREQ_DUPLICATE ;
2007-10-06 18:20:52 +00:00
}
2007-10-05 00:16:47 +00:00
2007-10-06 18:20:52 +00:00
/**
* * * Accept this request
* */
2007-09-20 16:32:01 +00:00
2008-11-23 16:30:09 +00:00
dbgmsg ( msgs , " adding req for % " PRIu32 " :% " PRIu32 " ->% " PRIu32 " to our `will request' list " ,
index , offset , length ) ;
2008-02-29 03:41:50 +00:00
req . time_requested = time ( NULL ) ;
2008-10-11 04:07:50 +00:00
reqListAppend ( & msgs - > clientWillAskFor , & req ) ;
2007-09-20 16:32:01 +00:00
return TR_ADDREQ_OK ;
}
2007-10-06 18:20:52 +00:00
static void
2008-12-05 01:12:55 +00:00
cancelAllRequestsToPeer ( tr_peermsgs * msgs , tr_bool sendCancel )
2007-10-06 18:20:52 +00:00
{
2009-01-04 16:29:44 +00:00
size_t i ;
2008-02-29 03:41:50 +00:00
struct request_list a = msgs - > clientWillAskFor ;
struct request_list b = msgs - > clientAskedFor ;
2008-11-23 16:30:09 +00:00
dbgmsg ( msgs , " cancelling all requests to peer " ) ;
2007-10-06 18:20:52 +00:00
2008-02-29 03:41:50 +00:00
msgs - > clientAskedFor = REQUEST_LIST_INIT ;
msgs - > clientWillAskFor = REQUEST_LIST_INIT ;
2007-10-06 18:20:52 +00:00
2009-01-04 16:29:44 +00:00
for ( i = 0 ; i < a . len ; + + i )
fireCancelledReq ( msgs , & a . fifo [ i ] ) ;
2008-02-29 03:41:50 +00:00
2009-01-04 16:29:44 +00:00
for ( i = 0 ; i < b . len ; + + i ) {
fireCancelledReq ( msgs , & b . fifo [ i ] ) ;
2008-12-05 01:12:55 +00:00
if ( sendCancel )
2009-01-04 16:29:44 +00:00
protocolSendCancel ( msgs , & b . fifo [ i ] ) ;
2007-10-06 18:20:52 +00:00
}
2008-02-29 03:41:50 +00:00
reqListClear ( & a ) ;
reqListClear ( & b ) ;
2007-10-06 18:20:52 +00:00
}
2008-10-11 04:07:50 +00:00
void
tr_peerMsgsCancel ( tr_peermsgs * msgs ,
uint32_t pieceIndex ,
uint32_t offset ,
uint32_t length )
{
struct peer_request req ;
assert ( msgs ! = NULL ) ;
assert ( length > 0 ) ;
2008-11-23 16:30:09 +00:00
2008-10-11 04:07:50 +00:00
/* have we asked the peer for this piece? */
req . index = pieceIndex ;
req . offset = offset ;
req . length = length ;
/* if it's only in the queue and hasn't been sent yet, free it */
2008-11-23 16:30:09 +00:00
if ( reqListRemove ( & msgs - > clientWillAskFor , & req ) ) {
2008-12-16 22:08:17 +00:00
dbgmsg ( msgs , " cancelling % " PRIu32 " :% " PRIu32 " ->% " PRIu32 , pieceIndex , offset , length ) ;
2008-10-11 04:07:50 +00:00
fireCancelledReq ( msgs , & req ) ;
2008-11-23 16:30:09 +00:00
}
2008-10-11 04:07:50 +00:00
/* if it's already been sent, send a cancel message too */
2008-10-25 02:20:16 +00:00
if ( reqListRemove ( & msgs - > clientAskedFor , & req ) ) {
2008-12-16 22:08:17 +00:00
dbgmsg ( msgs , " cancelling % " PRIu32 " :% " PRIu32 " ->% " PRIu32 , pieceIndex , offset , length ) ;
2008-10-11 04:07:50 +00:00
protocolSendCancel ( msgs , & req ) ;
fireCancelledReq ( msgs , & req ) ;
}
}
2008-12-02 17:10:54 +00:00
2007-09-20 16:32:01 +00:00
/**
* * *
* */
static void
sendLtepHandshake ( tr_peermsgs * msgs )
{
2008-12-05 22:56:19 +00:00
tr_benc val , * m ;
char * buf ;
int len ;
int pex ;
2008-08-16 05:11:28 +00:00
struct evbuffer * out = msgs - > outMessages ;
2007-09-20 16:32:01 +00:00
2007-09-29 00:46:41 +00:00
if ( msgs - > clientSentLtepHandshake )
return ;
2007-09-20 16:32:01 +00:00
dbgmsg ( msgs , " sending an ltep handshake " ) ;
2007-09-29 00:46:41 +00:00
msgs - > clientSentLtepHandshake = 1 ;
/* decide if we want to advertise pex support */
2007-12-24 05:03:40 +00:00
if ( ! tr_torrentAllowsPex ( msgs - > torrent ) )
2007-09-29 00:46:41 +00:00
pex = 0 ;
else if ( msgs - > peerSentLtepHandshake )
pex = msgs - > peerSupportsPex ? 1 : 0 ;
else
pex = 1 ;
2008-12-05 22:56:19 +00:00
tr_bencInitDict ( & val , 5 ) ;
2008-12-02 19:46:51 +00:00
tr_bencDictAddInt ( & val , " e " , msgs - > session - > encryptionMode ! = TR_CLEAR_PREFERRED ) ;
2008-08-16 21:06:57 +00:00
tr_bencDictAddInt ( & val , " p " , tr_sessionGetPeerPort ( msgs - > session ) ) ;
2008-12-02 19:46:51 +00:00
tr_bencDictAddInt ( & val , " upload_only " , tr_torrentIsSeed ( msgs - > torrent ) ) ;
2008-04-17 02:11:29 +00:00
tr_bencDictAddStr ( & val , " v " , TR_NAME " " USERAGENT_PREFIX ) ;
m = tr_bencDictAddDict ( & val , " m " , 1 ) ;
if ( pex )
tr_bencDictAddInt ( m , " ut_pex " , TR_LTEP_PEX ) ;
2009-06-02 01:48:48 +00:00
buf = tr_bencToStr ( & val , TR_FMT_BENC , & len ) ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
tr_peerIoWriteUint32 ( msgs - > peer - > io , out , 2 * sizeof ( uint8_t ) + len ) ;
tr_peerIoWriteUint8 ( msgs - > peer - > io , out , BT_LTEP ) ;
tr_peerIoWriteUint8 ( msgs - > peer - > io , out , LTEP_HANDSHAKE ) ;
tr_peerIoWriteBytes ( msgs - > peer - > io , out , buf , len ) ;
2008-08-16 05:11:28 +00:00
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
2008-12-05 22:56:19 +00:00
dbgOutMessageLen ( msgs ) ;
2007-09-20 16:32:01 +00:00
/* cleanup */
tr_bencFree ( & val ) ;
tr_free ( buf ) ;
}
static void
2008-09-23 19:11:04 +00:00
parseLtepHandshake ( tr_peermsgs * msgs ,
int len ,
struct evbuffer * inbuf )
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
int64_t i ;
tr_benc val , * sub ;
2007-09-20 16:32:01 +00:00
uint8_t * tmp = tr_new ( uint8_t , len ) ;
2007-09-22 03:37:37 +00:00
2008-12-12 02:44:21 +00:00
tr_peerIoReadBytes ( msgs - > peer - > io , inbuf , tmp , len ) ;
2007-09-29 00:46:41 +00:00
msgs - > peerSentLtepHandshake = 1 ;
2007-09-20 16:32:01 +00:00
2008-12-05 22:56:19 +00:00
if ( tr_bencLoad ( tmp , len , & val , NULL ) | | ! tr_bencIsDict ( & val ) )
2008-09-23 19:11:04 +00:00
{
2007-09-20 16:32:01 +00:00
dbgmsg ( msgs , " GET extended-handshake, couldn't get dictionary " ) ;
tr_free ( tmp ) ;
return ;
}
2008-11-23 16:30:09 +00:00
dbgmsg ( msgs , " here is the handshake: [%*.*s] " , len , len , tmp ) ;
2007-09-29 00:46:41 +00:00
/* does the peer prefer encrypted connections? */
2008-08-20 18:42:45 +00:00
if ( tr_bencDictFindInt ( & val , " e " , & i ) )
2008-12-12 02:44:21 +00:00
msgs - > peer - > encryption_preference = i ? ENCRYPTION_PREFERENCE_YES
2008-12-05 22:56:19 +00:00
: ENCRYPTION_PREFERENCE_NO ;
2007-09-29 00:46:41 +00:00
2007-09-20 16:32:01 +00:00
/* check supported messages for utorrent pex */
2008-01-24 17:16:20 +00:00
msgs - > peerSupportsPex = 0 ;
2008-12-05 22:56:19 +00:00
if ( tr_bencDictFindDict ( & val , " m " , & sub ) ) {
if ( tr_bencDictFindInt ( sub , " ut_pex " , & i ) ) {
2008-08-20 18:42:45 +00:00
msgs - > ut_pex_id = ( uint8_t ) i ;
2008-01-24 17:16:20 +00:00
msgs - > peerSupportsPex = msgs - > ut_pex_id = = 0 ? 0 : 1 ;
2007-09-20 16:32:01 +00:00
dbgmsg ( msgs , " msgs->ut_pex is %d " , ( int ) msgs - > ut_pex_id ) ;
}
}
2008-12-02 19:46:51 +00:00
/* look for upload_only (BEP 21) */
if ( tr_bencDictFindInt ( & val , " upload_only " , & i ) )
fireUploadOnly ( msgs , i ! = 0 ) ;
2007-09-20 16:32:01 +00:00
/* get peer's listening port */
2008-12-05 22:56:19 +00:00
if ( tr_bencDictFindInt ( & val , " p " , & i ) ) {
2008-12-12 02:44:21 +00:00
msgs - > peer - > port = htons ( ( uint16_t ) i ) ;
dbgmsg ( msgs , " msgs->port is now %hu " , msgs - > peer - > port ) ;
2007-09-20 16:32:01 +00:00
}
2008-12-08 20:23:10 +00:00
/* get peer's maximum request queue size */
if ( tr_bencDictFindInt ( & val , " reqq " , & i ) )
msgs - > reqq = i ;
2007-09-20 16:32:01 +00:00
tr_bencFree ( & val ) ;
tr_free ( tmp ) ;
}
static void
2008-12-05 22:56:19 +00:00
parseUtPex ( tr_peermsgs * msgs , int msglen , struct evbuffer * inbuf )
2007-09-20 16:32:01 +00:00
{
2008-12-05 22:56:19 +00:00
int loaded = 0 ;
uint8_t * tmp = tr_new ( uint8_t , msglen ) ;
tr_benc val ;
2009-01-13 21:00:05 +00:00
tr_torrent * tor = msgs - > torrent ;
2008-12-05 22:56:19 +00:00
const uint8_t * added ;
size_t added_len ;
2008-08-20 18:42:45 +00:00
2008-12-12 02:44:21 +00:00
tr_peerIoReadBytes ( msgs - > peer - > io , inbuf , tmp , msglen ) ;
2007-09-20 16:32:01 +00:00
2008-03-17 02:45:09 +00:00
if ( tr_torrentAllowsPex ( tor )
2008-12-15 00:17:08 +00:00
& & ( ( loaded = ! tr_bencLoad ( tmp , msglen , & val , NULL ) ) ) )
2008-01-03 03:45:10 +00:00
{
2008-12-15 00:17:08 +00:00
if ( tr_bencDictFindRaw ( & val , " added " , & added , & added_len ) )
{
const uint8_t * added_f = NULL ;
tr_pex * pex ;
size_t i , n ;
size_t added_f_len = 0 ;
tr_bencDictFindRaw ( & val , " added.f " , & added_f , & added_f_len ) ;
pex =
tr_peerMgrCompactToPex ( added , added_len , added_f , added_f_len ,
& n ) ;
for ( i = 0 ; i < n ; + + i )
2009-01-13 21:00:05 +00:00
tr_peerMgrAddPex ( tor , TR_PEER_FROM_PEX , pex + i ) ;
2008-12-15 00:17:08 +00:00
tr_free ( pex ) ;
}
if ( tr_bencDictFindRaw ( & val , " added6 " , & added , & added_len ) )
{
const uint8_t * added_f = NULL ;
tr_pex * pex ;
size_t i , n ;
size_t added_f_len = 0 ;
tr_bencDictFindRaw ( & val , " added6.f " , & added_f , & added_f_len ) ;
pex =
tr_peerMgrCompact6ToPex ( added , added_len , added_f , added_f_len ,
& n ) ;
for ( i = 0 ; i < n ; + + i )
2009-01-13 21:00:05 +00:00
tr_peerMgrAddPex ( tor , TR_PEER_FROM_PEX , pex + i ) ;
2008-12-15 00:17:08 +00:00
tr_free ( pex ) ;
}
2007-09-20 16:32:01 +00:00
}
2008-03-01 14:09:18 +00:00
if ( loaded )
2008-01-03 03:45:10 +00:00
tr_bencFree ( & val ) ;
2007-09-20 16:32:01 +00:00
tr_free ( tmp ) ;
}
2008-09-23 19:11:04 +00:00
static void sendPex ( tr_peermsgs * msgs ) ;
2007-09-20 16:32:01 +00:00
static void
2008-09-23 19:11:04 +00:00
parseLtep ( tr_peermsgs * msgs ,
int msglen ,
struct evbuffer * inbuf )
2007-09-20 16:32:01 +00:00
{
uint8_t ltep_msgid ;
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint8 ( msgs - > peer - > io , inbuf , & ltep_msgid ) ;
2007-09-20 16:32:01 +00:00
msglen - - ;
if ( ltep_msgid = = LTEP_HANDSHAKE )
{
dbgmsg ( msgs , " got ltep handshake " ) ;
parseLtepHandshake ( msgs , msglen , inbuf ) ;
2008-12-12 02:44:21 +00:00
if ( tr_peerIoSupportsLTEP ( msgs - > peer - > io ) )
2007-11-16 04:42:51 +00:00
{
sendLtepHandshake ( msgs ) ;
sendPex ( msgs ) ;
}
2007-09-20 16:32:01 +00:00
}
2007-11-22 06:48:08 +00:00
else if ( ltep_msgid = = TR_LTEP_PEX )
2007-09-20 16:32:01 +00:00
{
dbgmsg ( msgs , " got ut pex " ) ;
msgs - > peerSupportsPex = 1 ;
parseUtPex ( msgs , msglen , inbuf ) ;
}
else
{
dbgmsg ( msgs , " skipping unknown ltep message (%d) " , ( int ) ltep_msgid ) ;
evbuffer_drain ( inbuf , msglen ) ;
}
}
static int
2008-09-23 19:11:04 +00:00
readBtLength ( tr_peermsgs * msgs ,
struct evbuffer * inbuf ,
size_t inlen )
2007-09-20 16:32:01 +00:00
{
uint32_t len ;
2008-09-23 19:11:04 +00:00
if ( inlen < sizeof ( len ) )
2008-09-19 17:03:25 +00:00
return READ_LATER ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & len ) ;
2007-09-20 16:32:01 +00:00
2007-09-26 01:55:04 +00:00
if ( len = = 0 ) /* peer sent us a keepalive message */
2007-10-06 18:20:52 +00:00
dbgmsg ( msgs , " got KeepAlive " ) ;
2009-01-02 23:28:57 +00:00
else
{
msgs - > incoming . length = len ;
msgs - > state = AWAITING_BT_ID ;
}
2007-09-26 01:55:04 +00:00
2008-09-19 17:03:25 +00:00
return READ_NOW ;
2007-09-20 16:32:01 +00:00
}
2009-01-02 23:28:57 +00:00
static int readBtMessage ( tr_peermsgs * msgs ,
struct evbuffer * inbuf ,
size_t inlen ) ;
static int
readBtId ( tr_peermsgs * msgs ,
struct evbuffer * inbuf ,
size_t inlen )
{
uint8_t id ;
if ( inlen < sizeof ( uint8_t ) )
return READ_LATER ;
tr_peerIoReadUint8 ( msgs - > peer - > io , inbuf , & id ) ;
msgs - > incoming . id = id ;
2009-01-22 04:20:30 +00:00
dbgmsg ( msgs , " msgs->incoming.id is now %d; msgs->incoming.length is %zu " , id , ( size_t ) msgs - > incoming . length ) ;
2009-01-02 23:28:57 +00:00
if ( id = = BT_PIECE )
{
msgs - > state = AWAITING_BT_PIECE ;
return READ_NOW ;
}
else if ( msgs - > incoming . length ! = 1 )
{
msgs - > state = AWAITING_BT_MESSAGE ;
return READ_NOW ;
}
else return readBtMessage ( msgs , inbuf , inlen - 1 ) ;
}
2007-10-03 16:42:43 +00:00
static void
updatePeerProgress ( tr_peermsgs * msgs )
{
2008-12-12 02:44:21 +00:00
msgs - > peer - > progress = tr_bitfieldCountTrueBits ( msgs - > peer - > have ) / ( float ) msgs - > torrent - > info . pieceCount ;
dbgmsg ( msgs , " peer progress is %f " , msgs - > peer - > progress ) ;
2008-12-02 17:10:54 +00:00
updateFastSet ( msgs ) ;
2007-10-03 16:42:43 +00:00
updateInterest ( msgs ) ;
firePeerProgress ( msgs ) ;
}
2007-10-27 15:45:03 +00:00
static void
2008-09-23 19:11:04 +00:00
peerMadeRequest ( tr_peermsgs * msgs ,
const struct peer_request * req )
2007-10-27 15:45:03 +00:00
{
2008-12-12 02:44:21 +00:00
const tr_bool fext = tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ;
2007-10-27 15:45:03 +00:00
const int reqIsValid = requestIsValid ( msgs , req ) ;
2009-01-02 17:01:55 +00:00
const int clientHasPiece = reqIsValid & & tr_cpPieceIsComplete ( & msgs - > torrent - > completion , req - > index ) ;
2008-12-12 02:44:21 +00:00
const int peerIsChoked = msgs - > peer - > peerIsChoked ;
2007-09-20 16:32:01 +00:00
2008-12-02 17:10:54 +00:00
int allow = FALSE ;
if ( ! reqIsValid )
2007-10-27 15:45:03 +00:00
dbgmsg ( msgs , " rejecting an invalid request. " ) ;
2008-12-02 17:10:54 +00:00
else if ( ! clientHasPiece )
2007-10-27 15:45:03 +00:00
dbgmsg ( msgs , " rejecting request for a piece we don't have. " ) ;
2008-12-02 17:10:54 +00:00
else if ( peerIsChoked )
dbgmsg ( msgs , " rejecting request from choked peer " ) ;
else
allow = TRUE ;
if ( allow )
2008-11-29 20:37:34 +00:00
reqListAppend ( & msgs - > peerAskedFor , req ) ;
2008-12-02 17:10:54 +00:00
else if ( fext )
protocolSendReject ( msgs , req ) ;
2007-10-27 15:45:03 +00:00
}
2007-09-20 16:32:01 +00:00
2009-02-19 21:55:00 +00:00
static tr_bool
2008-12-05 22:56:19 +00:00
messageLengthIsCorrect ( const tr_peermsgs * msg , uint8_t id , uint32_t len )
2007-10-27 15:45:03 +00:00
{
2007-09-20 16:32:01 +00:00
switch ( id )
{
case BT_CHOKE :
case BT_UNCHOKE :
case BT_INTERESTED :
case BT_NOT_INTERESTED :
2008-12-02 17:10:54 +00:00
case BT_FEXT_HAVE_ALL :
case BT_FEXT_HAVE_NONE :
2008-09-23 19:11:04 +00:00
return len = = 1 ;
2007-09-20 16:32:01 +00:00
case BT_HAVE :
2008-12-02 17:10:54 +00:00
case BT_FEXT_SUGGEST :
case BT_FEXT_ALLOWED_FAST :
2008-12-02 00:37:10 +00:00
return len = = 5 ;
2007-09-20 16:32:01 +00:00
2007-10-27 15:45:03 +00:00
case BT_BITFIELD :
2008-09-23 19:11:04 +00:00
return len = = ( msg - > torrent - > info . pieceCount + 7u ) / 8u + 1u ;
2007-10-27 15:45:03 +00:00
case BT_REQUEST :
case BT_CANCEL :
2008-12-02 17:10:54 +00:00
case BT_FEXT_REJECT :
2008-09-23 19:11:04 +00:00
return len = = 13 ;
2007-09-28 16:40:21 +00:00
2007-10-27 15:45:03 +00:00
case BT_PIECE :
2008-09-23 19:11:04 +00:00
return len > 9 & & len < = 16393 ;
2007-09-20 16:32:01 +00:00
2007-10-27 15:45:03 +00:00
case BT_PORT :
2008-09-23 19:11:04 +00:00
return len = = 3 ;
2007-09-20 16:32:01 +00:00
case BT_LTEP :
2007-10-27 15:45:03 +00:00
return len > = 2 ;
2007-09-20 16:32:01 +00:00
default :
2007-10-27 15:45:03 +00:00
return FALSE ;
}
}
2008-09-23 19:11:04 +00:00
static int clientGotBlock ( tr_peermsgs * msgs ,
const uint8_t * block ,
const struct peer_request * req ) ;
2007-10-27 15:45:03 +00:00
2007-11-16 20:40:03 +00:00
static int
2008-11-25 21:35:17 +00:00
readBtPiece ( tr_peermsgs * msgs ,
struct evbuffer * inbuf ,
size_t inlen ,
size_t * setme_piece_bytes_read )
2007-11-16 20:40:03 +00:00
{
2009-01-02 23:28:57 +00:00
struct peer_request * req = & msgs - > incoming . blockReq ;
2008-09-23 19:11:04 +00:00
assert ( EVBUFFER_LENGTH ( inbuf ) > = inlen ) ;
2007-11-16 20:40:03 +00:00
dbgmsg ( msgs , " In readBtPiece " ) ;
2009-01-02 23:28:57 +00:00
if ( ! req - > length )
{
if ( inlen < 8 )
return READ_LATER ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & req - > index ) ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & req - > offset ) ;
req - > length = msgs - > incoming . length - 9 ;
dbgmsg ( msgs , " got incoming block header %u:%u->%u " , req - > index , req - > offset , req - > length ) ;
return READ_NOW ;
}
else
{
2008-12-30 19:44:49 +00:00
int err ;
2008-12-30 00:56:10 +00:00
2009-01-02 23:28:57 +00:00
/* read in another chunk of data */
const size_t nLeft = req - > length - EVBUFFER_LENGTH ( msgs - > incoming . block ) ;
size_t n = MIN ( nLeft , inlen ) ;
size_t i = n ;
while ( i > 0 )
{
uint8_t buf [ MAX_STACK_ARRAY_SIZE ] ;
const size_t thisPass = MIN ( i , sizeof ( buf ) ) ;
tr_peerIoReadBytes ( msgs - > peer - > io , inbuf , buf , thisPass ) ;
evbuffer_add ( msgs - > incoming . block , buf , thisPass ) ;
i - = thisPass ;
}
2008-12-30 00:56:10 +00:00
2009-01-02 23:28:57 +00:00
fireClientGotData ( msgs , n , TRUE ) ;
* setme_piece_bytes_read + = n ;
dbgmsg ( msgs , " got %zu bytes for block %u:%u->%u ... %d remain " ,
n , req - > index , req - > offset , req - > length ,
( int ) ( req - > length - EVBUFFER_LENGTH ( msgs - > incoming . block ) ) ) ;
if ( EVBUFFER_LENGTH ( msgs - > incoming . block ) < req - > length )
return READ_LATER ;
2007-11-16 20:40:03 +00:00
/* we've got the whole block ... process it */
2009-01-02 23:28:57 +00:00
err = clientGotBlock ( msgs , EVBUFFER_DATA ( msgs - > incoming . block ) , req ) ;
2007-11-16 20:40:03 +00:00
/* cleanup */
2008-12-05 22:56:19 +00:00
evbuffer_drain ( msgs - > incoming . block , EVBUFFER_LENGTH ( msgs - > incoming . block ) ) ;
2009-01-02 23:28:57 +00:00
req - > length = 0 ;
msgs - > state = AWAITING_BT_LENGTH ;
2007-11-16 20:40:03 +00:00
if ( ! err )
2008-09-19 17:03:25 +00:00
return READ_NOW ;
2008-12-05 22:56:19 +00:00
else {
2008-01-18 19:13:32 +00:00
fireError ( msgs , err ) ;
2008-09-19 17:03:25 +00:00
return READ_ERR ;
2007-11-16 20:40:03 +00:00
}
}
}
2007-10-27 15:45:03 +00:00
static int
2009-01-02 23:28:57 +00:00
readBtMessage ( tr_peermsgs * msgs , struct evbuffer * inbuf , size_t inlen )
2007-10-27 15:45:03 +00:00
{
2008-09-23 19:11:04 +00:00
uint32_t ui32 ;
uint32_t msglen = msgs - > incoming . length ;
2009-01-02 23:28:57 +00:00
const uint8_t id = msgs - > incoming . id ;
2008-09-23 19:11:04 +00:00
const size_t startBufLen = EVBUFFER_LENGTH ( inbuf ) ;
2008-12-12 02:44:21 +00:00
const tr_bool fext = tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ;
2007-10-27 15:45:03 +00:00
2009-01-02 23:28:57 +00:00
- - msglen ; /* id length */
2009-01-22 04:20:30 +00:00
dbgmsg ( msgs , " got BT id %d, len %d, buffer size is %zu " , ( int ) id , ( int ) msglen , inlen ) ;
2007-11-17 17:49:30 +00:00
if ( inlen < msglen )
2008-09-19 17:03:25 +00:00
return READ_LATER ;
2007-10-27 15:45:03 +00:00
2009-01-02 23:28:57 +00:00
if ( ! messageLengthIsCorrect ( msgs , id , msglen + 1 ) )
2007-10-27 15:45:03 +00:00
{
2008-12-05 22:56:19 +00:00
dbgmsg ( msgs , " bad packet - BT message #%d with a length of %d " , ( int ) id , ( int ) msglen ) ;
2008-10-10 00:38:37 +00:00
fireError ( msgs , EMSGSIZE ) ;
2008-09-19 17:03:25 +00:00
return READ_ERR ;
2007-10-27 15:45:03 +00:00
}
switch ( id )
{
2007-11-10 04:56:27 +00:00
case BT_CHOKE :
dbgmsg ( msgs , " got Choke " ) ;
2008-12-12 02:44:21 +00:00
msgs - > peer - > clientIsChoked = 1 ;
2008-12-02 17:10:54 +00:00
if ( ! fext )
2008-12-05 01:12:55 +00:00
cancelAllRequestsToPeer ( msgs , FALSE ) ;
2007-11-10 04:56:27 +00:00
break ;
case BT_UNCHOKE :
dbgmsg ( msgs , " got Unchoke " ) ;
2008-12-12 02:44:21 +00:00
msgs - > peer - > clientIsChoked = 0 ;
2009-02-11 16:34:35 +00:00
fireNeedReq ( msgs ) ;
2007-11-10 04:56:27 +00:00
break ;
case BT_INTERESTED :
dbgmsg ( msgs , " got Interested " ) ;
2008-12-12 02:44:21 +00:00
msgs - > peer - > peerIsInterested = 1 ;
2007-11-10 04:56:27 +00:00
break ;
case BT_NOT_INTERESTED :
dbgmsg ( msgs , " got Not Interested " ) ;
2008-12-12 02:44:21 +00:00
msgs - > peer - > peerIsInterested = 0 ;
2007-11-10 04:56:27 +00:00
break ;
2008-09-23 19:11:04 +00:00
2007-11-10 04:56:27 +00:00
case BT_HAVE :
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & ui32 ) ;
2007-11-10 04:56:27 +00:00
dbgmsg ( msgs , " got Have: %u " , ui32 ) ;
2008-12-12 02:44:21 +00:00
if ( tr_bitfieldAdd ( msgs - > peer - > have , ui32 ) ) {
2008-10-03 04:49:06 +00:00
fireError ( msgs , ERANGE ) ;
2008-11-30 21:36:49 +00:00
return READ_ERR ;
}
2007-11-10 04:56:27 +00:00
updatePeerProgress ( msgs ) ;
2009-01-02 20:42:35 +00:00
tr_rcTransferred ( & msgs - > torrent - > swarmSpeed ,
2008-09-23 19:11:04 +00:00
msgs - > torrent - > info . pieceSize ) ;
2007-11-10 04:56:27 +00:00
break ;
2008-09-23 19:11:04 +00:00
case BT_BITFIELD :
2009-02-11 16:34:35 +00:00
{
2007-11-10 04:56:27 +00:00
dbgmsg ( msgs , " got a bitfield " ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoReadBytes ( msgs - > peer - > io , inbuf , msgs - > peer - > have - > bits , msglen ) ;
2007-11-10 04:56:27 +00:00
updatePeerProgress ( msgs ) ;
2009-02-11 16:34:35 +00:00
fireNeedReq ( msgs ) ;
2007-11-10 04:56:27 +00:00
break ;
2009-02-11 16:34:35 +00:00
}
2007-11-10 04:56:27 +00:00
2008-09-23 19:11:04 +00:00
case BT_REQUEST :
{
2008-03-01 14:09:18 +00:00
struct peer_request r ;
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . index ) ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . offset ) ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . length ) ;
2008-12-01 05:56:39 +00:00
dbgmsg ( msgs , " got Request: %u:%u->%u " , r . index , r . offset , r . length ) ;
2008-03-01 14:09:18 +00:00
peerMadeRequest ( msgs , & r ) ;
2007-11-10 04:56:27 +00:00
break ;
}
2008-09-23 19:11:04 +00:00
case BT_CANCEL :
{
2008-03-01 14:09:18 +00:00
struct peer_request r ;
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . index ) ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . offset ) ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . length ) ;
2008-12-01 05:56:39 +00:00
dbgmsg ( msgs , " got a Cancel %u:%u->%u " , r . index , r . offset , r . length ) ;
2008-12-02 17:10:54 +00:00
if ( reqListRemove ( & msgs - > peerAskedFor , & r ) & & fext )
protocolSendReject ( msgs , & r ) ;
2007-11-10 04:56:27 +00:00
break ;
}
2007-11-16 20:40:03 +00:00
case BT_PIECE :
2009-01-02 23:28:57 +00:00
assert ( 0 ) ; /* handled elsewhere! */
2007-11-10 04:56:27 +00:00
break ;
2008-09-23 19:11:04 +00:00
2007-11-10 04:56:27 +00:00
case BT_PORT :
dbgmsg ( msgs , " Got a BT_PORT " ) ;
2009-05-16 14:31:18 +00:00
tr_peerIoReadUint16 ( msgs - > peer - > io , inbuf , & msgs - > peer - > dht_port ) ;
2009-05-27 17:35:49 +00:00
if ( msgs - > peer - > dht_port > 0 )
2009-05-20 03:55:09 +00:00
tr_dhtAddNode ( msgs - > session , & msgs - > peer - > addr , msgs - > peer - > dht_port , 0 ) ;
2007-11-10 04:56:27 +00:00
break ;
2008-09-23 19:11:04 +00:00
2008-12-02 17:10:54 +00:00
case BT_FEXT_SUGGEST :
dbgmsg ( msgs , " Got a BT_FEXT_SUGGEST " ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & ui32 ) ;
2008-12-02 17:10:54 +00:00
if ( fext )
fireClientGotSuggest ( msgs , ui32 ) ;
else {
2008-12-03 13:21:41 +00:00
fireError ( msgs , EMSGSIZE ) ;
2008-12-02 17:10:54 +00:00
return READ_ERR ;
}
2007-11-10 04:56:27 +00:00
break ;
2008-09-23 19:11:04 +00:00
2008-12-02 17:10:54 +00:00
case BT_FEXT_ALLOWED_FAST :
dbgmsg ( msgs , " Got a BT_FEXT_ALLOWED_FAST " ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & ui32 ) ;
2008-12-02 17:10:54 +00:00
if ( fext )
fireClientGotAllowedFast ( msgs , ui32 ) ;
else {
2008-12-03 13:21:41 +00:00
fireError ( msgs , EMSGSIZE ) ;
2008-12-02 17:10:54 +00:00
return READ_ERR ;
}
2007-11-10 04:56:27 +00:00
break ;
2008-09-23 19:11:04 +00:00
2008-12-02 17:10:54 +00:00
case BT_FEXT_HAVE_ALL :
dbgmsg ( msgs , " Got a BT_FEXT_HAVE_ALL " ) ;
if ( fext ) {
2008-12-12 02:44:21 +00:00
tr_bitfieldAddRange ( msgs - > peer - > have , 0 , msgs - > torrent - > info . pieceCount ) ;
2008-12-02 17:10:54 +00:00
updatePeerProgress ( msgs ) ;
} else {
2008-12-03 13:21:41 +00:00
fireError ( msgs , EMSGSIZE ) ;
2008-12-02 17:10:54 +00:00
return READ_ERR ;
}
break ;
2008-09-23 19:11:04 +00:00
2008-12-02 17:10:54 +00:00
case BT_FEXT_HAVE_NONE :
dbgmsg ( msgs , " Got a BT_FEXT_HAVE_NONE " ) ;
if ( fext ) {
2008-12-12 02:44:21 +00:00
tr_bitfieldClear ( msgs - > peer - > have ) ;
2008-12-02 17:10:54 +00:00
updatePeerProgress ( msgs ) ;
} else {
2008-12-03 13:21:41 +00:00
fireError ( msgs , EMSGSIZE ) ;
2008-12-02 17:10:54 +00:00
return READ_ERR ;
}
2007-11-10 04:56:27 +00:00
break ;
2008-09-23 19:11:04 +00:00
2008-12-02 17:10:54 +00:00
case BT_FEXT_REJECT :
2008-09-23 19:11:04 +00:00
{
2008-03-01 14:09:18 +00:00
struct peer_request r ;
2008-12-02 17:10:54 +00:00
dbgmsg ( msgs , " Got a BT_FEXT_REJECT " ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . index ) ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . offset ) ;
tr_peerIoReadUint32 ( msgs - > peer - > io , inbuf , & r . length ) ;
2008-12-02 17:10:54 +00:00
if ( fext )
reqListRemove ( & msgs - > clientAskedFor , & r ) ;
else {
2008-12-03 13:21:41 +00:00
fireError ( msgs , EMSGSIZE ) ;
2008-12-02 17:10:54 +00:00
return READ_ERR ;
}
2007-11-10 04:56:27 +00:00
break ;
}
case BT_LTEP :
dbgmsg ( msgs , " Got a BT_LTEP " ) ;
parseLtep ( msgs , msglen , inbuf ) ;
break ;
default :
dbgmsg ( msgs , " peer sent us an UNKNOWN: %d " , ( int ) id ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoDrain ( msgs - > peer - > io , inbuf , msglen ) ;
2007-11-10 04:56:27 +00:00
break ;
2007-09-20 16:32:01 +00:00
}
2009-01-02 23:28:57 +00:00
assert ( msglen + 1 = = msgs - > incoming . length ) ;
assert ( EVBUFFER_LENGTH ( inbuf ) = = startBufLen - msglen ) ;
2007-11-13 05:36:43 +00:00
2009-01-02 23:28:57 +00:00
msgs - > state = AWAITING_BT_LENGTH ;
return READ_NOW ;
2007-09-20 16:32:01 +00:00
}
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2008-12-05 22:56:19 +00:00
decrementDownloadedCount ( tr_peermsgs * msgs , uint32_t byteCount )
2008-03-18 17:46:29 +00:00
{
tr_torrent * tor = msgs - > torrent ;
2008-09-23 19:11:04 +00:00
2008-03-18 17:46:29 +00:00
tor - > downloadedCur - = MIN ( tor - > downloadedCur , byteCount ) ;
}
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2008-12-05 22:56:19 +00:00
clientGotUnwantedBlock ( tr_peermsgs * msgs , const struct peer_request * req )
2007-09-20 16:32:01 +00:00
{
2008-03-18 17:46:29 +00:00
decrementDownloadedCount ( msgs , req - > length ) ;
2007-09-20 16:32:01 +00:00
}
static void
2008-12-05 22:56:19 +00:00
addPeerToBlamefield ( tr_peermsgs * msgs , uint32_t index )
2007-09-20 16:32:01 +00:00
{
2008-12-12 02:44:21 +00:00
if ( ! msgs - > peer - > blame )
msgs - > peer - > blame = tr_bitfieldNew ( msgs - > torrent - > info . pieceCount ) ;
tr_bitfieldAdd ( msgs - > peer - > blame , index ) ;
2007-09-20 16:32:01 +00:00
}
2008-10-03 04:49:06 +00:00
/* returns 0 on success, or an errno on failure */
static int
2008-09-23 19:11:04 +00:00
clientGotBlock ( tr_peermsgs * msgs ,
const uint8_t * data ,
const struct peer_request * req )
2007-09-20 16:32:01 +00:00
{
2008-12-05 22:56:19 +00:00
int err ;
tr_torrent * tor = msgs - > torrent ;
2008-03-22 18:10:59 +00:00
const tr_block_index_t block = _tr_block ( tor , req - > index , req - > offset ) ;
2007-11-09 01:22:15 +00:00
2008-08-01 16:43:22 +00:00
assert ( msgs ) ;
assert ( req ) ;
2007-11-13 05:36:43 +00:00
2008-12-05 22:56:19 +00:00
if ( req - > length ! = tr_torBlockCountBytes ( msgs - > torrent , block ) ) {
2007-11-13 05:36:43 +00:00
dbgmsg ( msgs , " wrong block size -- expected %u, got %d " ,
tr_torBlockCountBytes ( msgs - > torrent , block ) , req - > length ) ;
2008-10-03 04:49:06 +00:00
return EMSGSIZE ;
2007-11-13 05:36:43 +00:00
}
2007-11-09 01:22:15 +00:00
/* save the block */
2008-12-05 22:56:19 +00:00
dbgmsg ( msgs , " got block %u:%u->%u " , req - > index , req - > offset , req - > length ) ;
2007-09-20 16:32:01 +00:00
/**
* * * Remove the block from our ` we asked for this ' list
* */
2008-12-05 22:56:19 +00:00
if ( ! reqListRemove ( & msgs - > clientAskedFor , req ) ) {
2007-11-09 01:22:15 +00:00
clientGotUnwantedBlock ( msgs , req ) ;
2007-09-20 16:32:01 +00:00
dbgmsg ( msgs , " we didn't ask for this message... " ) ;
2007-11-13 05:36:43 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
2007-11-09 01:22:15 +00:00
2007-09-20 16:32:01 +00:00
dbgmsg ( msgs , " peer has %d more blocks we've asked for " ,
2009-01-04 16:29:44 +00:00
msgs - > clientAskedFor . len ) ;
2007-11-16 15:45:26 +00:00
2007-09-20 16:32:01 +00:00
/**
* * * Error checks
* */
2009-01-02 17:01:55 +00:00
if ( tr_cpBlockIsComplete ( & tor - > completion , block ) ) {
2007-11-09 01:22:15 +00:00
dbgmsg ( msgs , " we have this block already... " ) ;
clientGotUnwantedBlock ( msgs , req ) ;
2007-11-13 05:36:43 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
/**
2007-11-09 01:22:15 +00:00
* * * Save the block
2007-09-20 16:32:01 +00:00
* */
2008-10-03 04:49:06 +00:00
if ( ( err = tr_ioWrite ( tor , req - > index , req - > offset , req - > length , data ) ) )
2008-01-18 19:13:32 +00:00
return err ;
2007-10-31 04:23:51 +00:00
2007-11-09 01:22:15 +00:00
addPeerToBlamefield ( msgs , req - > index ) ;
fireGotBlock ( msgs , req ) ;
2007-11-13 05:36:43 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
2008-11-24 04:21:23 +00:00
static int peerPulse ( void * vmsgs ) ;
2008-11-17 04:00:57 +00:00
static void
didWrite ( tr_peerIo * io UNUSED , size_t bytesWritten , int wasPieceData , void * vmsgs )
{
tr_peermsgs * msgs = vmsgs ;
firePeerGotData ( msgs , bytesWritten , wasPieceData ) ;
2009-02-13 18:23:56 +00:00
if ( tr_isPeerIo ( io ) & & io - > userData )
peerPulse ( msgs ) ;
2008-11-17 04:00:57 +00:00
}
2007-09-20 16:32:01 +00:00
static ReadState
2008-12-16 22:08:17 +00:00
canRead ( tr_peerIo * io , void * vmsgs , size_t * piece )
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
ReadState ret ;
tr_peermsgs * msgs = vmsgs ;
2008-12-16 22:08:17 +00:00
struct evbuffer * in = tr_peerIoGetReadBuffer ( io ) ;
2008-09-23 19:11:04 +00:00
const size_t inlen = EVBUFFER_LENGTH ( in ) ;
2007-09-20 16:32:01 +00:00
2009-01-22 04:20:30 +00:00
dbgmsg ( msgs , " canRead: inlen is %zu, msgs->state is %d " , inlen , msgs - > state ) ;
2008-02-29 17:09:33 +00:00
if ( ! inlen )
2009-01-02 23:28:57 +00:00
{
ret = READ_LATER ;
}
else if ( msgs - > state = = AWAITING_BT_PIECE )
{
ret = inlen ? readBtPiece ( msgs , in , inlen , piece ) : READ_LATER ;
}
else switch ( msgs - > state )
{
case AWAITING_BT_LENGTH :
ret = readBtLength ( msgs , in , inlen ) ; break ;
2008-09-23 19:11:04 +00:00
2009-01-02 23:28:57 +00:00
case AWAITING_BT_ID :
ret = readBtId ( msgs , in , inlen ) ; break ;
case AWAITING_BT_MESSAGE :
ret = readBtMessage ( msgs , in , inlen ) ; break ;
default :
2009-01-16 17:29:42 +00:00
ret = READ_ERR ;
2009-01-02 23:28:57 +00:00
assert ( 0 ) ;
}
2008-11-17 04:00:57 +00:00
2009-01-22 04:20:30 +00:00
dbgmsg ( msgs , " canRead: ret is %d " , ( int ) ret ) ;
2008-11-17 04:00:57 +00:00
/* log the raw data that was read */
2008-11-30 21:36:49 +00:00
if ( ( ret ! = READ_ERR ) & & ( EVBUFFER_LENGTH ( in ) ! = inlen ) )
2008-11-17 04:00:57 +00:00
fireClientGotData ( msgs , inlen - EVBUFFER_LENGTH ( in ) , FALSE ) ;
2007-09-22 05:16:32 +00:00
2007-09-20 16:32:01 +00:00
return ret ;
}
/**
* * *
* */
2008-06-09 22:53:45 +00:00
static int
2009-01-05 04:27:54 +00:00
ratePulse ( tr_peermsgs * msgs , uint64_t now )
2007-10-06 18:20:52 +00:00
{
2009-01-05 04:27:54 +00:00
const double rateToClient = tr_peerGetPieceSpeed ( msgs - > peer , now , TR_PEER_TO_CLIENT ) ;
2008-12-16 22:08:17 +00:00
const int seconds = 10 ;
2008-12-21 18:31:28 +00:00
const int floor = 8 ;
2008-12-16 22:08:17 +00:00
const int estimatedBlocksInPeriod = ( rateToClient * seconds * 1024 ) / msgs - > torrent - > blockSize ;
2008-12-21 18:31:28 +00:00
msgs - > maxActiveRequests = floor + estimatedBlocksInPeriod ;
2008-12-16 22:08:17 +00:00
2008-12-08 20:23:10 +00:00
if ( msgs - > reqq > 0 )
msgs - > maxActiveRequests = MIN ( msgs - > maxActiveRequests , msgs - > reqq ) ;
2008-12-16 22:08:17 +00:00
2007-10-06 18:20:52 +00:00
return TRUE ;
}
2008-11-28 16:00:29 +00:00
static size_t
fillOutputBuffer ( tr_peermsgs * msgs , time_t now )
2007-09-20 16:32:01 +00:00
{
2008-11-28 16:00:29 +00:00
size_t bytesWritten = 0 ;
struct peer_request req ;
2008-12-22 00:52:44 +00:00
const tr_bool haveMessages = EVBUFFER_LENGTH ( msgs - > outMessages ) ! = 0 ;
2008-12-12 02:44:21 +00:00
const tr_bool fext = tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ;
2008-09-17 19:44:24 +00:00
2008-11-28 16:00:29 +00:00
/**
* * * Protocol messages
* */
2007-10-06 18:20:52 +00:00
2008-11-28 16:00:29 +00:00
if ( haveMessages & & ! msgs - > outMessagesBatchedAt ) /* fresh batch */
2007-09-20 16:32:01 +00:00
{
2008-11-28 16:00:29 +00:00
dbgmsg ( msgs , " started an outMessages batch (length is %zu) " , EVBUFFER_LENGTH ( msgs - > outMessages ) ) ;
msgs - > outMessagesBatchedAt = now ;
}
else if ( haveMessages & & ( ( now - msgs - > outMessagesBatchedAt ) > = msgs - > outMessagesBatchPeriod ) )
{
const size_t len = EVBUFFER_LENGTH ( msgs - > outMessages ) ;
/* flush the protocol messages */
2008-12-12 02:44:21 +00:00
dbgmsg ( msgs , " flushing outMessages... to %p (length is %zu) " , msgs - > peer - > io , len ) ;
tr_peerIoWriteBuf ( msgs - > peer - > io , msgs - > outMessages , FALSE ) ;
2008-11-28 16:00:29 +00:00
msgs - > clientSentAnythingAt = now ;
msgs - > outMessagesBatchedAt = 0 ;
msgs - > outMessagesBatchPeriod = LOW_PRIORITY_INTERVAL_SECS ;
bytesWritten + = len ;
}
2007-10-28 15:20:24 +00:00
2008-11-28 16:00:29 +00:00
/**
* * * Blocks
* */
2007-10-28 15:20:24 +00:00
2009-01-05 04:27:54 +00:00
if ( ( tr_peerIoGetWriteBufferSpace ( msgs - > peer - > io , now ) > = msgs - > torrent - > blockSize )
2008-12-02 17:10:54 +00:00
& & popNextRequest ( msgs , & req ) )
2008-11-28 16:00:29 +00:00
{
2008-12-02 17:10:54 +00:00
if ( requestIsValid ( msgs , & req )
2009-01-02 17:01:55 +00:00
& & tr_cpPieceIsComplete ( & msgs - > torrent - > completion , req . index ) )
2008-12-02 17:10:54 +00:00
{
2009-06-02 18:21:23 +00:00
/* FIXME(libevent2): we can eliminate "buf" and an extra memcpy if we create an evbuffer here, add the message header, then use evbuffer_reserve_space() + tr_ioRead() + evbuffer_commit_space() */
2008-12-30 08:25:39 +00:00
int err ;
2009-01-08 14:05:30 +00:00
static uint8_t buf [ MAX_BLOCK_SIZE ] ;
2008-12-30 08:25:39 +00:00
2008-12-02 17:10:54 +00:00
/* send a block */
2008-12-30 08:25:39 +00:00
if ( ( err = tr_ioRead ( msgs - > torrent , req . index , req . offset , req . length , buf ) ) ) {
2008-12-02 17:10:54 +00:00
fireError ( msgs , err ) ;
bytesWritten = 0 ;
msgs = NULL ;
} else {
2008-12-12 02:44:21 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2008-12-30 20:32:00 +00:00
struct evbuffer * out = tr_getBuffer ( ) ;
2008-12-02 17:10:54 +00:00
dbgmsg ( msgs , " sending block %u:%u->%u " , req . index , req . offset , req . length ) ;
tr_peerIoWriteUint32 ( io , out , sizeof ( uint8_t ) + 2 * sizeof ( uint32_t ) + req . length ) ;
tr_peerIoWriteUint8 ( io , out , BT_PIECE ) ;
tr_peerIoWriteUint32 ( io , out , req . index ) ;
tr_peerIoWriteUint32 ( io , out , req . offset ) ;
tr_peerIoWriteBytes ( io , out , buf , req . length ) ;
tr_peerIoWriteBuf ( io , out , TRUE ) ;
bytesWritten + = EVBUFFER_LENGTH ( out ) ;
msgs - > clientSentAnythingAt = now ;
2008-12-30 20:32:00 +00:00
tr_releaseBuffer ( out ) ;
2008-12-02 17:10:54 +00:00
}
}
else if ( fext ) /* peer needs a reject message */
{
protocolSendReject ( msgs , & req ) ;
2007-11-18 03:18:26 +00:00
}
}
2007-10-28 15:20:24 +00:00
2008-11-28 16:00:29 +00:00
/**
* * * Keepalive
* */
2008-11-30 21:36:49 +00:00
if ( ( msgs ! = NULL )
& & ( msgs - > clientSentAnythingAt ! = 0 )
2008-11-28 16:00:29 +00:00
& & ( ( now - msgs - > clientSentAnythingAt ) > KEEPALIVE_INTERVAL_SECS ) )
2007-11-18 03:18:26 +00:00
{
2008-11-28 16:00:29 +00:00
dbgmsg ( msgs , " sending a keepalive message " ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoWriteUint32 ( msgs - > peer - > io , msgs - > outMessages , 0 ) ;
2008-11-28 16:00:29 +00:00
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
}
2008-02-29 03:41:50 +00:00
2008-11-28 16:00:29 +00:00
return bytesWritten ;
}
2007-11-18 03:18:26 +00:00
2008-11-28 16:00:29 +00:00
static int
peerPulse ( void * vmsgs )
{
tr_peermsgs * msgs = vmsgs ;
const time_t now = time ( NULL ) ;
2009-01-05 04:27:54 +00:00
ratePulse ( msgs , now ) ;
2008-11-28 16:00:29 +00:00
pumpRequestQueue ( msgs , now ) ;
expireOldRequests ( msgs , now ) ;
for ( ; ; )
if ( fillOutputBuffer ( msgs , now ) < 1 )
break ;
2007-10-28 15:20:24 +00:00
2007-09-20 16:32:01 +00:00
return TRUE ; /* loop forever */
}
2008-09-17 19:44:24 +00:00
void
tr_peerMsgsPulse ( tr_peermsgs * msgs )
{
2008-12-22 00:52:44 +00:00
if ( msgs ! = NULL )
2008-09-17 19:44:24 +00:00
peerPulse ( msgs ) ;
}
2007-09-20 16:32:01 +00:00
static void
2008-12-16 22:08:17 +00:00
gotError ( tr_peerIo * io UNUSED ,
short what ,
void * vmsgs )
2007-09-20 16:32:01 +00:00
{
2007-11-17 17:49:30 +00:00
if ( what & EVBUFFER_TIMEOUT )
2008-11-25 21:35:17 +00:00
dbgmsg ( vmsgs , " libevent got a timeout, what=%hd " , what ) ;
2008-01-19 03:30:45 +00:00
if ( what & ( EVBUFFER_EOF | EVBUFFER_ERROR ) )
2007-11-17 17:49:30 +00:00
dbgmsg ( vmsgs , " libevent got an error! what=%hd, errno=%d (%s) " ,
2008-09-23 19:11:04 +00:00
what , errno , tr_strerror ( errno ) ) ;
2008-10-03 04:49:06 +00:00
fireError ( vmsgs , ENOTCONN ) ;
2007-09-20 16:32:01 +00:00
}
static void
sendBitfield ( tr_peermsgs * msgs )
{
2007-10-03 16:42:43 +00:00
struct evbuffer * out = msgs - > outMessages ;
2008-09-23 19:11:04 +00:00
tr_bitfield * field ;
tr_piece_index_t lazyPieces [ LAZY_PIECE_COUNT ] ;
size_t i ;
size_t lazyCount = 0 ;
2008-08-16 21:06:57 +00:00
2009-01-02 17:01:55 +00:00
field = tr_bitfieldDup ( tr_cpPieceBitfield ( & msgs - > torrent - > completion ) ) ;
2008-08-16 21:06:57 +00:00
if ( tr_sessionIsLazyBitfieldEnabled ( msgs - > session ) )
{
2008-08-27 18:50:21 +00:00
/** Lazy bitfields aren't a high priority or secure, so I'm opting for
speed over a truly random sample - - let ' s limit the pool size to
the first 1000 pieces so large torrents don ' t bog things down */
2008-11-16 08:56:18 +00:00
size_t poolSize ;
const size_t maxPoolSize = MIN ( msgs - > torrent - > info . pieceCount , 1000 ) ;
tr_piece_index_t * pool = tr_new ( tr_piece_index_t , maxPoolSize ) ;
2008-08-27 18:50:21 +00:00
/* build the pool */
2008-11-16 08:56:18 +00:00
for ( i = poolSize = 0 ; i < maxPoolSize ; + + i )
if ( tr_bitfieldHas ( field , i ) )
pool [ poolSize + + ] = i ;
2008-08-27 18:50:21 +00:00
/* pull random piece indices from the pool */
while ( ( poolSize > 0 ) & & ( lazyCount < LAZY_PIECE_COUNT ) )
2008-08-16 21:06:57 +00:00
{
2008-11-16 08:56:18 +00:00
const int pos = tr_cryptoWeakRandInt ( poolSize ) ;
2008-08-27 18:50:21 +00:00
const tr_piece_index_t piece = pool [ pos ] ;
tr_bitfieldRem ( field , piece ) ;
lazyPieces [ lazyCount + + ] = piece ;
pool [ pos ] = pool [ - - poolSize ] ;
2008-08-16 21:06:57 +00:00
}
2008-08-27 18:50:21 +00:00
/* cleanup */
tr_free ( pool ) ;
2008-08-16 21:06:57 +00:00
}
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
tr_peerIoWriteUint32 ( msgs - > peer - > io , out ,
2008-09-23 19:11:04 +00:00
sizeof ( uint8_t ) + field - > byteCount ) ;
2008-12-12 02:44:21 +00:00
tr_peerIoWriteUint8 ( msgs - > peer - > io , out , BT_BITFIELD ) ;
2009-06-01 00:43:01 +00:00
/* FIXME(libevent2): use evbuffer_add_reference() */
2008-12-12 02:44:21 +00:00
tr_peerIoWriteBytes ( msgs - > peer - > io , out , field - > bits , field - > byteCount ) ;
2008-12-05 22:56:19 +00:00
dbgmsg ( msgs , " sending bitfield... outMessage size is now %zu " ,
EVBUFFER_LENGTH ( out ) ) ;
2008-05-31 00:16:26 +00:00
pokeBatchPeriod ( msgs , IMMEDIATE_PRIORITY_INTERVAL_SECS ) ;
2008-08-16 21:06:57 +00:00
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < lazyCount ; + + i )
2008-08-16 21:06:57 +00:00
protocolSendHave ( msgs , lazyPieces [ i ] ) ;
tr_bitfieldFree ( field ) ;
2007-09-20 16:32:01 +00:00
}
2008-12-02 17:10:54 +00:00
static void
tellPeerWhatWeHave ( tr_peermsgs * msgs )
{
2008-12-12 02:44:21 +00:00
const tr_bool fext = tr_peerIoSupportsFEXT ( msgs - > peer - > io ) ;
2008-12-02 17:10:54 +00:00
2009-01-02 17:01:55 +00:00
if ( fext & & ( tr_cpGetStatus ( & msgs - > torrent - > completion ) = = TR_SEED ) )
2008-12-02 17:10:54 +00:00
{
protocolSendHaveAll ( msgs ) ;
}
2009-01-02 17:01:55 +00:00
else if ( fext & & ( tr_cpHaveValid ( & msgs - > torrent - > completion ) = = 0 ) )
2008-12-02 17:10:54 +00:00
{
protocolSendHaveNone ( msgs ) ;
}
else
{
sendBitfield ( msgs ) ;
}
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2007-09-28 16:14:19 +00:00
/* some peers give us error messages if we send
2008-04-12 23:01:40 +00:00
more than this many peers in a single pex message
http : //wiki.theory.org/BitTorrentPeerExchangeConventions */
# define MAX_PEX_ADDED 50
# define MAX_PEX_DROPPED 50
2007-09-20 16:32:01 +00:00
typedef struct
{
2008-09-23 19:11:04 +00:00
tr_pex * added ;
tr_pex * dropped ;
tr_pex * elements ;
int addedCount ;
int droppedCount ;
int elementCount ;
2007-09-20 16:32:01 +00:00
}
PexDiffs ;
static void
2008-09-23 19:11:04 +00:00
pexAddedCb ( void * vpex ,
void * userData )
2007-09-20 16:32:01 +00:00
{
2008-04-12 23:01:40 +00:00
PexDiffs * diffs = userData ;
2008-09-23 19:11:04 +00:00
tr_pex * pex = vpex ;
2008-04-12 23:01:40 +00:00
if ( diffs - > addedCount < MAX_PEX_ADDED )
2007-09-20 16:32:01 +00:00
{
diffs - > added [ diffs - > addedCount + + ] = * pex ;
diffs - > elements [ diffs - > elementCount + + ] = * pex ;
}
}
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2008-09-23 19:11:04 +00:00
pexDroppedCb ( void * vpex ,
void * userData )
2007-09-20 16:32:01 +00:00
{
2008-04-12 23:01:40 +00:00
PexDiffs * diffs = userData ;
2008-09-23 19:11:04 +00:00
tr_pex * pex = vpex ;
2008-04-12 23:01:40 +00:00
if ( diffs - > droppedCount < MAX_PEX_DROPPED )
2007-09-20 16:32:01 +00:00
{
diffs - > dropped [ diffs - > droppedCount + + ] = * pex ;
}
}
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2008-09-23 19:11:04 +00:00
pexElementCb ( void * vpex ,
void * userData )
2007-09-20 16:32:01 +00:00
{
2008-04-12 23:01:40 +00:00
PexDiffs * diffs = userData ;
2009-01-02 06:28:22 +00:00
tr_pex * pex = vpex ;
2008-09-23 19:11:04 +00:00
2008-04-12 23:01:40 +00:00
diffs - > elements [ diffs - > elementCount + + ] = * pex ;
2007-09-20 16:32:01 +00:00
}
static void
sendPex ( tr_peermsgs * msgs )
{
2007-12-24 05:03:40 +00:00
if ( msgs - > peerSupportsPex & & tr_torrentAllowsPex ( msgs - > torrent ) )
2007-09-20 16:32:01 +00:00
{
2008-11-28 05:48:17 +00:00
PexDiffs diffs ;
2008-12-15 00:17:08 +00:00
PexDiffs diffs6 ;
2008-11-28 05:48:17 +00:00
tr_pex * newPex = NULL ;
2008-12-15 00:17:08 +00:00
tr_pex * newPex6 = NULL ;
2009-01-13 21:00:05 +00:00
const int newCount = tr_peerMgrGetPeers ( msgs - > torrent , & newPex , TR_AF_INET ) ;
const int newCount6 = tr_peerMgrGetPeers ( msgs - > torrent , & newPex6 , TR_AF_INET6 ) ;
2007-09-20 16:32:01 +00:00
/* build the diffs */
diffs . added = tr_new ( tr_pex , newCount ) ;
diffs . addedCount = 0 ;
diffs . dropped = tr_new ( tr_pex , msgs - > pexCount ) ;
diffs . droppedCount = 0 ;
diffs . elements = tr_new ( tr_pex , newCount + msgs - > pexCount ) ;
diffs . elementCount = 0 ;
tr_set_compare ( msgs - > pex , msgs - > pexCount ,
newPex , newCount ,
2008-09-23 19:11:04 +00:00
tr_pexCompare , sizeof ( tr_pex ) ,
2008-04-12 23:01:40 +00:00
pexDroppedCb , pexAddedCb , pexElementCb , & diffs ) ;
2008-12-15 00:17:08 +00:00
diffs6 . added = tr_new ( tr_pex , newCount6 ) ;
diffs6 . addedCount = 0 ;
diffs6 . dropped = tr_new ( tr_pex , msgs - > pexCount6 ) ;
diffs6 . droppedCount = 0 ;
diffs6 . elements = tr_new ( tr_pex , newCount6 + msgs - > pexCount6 ) ;
diffs6 . elementCount = 0 ;
tr_set_compare ( msgs - > pex6 , msgs - > pexCount6 ,
newPex6 , newCount6 ,
tr_pexCompare , sizeof ( tr_pex ) ,
pexDroppedCb , pexAddedCb , pexElementCb , & diffs6 ) ;
2008-09-23 19:11:04 +00:00
dbgmsg (
msgs ,
" pex: old peer count %d, new peer count %d, added %d, removed %d " ,
2008-12-15 00:17:08 +00:00
msgs - > pexCount , newCount + newCount6 ,
diffs . addedCount + diffs6 . addedCount ,
diffs . droppedCount + diffs6 . droppedCount ) ;
2007-09-20 16:32:01 +00:00
2008-12-15 00:17:08 +00:00
if ( ! diffs . addedCount & & ! diffs . droppedCount & & ! diffs6 . addedCount & &
! diffs6 . droppedCount )
2008-12-01 05:57:59 +00:00
{
tr_free ( diffs . elements ) ;
2008-12-15 00:17:08 +00:00
tr_free ( diffs6 . elements ) ;
2008-12-01 05:57:59 +00:00
}
else
2008-09-23 19:11:04 +00:00
{
2008-11-28 05:48:17 +00:00
int i ;
tr_benc val ;
char * benc ;
int bencLen ;
uint8_t * tmp , * walk ;
2009-01-22 04:20:30 +00:00
tr_peerIo * io = msgs - > peer - > io ;
2008-11-28 05:48:17 +00:00
struct evbuffer * out = msgs - > outMessages ;
/* update peer */
tr_free ( msgs - > pex ) ;
msgs - > pex = diffs . elements ;
msgs - > pexCount = diffs . elementCount ;
2008-12-15 00:17:08 +00:00
tr_free ( msgs - > pex6 ) ;
msgs - > pex6 = diffs6 . elements ;
msgs - > pexCount6 = diffs6 . elementCount ;
2008-11-28 05:48:17 +00:00
/* build the pex payload */
2008-12-15 00:17:08 +00:00
tr_bencInitDict ( & val , 3 ) ; /* ipv6 support: left as 3:
* speed vs . likelihood ? */
2008-11-28 05:48:17 +00:00
/* "added" */
tmp = walk = tr_new ( uint8_t , diffs . addedCount * 6 ) ;
2008-12-15 00:17:08 +00:00
for ( i = 0 ; i < diffs . addedCount ; + + i )
{
2008-12-02 03:41:58 +00:00
memcpy ( walk , & diffs . added [ i ] . addr . addr , 4 ) ; walk + = 4 ;
2008-11-28 05:48:17 +00:00
memcpy ( walk , & diffs . added [ i ] . port , 2 ) ; walk + = 2 ;
}
assert ( ( walk - tmp ) = = diffs . addedCount * 6 ) ;
tr_bencDictAddRaw ( & val , " added " , tmp , walk - tmp ) ;
tr_free ( tmp ) ;
/* "added.f" */
tmp = walk = tr_new ( uint8_t , diffs . addedCount ) ;
for ( i = 0 ; i < diffs . addedCount ; + + i )
* walk + + = diffs . added [ i ] . flags ;
assert ( ( walk - tmp ) = = diffs . addedCount ) ;
tr_bencDictAddRaw ( & val , " added.f " , tmp , walk - tmp ) ;
tr_free ( tmp ) ;
/* "dropped" */
tmp = walk = tr_new ( uint8_t , diffs . droppedCount * 6 ) ;
2008-12-15 00:17:08 +00:00
for ( i = 0 ; i < diffs . droppedCount ; + + i )
{
2008-12-02 03:41:58 +00:00
memcpy ( walk , & diffs . dropped [ i ] . addr . addr , 4 ) ; walk + = 4 ;
2008-11-28 05:48:17 +00:00
memcpy ( walk , & diffs . dropped [ i ] . port , 2 ) ; walk + = 2 ;
}
assert ( ( walk - tmp ) = = diffs . droppedCount * 6 ) ;
tr_bencDictAddRaw ( & val , " dropped " , tmp , walk - tmp ) ;
tr_free ( tmp ) ;
2008-12-15 00:17:08 +00:00
/* "added6" */
tmp = walk = tr_new ( uint8_t , diffs6 . addedCount * 18 ) ;
for ( i = 0 ; i < diffs6 . addedCount ; + + i )
{
memcpy ( walk , & diffs6 . added [ i ] . addr . addr . addr6 . s6_addr , 16 ) ;
walk + = 16 ;
memcpy ( walk , & diffs6 . added [ i ] . port , 2 ) ;
walk + = 2 ;
}
assert ( ( walk - tmp ) = = diffs6 . addedCount * 18 ) ;
tr_bencDictAddRaw ( & val , " added6 " , tmp , walk - tmp ) ;
tr_free ( tmp ) ;
/* "added6.f" */
tmp = walk = tr_new ( uint8_t , diffs6 . addedCount ) ;
for ( i = 0 ; i < diffs6 . addedCount ; + + i )
* walk + + = diffs6 . added [ i ] . flags ;
assert ( ( walk - tmp ) = = diffs6 . addedCount ) ;
tr_bencDictAddRaw ( & val , " added6.f " , tmp , walk - tmp ) ;
tr_free ( tmp ) ;
/* "dropped6" */
tmp = walk = tr_new ( uint8_t , diffs6 . droppedCount * 18 ) ;
for ( i = 0 ; i < diffs6 . droppedCount ; + + i )
{
memcpy ( walk , & diffs6 . dropped [ i ] . addr . addr . addr6 . s6_addr , 16 ) ;
walk + = 16 ;
memcpy ( walk , & diffs6 . dropped [ i ] . port , 2 ) ;
walk + = 2 ;
}
assert ( ( walk - tmp ) = = diffs6 . droppedCount * 18 ) ;
tr_bencDictAddRaw ( & val , " dropped6 " , tmp , walk - tmp ) ;
tr_free ( tmp ) ;
2008-11-28 05:48:17 +00:00
/* write the pex message */
2009-06-02 01:48:48 +00:00
benc = tr_bencToStr ( & val , TR_FMT_BENC , & bencLen ) ;
2009-01-22 04:20:30 +00:00
tr_peerIoWriteUint32 ( io , out , 2 * sizeof ( uint8_t ) + bencLen ) ;
tr_peerIoWriteUint8 ( io , out , BT_LTEP ) ;
tr_peerIoWriteUint8 ( io , out , msgs - > ut_pex_id ) ;
tr_peerIoWriteBytes ( io , out , benc , bencLen ) ;
2008-11-28 05:48:17 +00:00
pokeBatchPeriod ( msgs , HIGH_PRIORITY_INTERVAL_SECS ) ;
dbgmsg ( msgs , " sending a pex message; outMessage size is now %zu " , EVBUFFER_LENGTH ( out ) ) ;
2009-01-22 04:20:30 +00:00
dbgOutMessageLen ( msgs ) ;
2008-11-28 05:48:17 +00:00
tr_free ( benc ) ;
tr_bencFree ( & val ) ;
2007-09-20 16:32:01 +00:00
}
/* cleanup */
tr_free ( diffs . added ) ;
tr_free ( diffs . dropped ) ;
tr_free ( newPex ) ;
2008-12-15 00:17:08 +00:00
tr_free ( diffs6 . added ) ;
tr_free ( diffs6 . dropped ) ;
tr_free ( newPex6 ) ;
2007-09-20 16:32:01 +00:00
2009-06-03 04:56:53 +00:00
/*msgs->clientSentPexAt = time( NULL );*/
2007-09-20 16:32:01 +00:00
}
}
2009-01-11 17:02:04 +00:00
static TR_INLINE int
2007-09-20 16:32:01 +00:00
pexPulse ( void * vpeer )
{
sendPex ( vpeer ) ;
return TRUE ;
}
/**
* * *
* */
tr_peermsgs *
2007-10-03 04:04:34 +00:00
tr_peerMsgsNew ( struct tr_torrent * torrent ,
2008-12-22 00:52:44 +00:00
struct tr_peer * peer ,
2007-10-03 04:04:34 +00:00
tr_delivery_func func ,
2008-12-22 00:52:44 +00:00
void * userData ,
tr_publisher_tag * setme )
2007-09-20 16:32:01 +00:00
{
2007-10-03 04:04:34 +00:00
tr_peermsgs * m ;
2007-09-20 16:32:01 +00:00
2008-12-02 19:06:08 +00:00
assert ( peer ) ;
assert ( peer - > io ) ;
2007-09-20 16:32:01 +00:00
2007-10-03 04:04:34 +00:00
m = tr_new0 ( tr_peermsgs , 1 ) ;
2008-12-29 18:10:07 +00:00
m - > publisher = TR_PUBLISHER_INIT ;
2008-12-12 02:44:21 +00:00
m - > peer = peer ;
2008-10-02 15:53:33 +00:00
m - > session = torrent - > session ;
2007-10-03 04:04:34 +00:00
m - > torrent = torrent ;
2008-12-12 02:44:21 +00:00
m - > peer - > clientIsChoked = 1 ;
m - > peer - > peerIsChoked = 1 ;
m - > peer - > clientIsInterested = 0 ;
m - > peer - > peerIsInterested = 0 ;
m - > peer - > have = tr_bitfieldNew ( torrent - > info . pieceCount ) ;
2009-01-02 23:28:57 +00:00
m - > state = AWAITING_BT_LENGTH ;
2008-08-16 21:06:57 +00:00
m - > pexTimer = tr_timerNew ( m - > session , pexPulse , m , PEX_INTERVAL ) ;
2007-10-03 04:04:34 +00:00
m - > outMessages = evbuffer_new ( ) ;
2008-05-31 00:16:26 +00:00
m - > outMessagesBatchedAt = 0 ;
m - > outMessagesBatchPeriod = LOW_PRIORITY_INTERVAL_SECS ;
2007-11-16 20:40:03 +00:00
m - > incoming . block = evbuffer_new ( ) ;
2008-02-29 03:41:50 +00:00
m - > peerAskedFor = REQUEST_LIST_INIT ;
m - > clientAskedFor = REQUEST_LIST_INIT ;
m - > clientWillAskFor = REQUEST_LIST_INIT ;
2008-12-02 19:06:08 +00:00
peer - > msgs = m ;
2008-12-29 18:10:07 +00:00
* setme = tr_publisherSubscribe ( & m - > publisher , func , userData ) ;
2007-09-20 16:32:01 +00:00
2008-12-12 02:44:21 +00:00
if ( tr_peerIoSupportsLTEP ( peer - > io ) )
2007-10-22 23:27:47 +00:00
sendLtepHandshake ( m ) ;
2008-04-18 00:02:04 +00:00
2009-05-19 18:38:26 +00:00
if ( tr_peerIoSupportsDHT ( peer - > io ) )
protocolSendPort ( m , tr_dhtPort ( torrent - > session ) ) ;
2008-12-02 17:10:54 +00:00
tellPeerWhatWeHave ( m ) ;
2008-09-23 19:11:04 +00:00
2008-12-12 02:44:21 +00:00
tr_peerIoSetIOFuncs ( m - > peer - > io , canRead , didWrite , gotError , m ) ;
2009-01-05 04:27:54 +00:00
ratePulse ( m , tr_date ( ) ) ;
2007-10-22 23:27:47 +00:00
2007-10-03 04:04:34 +00:00
return m ;
2007-09-20 16:32:01 +00:00
}
void
2007-09-24 17:47:15 +00:00
tr_peerMsgsFree ( tr_peermsgs * msgs )
2007-09-20 16:32:01 +00:00
{
2008-08-01 16:43:22 +00:00
if ( msgs )
2007-09-20 16:32:01 +00:00
{
2007-09-24 17:47:15 +00:00
tr_timerFree ( & msgs - > pexTimer ) ;
2008-12-29 18:10:07 +00:00
tr_publisherDestruct ( & msgs - > publisher ) ;
2008-02-29 03:41:50 +00:00
reqListClear ( & msgs - > clientWillAskFor ) ;
reqListClear ( & msgs - > clientAskedFor ) ;
2008-12-01 05:56:39 +00:00
reqListClear ( & msgs - > peerAskedFor ) ;
2008-11-29 20:37:34 +00:00
2007-11-16 20:40:03 +00:00
evbuffer_free ( msgs - > incoming . block ) ;
2007-09-24 17:47:15 +00:00
evbuffer_free ( msgs - > outMessages ) ;
2008-12-15 00:17:08 +00:00
tr_free ( msgs - > pex6 ) ;
2007-09-24 17:47:15 +00:00
tr_free ( msgs - > pex ) ;
2007-11-17 07:48:51 +00:00
memset ( msgs , ~ 0 , sizeof ( tr_peermsgs ) ) ;
2007-09-24 17:47:15 +00:00
tr_free ( msgs ) ;
2007-09-20 16:32:01 +00:00
}
}
void
2008-09-23 19:11:04 +00:00
tr_peerMsgsUnsubscribe ( tr_peermsgs * peer ,
tr_publisher_tag tag )
2007-09-20 16:32:01 +00:00
{
2008-12-29 18:10:07 +00:00
tr_publisherUnsubscribe ( & peer - > publisher , tag ) ;
2007-09-20 16:32:01 +00:00
}
2008-09-23 19:11:04 +00:00