2007-09-20 16:32:01 +00:00
/*
2011-01-19 13:48:47 +00:00
* This file Copyright ( C ) Mnemosyne LLC
2007-09-20 16:32:01 +00:00
*
2010-12-27 19:18:17 +00:00
* This file is licensed by the GPL version 2. Works owned by the
2012-12-05 17:29:46 +00:00
* 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>
2010-06-25 20:36:10 +00:00
# include <errno.h> /* error codes ERANGE, ... */
2010-06-27 01:24:48 +00:00
# include <limits.h> /* INT_MAX */
2007-11-25 16:57:08 +00:00
# include <string.h> /* memcpy, memcmp, strstr */
2007-09-20 16:32:01 +00:00
# include <stdlib.h> /* qsort */
2010-12-24 08:58:41 +00:00
# include <event2/event.h>
2007-10-02 14:35:02 +00:00
2012-05-30 17:47:29 +00:00
# include <libutp/utp.h>
2007-09-20 16:32:01 +00:00
# include "transmission.h"
2009-12-02 05:30:46 +00:00
# include "announcer.h"
2008-11-24 04:21:23 +00:00
# include "bandwidth.h"
2008-03-29 21:05:51 +00:00
# include "blocklist.h"
2010-06-19 14:25:11 +00:00
# include "cache.h"
2007-09-20 16:32:01 +00:00
# include "clients.h"
# include "completion.h"
2007-09-28 16:40:21 +00:00
# include "crypto.h"
2007-09-20 16:32:01 +00:00
# include "handshake.h"
2013-01-25 23:34:20 +00:00
# include "log.h"
2007-09-20 16:32:01 +00:00
# include "net.h"
# include "peer-io.h"
# include "peer-mgr.h"
# include "peer-msgs.h"
# include "ptrarray.h"
2009-07-01 14:58:57 +00:00
# include "session.h"
2008-11-04 21:33:24 +00:00
# include "stats.h" /* tr_statsAddUploaded, tr_statsAddDownloaded */
2007-12-25 05:37:32 +00:00
# include "torrent.h"
2011-10-08 23:53:27 +00:00
# include "tr-utp.h"
2007-09-20 16:32:01 +00:00
# include "utils.h"
2008-06-07 21:26:41 +00:00
# include "webseed.h"
2007-09-20 16:32:01 +00:00
2007-09-22 14:18:52 +00:00
enum
{
2013-01-24 23:59:52 +00:00
/* how frequently to cull old atoms */
ATOM_PERIOD_MSEC = ( 60 * 1000 ) ,
2009-11-26 05:13:58 +00:00
2013-01-24 23:59:52 +00:00
/* how frequently to change which peers are choked */
RECHOKE_PERIOD_MSEC = ( 10 * 1000 ) ,
2007-09-22 14:18:52 +00:00
2013-01-24 23:59:52 +00:00
/* an optimistically unchoked peer is immune from rechoking
for this many calls to rechokeUploads ( ) . */
OPTIMISTIC_UNCHOKE_MULTIPLIER = 4 ,
2010-10-13 03:56:25 +00:00
2013-01-24 23:59:52 +00:00
/* how frequently to reallocate bandwidth */
BANDWIDTH_PERIOD_MSEC = 500 ,
2009-02-04 16:58:52 +00:00
2013-01-24 23:59:52 +00:00
/* how frequently to age out old piece request lists */
REFILL_UPKEEP_PERIOD_MSEC = ( 10 * 1000 ) ,
2009-02-18 17:19:36 +00:00
2013-01-24 23:59:52 +00:00
/* how frequently to decide which peers live and die */
RECONNECT_PERIOD_MSEC = 500 ,
2007-09-22 00:22:10 +00:00
2013-01-24 23:59:52 +00:00
/* when many peers are available, keep idle ones this long */
MIN_UPLOAD_IDLE_SECS = ( 60 ) ,
2007-10-13 13:54:05 +00:00
2013-01-24 23:59:52 +00:00
/* when few peers are available, keep idle ones this long */
MAX_UPLOAD_IDLE_SECS = ( 60 * 5 ) ,
2007-10-13 13:54:05 +00:00
2013-01-24 23:59:52 +00:00
/* max number of peers to ask for per second overall.
* this throttle is to avoid overloading the router */
MAX_CONNECTIONS_PER_SECOND = 12 ,
2008-01-11 18:13:09 +00:00
2013-01-24 23:59:52 +00:00
MAX_CONNECTIONS_PER_PULSE = ( int ) ( MAX_CONNECTIONS_PER_SECOND * ( RECONNECT_PERIOD_MSEC / 1000.0 ) ) ,
2010-04-20 21:54:03 +00:00
2013-01-24 23:59:52 +00:00
/* number of bad pieces a peer is allowed to send before we ban them */
MAX_BAD_PIECES_PER_PEER = 5 ,
2007-12-15 04:26:31 +00:00
2013-01-24 23:59:52 +00:00
/* amount of time to keep a list of request pieces lying around
before it ' s considered too old and needs to be rebuilt */
PIECE_LIST_SHELF_LIFE_SECS = 60 ,
2009-02-18 17:19:36 +00:00
2013-01-24 23:59:52 +00:00
/* use for bitwise operations w/peer_atom.flags2 */
MYFLAG_BANNED = 1 ,
2007-12-15 04:26:31 +00:00
2013-01-24 23:59:52 +00:00
/* use for bitwise operations w/peer_atom.flags2 */
/* unreachable for now... but not banned.
* if they try to connect to us it ' s okay */
MYFLAG_UNREACHABLE = 2 ,
2008-09-05 05:14:49 +00:00
2013-01-24 23:59:52 +00:00
/* the minimum we'll wait before attempting to reconnect to a peer */
MINIMUM_RECONNECT_INTERVAL_SECS = 5 ,
2009-12-16 18:20:01 +00:00
2013-01-24 23:59:52 +00:00
/** how long we'll let requests we've made linger before we cancel them */
REQUEST_TTL_SECS = 90 ,
2010-03-08 04:29:58 +00:00
2013-01-24 23:59:52 +00:00
NO_BLOCKS_CANCEL_HISTORY = 120 ,
2010-11-16 15:17:34 +00:00
2013-01-24 23:59:52 +00:00
CANCEL_HISTORY_SEC = 60
2009-11-01 02:10:47 +00:00
} ;
2007-10-01 16:31:17 +00:00
2013-01-30 18:00:03 +00:00
const tr_peer_event TR_PEER_EVENT_INIT = { 0 , 0 , NULL , 0 , 0 , 0 , 0 } ;
2009-11-02 00:17:30 +00:00
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2008-12-11 17:02:34 +00:00
/**
* Peer information that should be kept even before we ' ve connected and
2010-12-27 19:18:17 +00:00
* after we ' ve disconnected . These are kept in a pool of peer_atoms to decide
2008-12-11 17:02:34 +00:00
* which ones would make good candidates for connecting to , and to watch out
* for banned peers .
*
* @ see tr_peer
2013-02-04 16:23:33 +00:00
* @ see tr_peerMsgs
2008-12-11 17:02:34 +00:00
*/
2007-09-30 23:55:49 +00:00
struct peer_atom
2008-09-23 19:11:04 +00:00
{
2013-01-24 23:59:52 +00:00
uint8_t fromFirst ; /* where the peer was first found */
uint8_t fromBest ; /* the "best" value of where the peer has been found */
uint8_t flags ; /* these match the added_f flags */
uint8_t flags2 ; /* flags that aren't defined in added_f */
int8_t seedProbability ; /* how likely is this to be a seed... [0..100] or -1 for unknown */
int8_t blocklisted ; /* -1 for unknown, true for blocklisted, false for not blocklisted */
tr_port port ;
bool utp_failed ; /* We recently failed to connect over uTP */
uint16_t numFails ;
time_t time ; /* when the peer's connection status last changed */
time_t piece_data_time ;
time_t lastConnectionAttemptAt ;
time_t lastConnectionAt ;
/* similar to a TTL field, but less rigid --
* if the swarm is small , the atom will be kept past this date . */
time_t shelf_date ;
tr_peer * peer ; /* will be NULL if not connected */
tr_address addr ;
2007-09-30 23:55:49 +00:00
} ;
2009-12-28 23:27:17 +00:00
# ifdef NDEBUG
# define tr_isAtom(a) (TRUE)
# else
2011-03-22 15:19:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
tr_isAtom ( const struct peer_atom * atom )
2009-09-10 03:28:55 +00:00
{
2013-01-24 23:59:52 +00:00
return ( atom ! = NULL )
& & ( atom - > fromFirst < TR_PEER_FROM__MAX )
& & ( atom - > fromBest < TR_PEER_FROM__MAX )
& & ( tr_address_is_valid ( & atom - > addr ) ) ;
2009-09-10 03:28:55 +00:00
}
2009-12-28 23:27:17 +00:00
# endif
2009-09-10 03:28:55 +00:00
2009-10-29 16:10:03 +00:00
static const char *
2012-12-05 17:29:46 +00:00
tr_atomAddrStr ( const struct peer_atom * atom )
2009-10-29 16:10:03 +00:00
{
2013-01-24 23:59:52 +00:00
return atom ? tr_peerIoAddrStr ( & atom - > addr , atom - > port ) : " [no atom] " ;
2009-10-29 16:10:03 +00:00
}
2009-11-08 23:20:00 +00:00
struct block_request
2009-02-18 17:19:36 +00:00
{
2013-01-24 23:59:52 +00:00
tr_block_index_t block ;
tr_peer * peer ;
time_t sentAt ;
2009-11-08 23:20:00 +00:00
} ;
struct weighted_piece
{
2013-01-24 23:59:52 +00:00
tr_piece_index_t index ;
int16_t salt ;
int16_t requestCount ;
2009-02-18 17:19:36 +00:00
} ;
2011-02-17 05:14:53 +00:00
enum piece_sort_state
{
2013-01-24 23:59:52 +00:00
PIECES_UNSORTED ,
PIECES_SORTED_BY_INDEX ,
PIECES_SORTED_BY_WEIGHT
2011-02-17 05:14:53 +00:00
} ;
2010-01-19 19:37:00 +00:00
/** @brief Opaque, per-torrent data structure for peer connection information */
2013-01-27 21:03:52 +00:00
typedef struct tr_swarm
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
tr_ptrArray outgoingHandshakes ; /* tr_handshake */
tr_ptrArray pool ; /* struct peer_atom */
2013-02-04 16:23:33 +00:00
tr_ptrArray peers ; /* tr_peerMsgs */
2013-01-24 23:59:52 +00:00
tr_ptrArray webseeds ; /* tr_webseed */
2009-06-24 03:54:11 +00:00
2013-01-24 23:59:52 +00:00
tr_torrent * tor ;
struct tr_peerMgr * manager ;
2009-06-24 03:54:11 +00:00
2013-02-04 16:23:33 +00:00
tr_peerMsgs * optimistic ; /* the optimistic peer, or NULL if none */
2013-01-24 23:59:52 +00:00
int optimisticUnchokeTimeScaler ;
2010-10-13 03:56:25 +00:00
2013-01-24 23:59:52 +00:00
bool isRunning ;
bool needsCompletenessCheck ;
2009-11-08 23:20:00 +00:00
2013-01-24 23:59:52 +00:00
struct block_request * requests ;
int requestCount ;
int requestAlloc ;
2009-11-08 23:20:00 +00:00
2013-01-24 23:59:52 +00:00
struct weighted_piece * pieces ;
int pieceCount ;
enum piece_sort_state pieceSortState ;
2011-02-17 05:14:53 +00:00
2013-01-24 23:59:52 +00:00
/* An array of pieceCount items stating how many peers have each piece.
This is used to help us for downloading pieces " rarest first. "
This may be NULL if we don ' t have metainfo yet , or if we ' re not
downloading and don ' t care about rarity */
uint16_t * pieceReplication ;
size_t pieceReplicationSize ;
2010-03-08 04:29:58 +00:00
2013-01-24 23:59:52 +00:00
int interestedCount ;
int maxPeers ;
time_t lastCancel ;
2011-02-15 16:04:56 +00:00
2013-01-24 23:59:52 +00:00
/* Before the endgame this should be 0. In endgame, is contains the average
* number of pending requests per peer . Only peers which have more pending
* requests are considered ' fast ' are allowed to request a block that ' s
* already been requested from another ( slower ? ) peer . */
int endgame ;
2007-09-20 16:32:01 +00:00
}
2013-01-27 21:03:52 +00:00
tr_swarm ;
2007-09-20 16:32:01 +00:00
struct tr_peerMgr
{
2013-01-24 23:59:52 +00:00
tr_session * session ;
tr_ptrArray incomingHandshakes ; /* tr_handshake */
struct event * bandwidthTimer ;
struct event * rechokeTimer ;
struct event * refillUpkeepTimer ;
struct event * atomTimer ;
2007-09-20 16:32:01 +00:00
} ;
2012-12-05 17:29:46 +00:00
# define tordbg(t, ...) \
do \
{ \
2013-01-25 23:34:20 +00:00
if ( tr_logGetDeepEnabled ( ) ) \
tr_logAddDeep ( __FILE__ , __LINE__ , tr_torrentName ( t - > tor ) , __VA_ARGS__ ) ; \
2012-12-05 17:29:46 +00:00
} \
while ( 0 )
# define dbgmsg(...) \
do \
{ \
2013-01-25 23:34:20 +00:00
if ( tr_logGetDeepEnabled ( ) ) \
tr_logAddDeep ( __FILE__ , __LINE__ , NULL , __VA_ARGS__ ) ; \
2012-12-05 17:29:46 +00:00
} \
while ( 0 )
2007-10-02 14:35:02 +00:00
2013-02-04 16:23:33 +00:00
/**
* * * tr_peer virtual functions
* */
static bool
tr_peerIsTransferringPieces ( const tr_peer * peer ,
uint64_t now ,
tr_direction direction ,
unsigned int * Bps )
{
assert ( peer ! = NULL ) ;
assert ( peer - > funcs ! = NULL ) ;
return ( * peer - > funcs - > is_transferring_pieces ) ( peer , now , direction , Bps ) ;
}
unsigned int
tr_peerGetPieceSpeed_Bps ( const tr_peer * peer ,
uint64_t now ,
tr_direction direction )
{
unsigned int Bps = 0 ;
tr_peerIsTransferringPieces ( peer , now , direction , & Bps ) ;
return Bps ;
}
static void
tr_peerFree ( tr_peer * peer )
{
assert ( peer ! = NULL ) ;
assert ( peer - > funcs ! = NULL ) ;
( * peer - > funcs - > destruct ) ( peer ) ;
tr_free ( peer ) ;
}
void
tr_peerConstruct ( tr_peer * peer , const tr_torrent * tor )
{
assert ( peer ! = NULL ) ;
assert ( tr_isTorrent ( tor ) ) ;
memset ( peer , 0 , sizeof ( tr_peer ) ) ;
peer - > client = TR_KEY_NONE ;
peer - > swarm = tor - > swarm ;
tr_bitfieldConstruct ( & peer - > have , tor - > info . pieceCount ) ;
tr_bitfieldConstruct ( & peer - > blame , tor - > blockCount ) ;
}
static void peerDeclinedAllRequests ( tr_swarm * , const tr_peer * ) ;
void
tr_peerDestruct ( tr_peer * peer )
{
assert ( peer ! = NULL ) ;
if ( peer - > swarm ! = NULL )
peerDeclinedAllRequests ( peer - > swarm , peer ) ;
tr_bitfieldDestruct ( & peer - > have ) ;
tr_bitfieldDestruct ( & peer - > blame ) ;
if ( peer - > atom )
peer - > atom - > peer = NULL ;
}
2007-10-02 14:35:02 +00:00
/**
* * *
* */
2010-01-01 22:26:35 +00:00
static inline void
2012-12-05 17:29:46 +00:00
managerLock ( const struct tr_peerMgr * manager )
2007-09-29 06:37:03 +00:00
{
2013-01-24 23:59:52 +00:00
tr_sessionLock ( manager - > session ) ;
2007-09-29 06:37:03 +00:00
}
2008-09-23 19:11:04 +00:00
2010-01-01 22:26:35 +00:00
static inline void
2012-12-05 17:29:46 +00:00
managerUnlock ( const struct tr_peerMgr * manager )
2007-09-29 06:37:03 +00:00
{
2013-01-24 23:59:52 +00:00
tr_sessionUnlock ( manager - > session ) ;
2007-09-29 06:37:03 +00:00
}
2008-09-23 19:11:04 +00:00
2010-01-01 22:26:35 +00:00
static inline void
2013-01-27 21:03:52 +00:00
swarmLock ( tr_swarm * swarm )
2007-09-29 06:37:03 +00:00
{
2013-01-27 21:03:52 +00:00
managerLock ( swarm - > manager ) ;
2007-09-29 06:37:03 +00:00
}
2008-09-23 19:11:04 +00:00
2010-01-01 22:26:35 +00:00
static inline void
2013-01-27 21:03:52 +00:00
swarmUnlock ( tr_swarm * swarm )
2007-09-29 06:37:03 +00:00
{
2013-01-27 21:03:52 +00:00
managerUnlock ( swarm - > manager ) ;
2007-09-29 06:37:03 +00:00
}
2008-09-23 19:11:04 +00:00
2010-01-01 22:26:35 +00:00
static inline int
2013-01-27 21:03:52 +00:00
swarmIsLocked ( const tr_swarm * swarm )
2007-09-29 06:37:03 +00:00
{
2013-01-27 21:03:52 +00:00
return tr_sessionIsLocked ( swarm - > manager - > session ) ;
2007-09-29 06:37:03 +00:00
}
/**
* * *
* */
2007-09-20 16:32:01 +00:00
static int
2012-12-05 17:29:46 +00:00
handshakeCompareToAddr ( const void * va , const void * vb )
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
const tr_handshake * a = va ;
2008-09-23 19:11:04 +00:00
2013-01-24 23:59:52 +00:00
return tr_address_compare ( tr_handshakeGetAddr ( a , NULL ) , vb ) ;
2007-09-20 16:32:01 +00:00
}
static int
2012-12-05 17:29:46 +00:00
handshakeCompare ( const void * a , const void * b )
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
return handshakeCompareToAddr ( a , tr_handshakeGetAddr ( b , NULL ) ) ;
2007-09-20 16:32:01 +00:00
}
2010-06-14 11:57:46 +00:00
static inline tr_handshake *
2012-12-05 17:29:46 +00:00
getExistingHandshake ( tr_ptrArray * handshakes , const tr_address * addr )
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
if ( tr_ptrArrayEmpty ( handshakes ) )
return NULL ;
2010-06-14 11:57:46 +00:00
2013-01-24 23:59:52 +00:00
return tr_ptrArrayFindSorted ( handshakes , addr , handshakeCompareToAddr ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-30 23:55:49 +00:00
static int
2012-12-05 17:29:46 +00:00
comparePeerAtomToAddress ( const void * va , const void * vb )
2007-09-30 23:55:49 +00:00
{
2013-01-24 23:59:52 +00:00
const struct peer_atom * a = va ;
2008-09-23 19:11:04 +00:00
2013-01-24 23:59:52 +00:00
return tr_address_compare ( & a - > addr , vb ) ;
2007-09-30 23:55:49 +00:00
}
static int
2012-12-05 17:29:46 +00:00
compareAtomsByAddress ( const void * va , const void * vb )
2007-09-30 23:55:49 +00:00
{
2013-01-24 23:59:52 +00:00
const struct peer_atom * b = vb ;
2008-09-23 19:11:04 +00:00
2013-01-24 23:59:52 +00:00
assert ( tr_isAtom ( b ) ) ;
2009-09-10 03:07:54 +00:00
2013-01-24 23:59:52 +00:00
return comparePeerAtomToAddress ( va , & b - > addr ) ;
2007-09-30 23:55:49 +00:00
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2009-10-29 16:10:03 +00:00
const tr_address *
2012-12-05 17:29:46 +00:00
tr_peerAddress ( const tr_peer * peer )
2009-10-29 16:10:03 +00:00
{
2013-01-24 23:59:52 +00:00
return & peer - > atom - > addr ;
2009-10-29 16:10:03 +00:00
}
2013-01-27 21:03:52 +00:00
static tr_swarm *
getExistingSwarm ( tr_peerMgr * manager ,
const uint8_t * hash )
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
tr_torrent * tor = tr_torrentFindFromHash ( manager - > session , hash ) ;
2009-01-13 21:00:05 +00:00
2013-01-27 21:03:52 +00:00
return tor = = NULL ? NULL : tor - > swarm ;
2007-09-20 16:32:01 +00:00
}
static int
2012-12-05 17:29:46 +00:00
peerCompare ( const void * a , const void * b )
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
return tr_address_compare ( tr_peerAddress ( a ) , tr_peerAddress ( b ) ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-30 23:55:49 +00:00
static struct peer_atom *
2013-01-27 21:03:52 +00:00
getExistingAtom ( const tr_swarm * cswarm ,
2012-12-05 17:29:46 +00:00
const tr_address * addr )
2007-09-30 23:55:49 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * swarm = ( tr_swarm * ) cswarm ;
return tr_ptrArrayFindSorted ( & swarm - > pool , addr , comparePeerAtomToAddress ) ;
2007-09-30 23:55:49 +00:00
}
2011-03-22 15:19:54 +00:00
static bool
2013-01-27 21:03:52 +00:00
peerIsInUse ( const tr_swarm * cs , const struct peer_atom * atom )
2007-09-30 23:55:49 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s = ( tr_swarm * ) cs ;
2007-10-02 16:12:44 +00:00
2013-01-27 21:03:52 +00:00
assert ( swarmIsLocked ( s ) ) ;
2007-09-30 23:55:49 +00:00
2013-01-24 23:59:52 +00:00
return ( atom - > peer ! = NULL )
2013-01-27 21:03:52 +00:00
| | getExistingHandshake ( & s - > outgoingHandshakes , & atom - > addr )
| | getExistingHandshake ( & s - > manager - > incomingHandshakes , & atom - > addr ) ;
2007-10-03 16:42:43 +00:00
}
2013-01-27 21:03:52 +00:00
static inline bool
replicationExists ( const tr_swarm * s )
2007-09-30 23:55:49 +00:00
{
2013-01-27 21:03:52 +00:00
return s - > pieceReplication ! = NULL ;
2011-02-17 05:14:53 +00:00
}
2007-09-30 23:55:49 +00:00
2011-02-17 05:14:53 +00:00
static void
2013-01-27 21:03:52 +00:00
replicationFree ( tr_swarm * s )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
tr_free ( s - > pieceReplication ) ;
s - > pieceReplication = NULL ;
s - > pieceReplicationSize = 0 ;
2007-09-30 23:55:49 +00:00
}
2007-10-01 16:50:51 +00:00
static void
2013-01-27 21:03:52 +00:00
replicationNew ( tr_swarm * s )
2007-10-01 16:50:51 +00:00
{
2013-01-24 23:59:52 +00:00
tr_piece_index_t piece_i ;
2013-01-27 21:03:52 +00:00
const tr_piece_index_t piece_count = s - > tor - > info . pieceCount ;
2013-02-04 16:23:33 +00:00
const int n = tr_ptrArraySize ( & s - > peers ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
assert ( ! replicationExists ( s ) ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
s - > pieceReplicationSize = piece_count ;
s - > pieceReplication = tr_new0 ( uint16_t , piece_count ) ;
2011-02-17 05:14:53 +00:00
2013-01-24 23:59:52 +00:00
for ( piece_i = 0 ; piece_i < piece_count ; + + piece_i )
2011-02-17 05:14:53 +00:00
{
2013-01-24 23:59:52 +00:00
int peer_i ;
uint16_t r = 0 ;
2011-02-17 05:14:53 +00:00
2013-02-04 16:23:33 +00:00
for ( peer_i = 0 ; peer_i < n ; + + peer_i )
{
tr_peer * peer = tr_ptrArrayNth ( & s - > peers , peer_i ) ;
if ( tr_bitfieldHas ( & peer - > have , piece_i ) )
+ + r ;
}
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
s - > pieceReplication [ piece_i ] = r ;
2011-02-17 05:14:53 +00:00
}
2007-10-01 16:50:51 +00:00
}
2013-05-27 21:04:48 +00:00
static void
resetTorrentStats ( tr_torrent * tor )
{
int i ;
tor - > peerCount = 0 ;
tor - > activePeerCount [ TR_UP ] = 0 ;
tor - > activePeerCount [ TR_DOWN ] = 0 ;
tor - > activeWebseedCount = 0 ;
for ( i = 0 ; i < TR_PEER_FROM__MAX ; i + + )
tor - > peerFromCount [ i ] = 0 ;
}
2007-09-20 16:32:01 +00:00
static void
2013-01-27 21:03:52 +00:00
swarmFree ( void * vs )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s = vs ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
assert ( s ) ;
assert ( ! s - > isRunning ) ;
assert ( swarmIsLocked ( s ) ) ;
assert ( tr_ptrArrayEmpty ( & s - > outgoingHandshakes ) ) ;
assert ( tr_ptrArrayEmpty ( & s - > peers ) ) ;
2007-09-20 16:32:01 +00:00
2013-02-04 16:23:33 +00:00
tr_ptrArrayDestruct ( & s - > webseeds , ( PtrArrayForeachFunc ) tr_peerFree ) ;
2013-01-27 21:03:52 +00:00
tr_ptrArrayDestruct ( & s - > pool , ( PtrArrayForeachFunc ) tr_free ) ;
tr_ptrArrayDestruct ( & s - > outgoingHandshakes , NULL ) ;
tr_ptrArrayDestruct ( & s - > peers , NULL ) ;
2013-05-27 21:04:48 +00:00
resetTorrentStats ( s - > tor ) ;
2007-10-02 16:12:44 +00:00
2013-01-27 21:03:52 +00:00
replicationFree ( s ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
tr_free ( s - > requests ) ;
tr_free ( s - > pieces ) ;
tr_free ( s ) ;
2007-09-20 16:32:01 +00:00
}
2012-12-05 17:29:46 +00:00
static void peerCallbackFunc ( tr_peer * , const tr_peer_event * , void * ) ;
2008-06-07 21:26:41 +00:00
2012-10-05 22:04:08 +00:00
static void
2013-01-27 21:03:52 +00:00
rebuildWebseedArray ( tr_swarm * s , tr_torrent * tor )
2012-10-05 22:04:08 +00:00
{
2013-01-24 23:59:52 +00:00
unsigned int i ;
const tr_info * inf = & tor - > info ;
2012-10-05 22:04:08 +00:00
2013-01-24 23:59:52 +00:00
/* clear the array */
2013-02-04 16:23:33 +00:00
tr_ptrArrayDestruct ( & s - > webseeds , ( PtrArrayForeachFunc ) tr_peerFree ) ;
2013-01-27 21:03:52 +00:00
s - > webseeds = TR_PTR_ARRAY_INIT ;
2013-05-27 21:04:48 +00:00
s - > tor - > activeWebseedCount = 0 ;
2012-10-05 22:04:08 +00:00
2013-01-24 23:59:52 +00:00
/* repopulate it */
2013-02-04 16:23:33 +00:00
for ( i = 0 ; i < inf - > webseedCount ; + + i )
2012-10-05 22:04:08 +00:00
{
2013-01-27 21:03:52 +00:00
tr_webseed * w = tr_webseedNew ( tor , inf - > webseeds [ i ] , peerCallbackFunc , s ) ;
tr_ptrArrayAppend ( & s - > webseeds , w ) ;
2012-10-05 22:04:08 +00:00
}
}
2013-01-27 21:03:52 +00:00
static tr_swarm *
swarmNew ( tr_peerMgr * manager , tr_torrent * tor )
2007-10-02 16:12:44 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s ;
2007-10-02 16:12:44 +00:00
2013-01-27 21:03:52 +00:00
s = tr_new0 ( tr_swarm , 1 ) ;
s - > manager = manager ;
s - > tor = tor ;
s - > pool = TR_PTR_ARRAY_INIT ;
s - > peers = TR_PTR_ARRAY_INIT ;
s - > webseeds = TR_PTR_ARRAY_INIT ;
s - > outgoingHandshakes = TR_PTR_ARRAY_INIT ;
2007-10-02 16:12:44 +00:00
2013-01-27 21:03:52 +00:00
rebuildWebseedArray ( s , tor ) ;
2008-06-07 21:26:41 +00:00
2013-01-27 21:03:52 +00:00
return s ;
2007-10-02 16:12:44 +00:00
}
2012-12-05 17:29:46 +00:00
static void ensureMgrTimersExist ( struct tr_peerMgr * m ) ;
2011-08-01 22:24:24 +00:00
2007-09-20 16:32:01 +00:00
tr_peerMgr *
2012-12-05 17:29:46 +00:00
tr_peerMgrNew ( tr_session * session )
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
tr_peerMgr * m = tr_new0 ( tr_peerMgr , 1 ) ;
m - > session = session ;
m - > incomingHandshakes = TR_PTR_ARRAY_INIT ;
ensureMgrTimersExist ( m ) ;
return m ;
2009-05-13 20:54:35 +00:00
}
2009-02-04 16:58:52 +00:00
2009-05-13 20:54:35 +00:00
static void
2012-12-05 17:29:46 +00:00
deleteTimer ( struct event * * t )
2009-05-13 20:54:35 +00:00
{
2013-01-24 23:59:52 +00:00
if ( * t ! = NULL )
2009-12-10 05:52:46 +00:00
{
2013-01-24 23:59:52 +00:00
event_free ( * t ) ;
* t = NULL ;
2009-12-10 05:52:46 +00:00
}
}
2009-11-02 00:17:30 +00:00
2009-12-10 05:52:46 +00:00
static void
2012-12-05 17:29:46 +00:00
deleteTimers ( struct tr_peerMgr * m )
2009-12-10 05:52:46 +00:00
{
2013-01-24 23:59:52 +00:00
deleteTimer ( & m - > atomTimer ) ;
deleteTimer ( & m - > bandwidthTimer ) ;
deleteTimer ( & m - > rechokeTimer ) ;
deleteTimer ( & m - > refillUpkeepTimer ) ;
2007-09-20 16:32:01 +00:00
}
void
2012-12-05 17:29:46 +00:00
tr_peerMgrFree ( tr_peerMgr * manager )
2007-09-20 16:32:01 +00:00
{
2013-01-24 23:59:52 +00:00
managerLock ( manager ) ;
2007-09-29 06:37:03 +00:00
2013-01-24 23:59:52 +00:00
deleteTimers ( manager ) ;
2008-09-17 19:44:24 +00:00
2013-01-24 23:59:52 +00:00
/* free the handshakes. Abort invokes handshakeDoneCB (), which removes
* the item from manager - > handshakes , so this is a little roundabout . . . */
while ( ! tr_ptrArrayEmpty ( & manager - > incomingHandshakes ) )
tr_handshakeAbort ( tr_ptrArrayNth ( & manager - > incomingHandshakes , 0 ) ) ;
2008-09-23 19:11:04 +00:00
2013-01-24 23:59:52 +00:00
tr_ptrArrayDestruct ( & manager - > incomingHandshakes , NULL ) ;
2007-10-02 14:35:02 +00:00
2013-01-24 23:59:52 +00:00
managerUnlock ( manager ) ;
tr_free ( manager ) ;
2007-09-20 16:32:01 +00:00
}
2010-06-14 12:01:50 +00:00
/***
* * * *
* * */
void
2012-12-05 17:29:46 +00:00
tr_peerMgrOnBlocklistChanged ( tr_peerMgr * mgr )
2010-06-14 12:01:50 +00:00
{
2013-01-24 23:59:52 +00:00
tr_torrent * tor = NULL ;
tr_session * session = mgr - > session ;
2010-06-14 12:01:50 +00:00
2013-01-24 23:59:52 +00:00
/* we cache whether or not a peer is blocklisted...
since the blocklist has changed , erase that cached value */
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2010-06-14 12:01:50 +00:00
{
2013-01-24 23:59:52 +00:00
int i ;
2013-01-27 21:03:52 +00:00
tr_swarm * s = tor - > swarm ;
const int n = tr_ptrArraySize ( & s - > pool ) ;
2013-01-24 23:59:52 +00:00
for ( i = 0 ; i < n ; + + i )
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom = tr_ptrArrayNth ( & s - > pool , i ) ;
2013-01-24 23:59:52 +00:00
atom - > blocklisted = - 1 ;
2010-06-14 12:01:50 +00:00
}
}
}
2011-03-22 15:19:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
isAtomBlocklisted ( tr_session * session , struct peer_atom * atom )
2010-06-14 12:01:50 +00:00
{
2013-01-24 23:59:52 +00:00
if ( atom - > blocklisted < 0 )
atom - > blocklisted = tr_sessionIsAddressBlocked ( session , & atom - > addr ) ;
2010-06-14 12:01:50 +00:00
2013-01-24 23:59:52 +00:00
assert ( tr_isBool ( atom - > blocklisted ) ) ;
return atom - > blocklisted ;
2010-06-14 12:01:50 +00:00
}
2008-04-17 03:48:56 +00:00
/***
* * * *
* * */
2010-04-20 21:54:03 +00:00
static void
2012-12-05 17:29:46 +00:00
atomSetSeedProbability ( struct peer_atom * atom , int seedProbability )
2010-04-20 21:54:03 +00:00
{
2013-01-24 23:59:52 +00:00
assert ( atom ! = NULL ) ;
assert ( - 1 < = seedProbability & & seedProbability < = 100 ) ;
2010-04-20 21:54:03 +00:00
2013-01-24 23:59:52 +00:00
atom - > seedProbability = seedProbability ;
2010-04-20 21:54:03 +00:00
2013-01-24 23:59:52 +00:00
if ( seedProbability = = 100 )
atom - > flags | = ADDED_F_SEED_FLAG ;
else if ( seedProbability ! = - 1 )
atom - > flags & = ~ ADDED_F_SEED_FLAG ;
2010-04-20 21:54:03 +00:00
}
2011-03-22 15:19:54 +00:00
static inline bool
2012-12-05 17:29:46 +00:00
atomIsSeed ( const struct peer_atom * atom )
2010-04-20 21:54:03 +00:00
{
2013-01-24 23:59:52 +00:00
return atom - > seedProbability = = 100 ;
2010-04-20 21:54:03 +00:00
}
2011-02-24 14:35:45 +00:00
static void
2013-01-27 21:03:52 +00:00
atomSetSeed ( const tr_swarm * s , struct peer_atom * atom )
2011-02-24 14:35:45 +00:00
{
2013-01-24 23:59:52 +00:00
if ( ! atomIsSeed ( atom ) )
2011-02-24 14:35:45 +00:00
{
2013-01-27 21:03:52 +00:00
tordbg ( s , " marking peer %s as a seed " , tr_atomAddrStr ( atom ) ) ;
2011-02-24 14:35:45 +00:00
2013-01-24 23:59:52 +00:00
atomSetSeedProbability ( atom , 100 ) ;
2011-02-24 14:35:45 +00:00
}
}
2011-03-22 15:19:54 +00:00
bool
2012-12-05 17:29:46 +00:00
tr_peerMgrPeerIsSeed ( const tr_torrent * tor ,
const tr_address * addr )
2008-04-17 03:48:56 +00:00
{
2013-01-24 23:59:52 +00:00
bool isSeed = false ;
2013-01-27 21:03:52 +00:00
const tr_swarm * s = tor - > swarm ;
const struct peer_atom * atom = getExistingAtom ( s , addr ) ;
2008-04-17 03:48:56 +00:00
2013-01-24 23:59:52 +00:00
if ( atom )
isSeed = atomIsSeed ( atom ) ;
2008-04-17 03:48:56 +00:00
2013-01-24 23:59:52 +00:00
return isSeed ;
2008-04-17 03:48:56 +00:00
}
2011-02-18 00:41:06 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerMgrSetUtpSupported ( tr_torrent * tor , const tr_address * addr )
2011-02-18 00:41:06 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom = getExistingAtom ( tor - > swarm , addr ) ;
2011-02-18 00:41:06 +00:00
2013-01-24 23:59:52 +00:00
if ( atom )
atom - > flags | = ADDED_F_UTP_FLAGS ;
2011-02-18 00:41:06 +00:00
}
2011-02-18 00:43:31 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerMgrSetUtpFailed ( tr_torrent * tor , const tr_address * addr , bool failed )
2011-02-18 00:43:31 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom = getExistingAtom ( tor - > swarm , addr ) ;
2011-02-18 00:43:31 +00:00
2013-01-24 23:59:52 +00:00
if ( atom )
atom - > utp_failed = failed ;
2011-02-18 00:43:31 +00:00
}
2011-02-18 00:41:06 +00:00
2009-11-08 23:20:00 +00:00
/**
* * * REQUESTS
* * *
* * * There are two data structures associated with managing block requests :
2009-11-22 03:57:36 +00:00
* * *
2013-01-27 21:03:52 +00:00
* * * 1. tr_swarm : : requests , an array of " struct block_request " which keeps
2009-11-08 23:20:00 +00:00
* * * track of which blocks have been requested , and when , and by which peers .
* * * This is list is used for ( a ) cancelling requests that have been pending
* * * for too long and ( b ) avoiding duplicate requests before endgame .
2009-11-22 03:57:36 +00:00
* * *
2013-01-27 21:03:52 +00:00
* * * 2. tr_swarm : : pieces , an array of " struct weighted_piece " which lists the
2010-12-27 19:18:17 +00:00
* * * pieces that we want to request . It ' s used to decide which blocks to
2012-12-05 17:29:46 +00:00
* * * return next when tr_peerMgrGetBlockRequests ( ) is called .
2009-11-22 03:57:36 +00:00
* */
2009-11-08 23:20:00 +00:00
/**
* * * struct block_request
* */
2008-10-25 02:20:16 +00:00
2007-09-20 16:32:01 +00:00
static int
2012-12-05 17:29:46 +00:00
compareReqByBlock ( const void * va , const void * vb )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
const struct block_request * a = va ;
const struct block_request * b = vb ;
2009-12-15 20:13:34 +00:00
2013-01-27 21:03:52 +00:00
/* primary key: block */
if ( a - > block < b - > block ) return - 1 ;
if ( a - > block > b - > block ) return 1 ;
2009-12-15 20:13:34 +00:00
2013-01-27 21:03:52 +00:00
/* secondary key: peer */
if ( a - > peer < b - > peer ) return - 1 ;
if ( a - > peer > b - > peer ) return 1 ;
2009-12-15 20:13:34 +00:00
2013-01-27 21:03:52 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
2009-11-08 23:20:00 +00:00
static void
2013-01-27 21:03:52 +00:00
requestListAdd ( tr_swarm * s , tr_block_index_t block , tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
struct block_request key ;
2009-11-02 00:17:30 +00:00
2013-01-27 21:03:52 +00:00
/* ensure enough room is available... */
if ( s - > requestCount + 1 > = s - > requestAlloc )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
const int CHUNK_SIZE = 128 ;
s - > requestAlloc + = CHUNK_SIZE ;
s - > requests = tr_renew ( struct block_request ,
s - > requests , s - > requestAlloc ) ;
2009-11-08 23:20:00 +00:00
}
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
/* populate the record we're inserting */
key . block = block ;
key . peer = peer ;
key . sentAt = tr_time ( ) ;
2009-11-02 00:17:30 +00:00
2013-01-27 21:03:52 +00:00
/* insert the request to our array... */
{
bool exact ;
const int pos = tr_lowerBound ( & key , s - > requests , s - > requestCount ,
sizeof ( struct block_request ) ,
compareReqByBlock , & exact ) ;
assert ( ! exact ) ;
memmove ( s - > requests + pos + 1 ,
s - > requests + pos ,
sizeof ( struct block_request ) * ( s - > requestCount + + - pos ) ) ;
s - > requests [ pos ] = key ;
}
2009-12-16 18:20:01 +00:00
2013-01-27 21:03:52 +00:00
if ( peer ! = NULL )
2009-12-16 18:20:01 +00:00
{
2013-01-27 21:03:52 +00:00
+ + peer - > pendingReqsToPeer ;
assert ( peer - > pendingReqsToPeer > = 0 ) ;
2009-12-16 18:20:01 +00:00
}
2013-01-27 21:03:52 +00:00
/*fprintf (stderr, "added request of block %lu from peer %s... "
" there are now %d block \n " ,
( unsigned long ) block , tr_atomAddrStr ( peer - > atom ) , s - > requestCount ) ; */
2008-10-25 02:20:16 +00:00
}
2008-10-11 04:07:50 +00:00
2009-11-08 23:20:00 +00:00
static struct block_request *
2013-01-27 21:03:52 +00:00
requestListLookup ( tr_swarm * s , tr_block_index_t block , const tr_peer * peer )
2008-10-25 02:20:16 +00:00
{
2013-01-27 21:03:52 +00:00
struct block_request key ;
key . block = block ;
key . peer = ( tr_peer * ) peer ;
2008-10-11 04:07:50 +00:00
2013-01-27 21:03:52 +00:00
return bsearch ( & key , s - > requests , s - > requestCount ,
sizeof ( struct block_request ) ,
compareReqByBlock ) ;
2009-11-08 23:20:00 +00:00
}
2009-11-02 00:17:30 +00:00
2011-02-15 16:04:56 +00:00
/**
* Find the peers are we currently requesting the block
* with index @ a block from and append them to @ a peerArr .
*/
static void
2013-01-27 21:03:52 +00:00
getBlockRequestPeers ( tr_swarm * s , tr_block_index_t block ,
2012-12-05 17:29:46 +00:00
tr_ptrArray * peerArr )
2009-12-15 20:13:34 +00:00
{
2013-01-27 21:03:52 +00:00
bool exact ;
int i , pos ;
struct block_request key ;
2009-12-15 20:13:34 +00:00
2013-01-27 21:03:52 +00:00
key . block = block ;
key . peer = NULL ;
pos = tr_lowerBound ( & key , s - > requests , s - > requestCount ,
sizeof ( struct block_request ) ,
compareReqByBlock , & exact ) ;
2009-12-15 20:13:34 +00:00
2013-01-27 21:03:52 +00:00
assert ( ! exact ) ; /* shouldn't have a request with .peer == NULL */
2009-12-15 20:13:34 +00:00
2013-01-27 21:03:52 +00:00
for ( i = pos ; i < s - > requestCount ; + + i )
2011-02-15 16:04:56 +00:00
{
2013-01-27 21:03:52 +00:00
if ( s - > requests [ i ] . block ! = block )
break ;
tr_ptrArrayAppend ( peerArr , s - > requests [ i ] . peer ) ;
2009-12-15 20:13:34 +00:00
}
}
2010-01-25 05:19:54 +00:00
static void
2012-12-05 17:29:46 +00:00
decrementPendingReqCount ( const struct block_request * b )
2010-01-25 05:19:54 +00:00
{
2013-01-27 21:03:52 +00:00
if ( b - > peer ! = NULL )
if ( b - > peer - > pendingReqsToPeer > 0 )
- - b - > peer - > pendingReqsToPeer ;
2010-01-25 05:19:54 +00:00
}
2009-11-08 23:20:00 +00:00
static void
2013-01-27 21:03:52 +00:00
requestListRemove ( tr_swarm * s , tr_block_index_t block , const tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
const struct block_request * b = requestListLookup ( s , block , peer ) ;
if ( b ! = NULL )
2008-10-11 04:07:50 +00:00
{
2013-01-27 21:03:52 +00:00
const int pos = b - s - > requests ;
assert ( pos < s - > requestCount ) ;
2009-12-16 18:20:01 +00:00
2013-01-27 21:03:52 +00:00
decrementPendingReqCount ( b ) ;
2009-12-16 18:20:01 +00:00
2013-01-27 21:03:52 +00:00
tr_removeElementFromArray ( s - > requests ,
pos ,
sizeof ( struct block_request ) ,
s - > requestCount - - ) ;
2010-03-03 04:16:18 +00:00
2013-01-27 21:03:52 +00:00
/*fprintf (stderr, "removing request of block %lu from peer %s... "
" there are now %d block requests left \n " ,
2012-12-05 17:29:46 +00:00
( unsigned long ) block , tr_atomAddrStr ( peer - > atom ) , t - > requestCount ) ; */
2009-11-08 23:20:00 +00:00
}
}
2008-10-11 04:07:50 +00:00
2011-02-17 05:14:53 +00:00
static int
2013-02-04 16:23:33 +00:00
countActiveWebseeds ( tr_swarm * s )
2011-02-17 05:14:53 +00:00
{
2013-05-27 21:04:48 +00:00
int activeCount ;
2009-11-08 23:20:00 +00:00
2013-05-27 21:04:48 +00:00
if ( s - > tor - > isRunning & & ! tr_torrentIsSeed ( s - > tor ) )
{
int i ;
const int n = tr_ptrArraySize ( & s - > webseeds ) ;
const uint64_t now = tr_time_msec ( ) ;
for ( i = 0 ; i < n ; + + i )
if ( tr_peerIsTransferringPieces ( tr_ptrArrayNth ( & s - > webseeds , i ) , now , TR_DOWN , NULL ) )
+ + activeCount ;
}
else
{
activeCount = 0 ;
}
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
return activeCount ;
2011-02-17 05:14:53 +00:00
}
2011-03-28 16:31:05 +00:00
static bool
2013-01-27 21:03:52 +00:00
testForEndgame ( const tr_swarm * s )
2011-03-28 16:31:05 +00:00
{
2013-01-27 21:03:52 +00:00
/* we consider ourselves to be in endgame if the number of bytes
we ' ve got requested is > = the number of bytes left to download */
return ( s - > requestCount * s - > tor - > blockSize )
> = tr_cpLeftUntilDone ( & s - > tor - > completion ) ;
2011-03-28 16:31:05 +00:00
}
2011-02-17 05:14:53 +00:00
static void
2013-01-27 21:03:52 +00:00
updateEndgame ( tr_swarm * s )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( s - > requestCount > = 0 ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
if ( ! testForEndgame ( s ) )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
/* not in endgame */
s - > endgame = 0 ;
2011-02-17 05:14:53 +00:00
}
2013-01-27 21:03:52 +00:00
else if ( ! s - > endgame ) /* only recalculate when endgame first begins */
2011-02-17 05:14:53 +00:00
{
2013-02-04 16:23:33 +00:00
int i ;
2013-01-27 21:03:52 +00:00
int numDownloading = 0 ;
2013-02-04 16:23:33 +00:00
const int n = tr_ptrArraySize ( & s - > peers ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
/* add the active bittorrent peers... */
2013-02-04 16:23:33 +00:00
for ( i = 0 ; i < n ; + + i )
{
const tr_peer * p = tr_ptrArrayNth ( & s - > peers , i ) ;
if ( p - > pendingReqsToPeer > 0 )
+ + numDownloading ;
}
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
/* add the active webseeds... */
numDownloading + = countActiveWebseeds ( s ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
/* average number of pending requests per downloading peer */
s - > endgame = s - > requestCount / MAX ( numDownloading , 1 ) ;
2011-02-17 05:14:53 +00:00
}
}
/****
* * * * *
* * * * * Piece List Manipulation / Accessors
* * * * *
* * * */
static inline void
2013-01-27 21:03:52 +00:00
invalidatePieceSorting ( tr_swarm * s )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
s - > pieceSortState = PIECES_UNSORTED ;
2011-02-17 05:14:53 +00:00
}
2008-10-11 04:07:50 +00:00
2011-03-07 14:33:45 +00:00
static const tr_torrent * weightTorrent ;
2009-11-02 00:17:30 +00:00
2011-03-07 14:33:45 +00:00
static const uint16_t * weightReplication ;
2011-02-17 05:14:53 +00:00
static void
2013-01-27 21:03:52 +00:00
setComparePieceByWeightTorrent ( tr_swarm * s )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
if ( ! replicationExists ( s ) )
replicationNew ( s ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
weightTorrent = s - > tor ;
weightReplication = s - > pieceReplication ;
2011-02-17 05:14:53 +00:00
}
2009-11-08 23:20:00 +00:00
/* we try to create a "weight" s.t. high-priority pieces come before others,
* and that partially - complete pieces come before empty ones . */
static int
2012-12-05 17:29:46 +00:00
comparePieceByWeight ( const void * va , const void * vb )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
const struct weighted_piece * a = va ;
const struct weighted_piece * b = vb ;
int ia , ib , missing , pending ;
const tr_torrent * tor = weightTorrent ;
const uint16_t * rep = weightReplication ;
/* primary key: weight */
missing = tr_cpMissingBlocksInPiece ( & tor - > completion , a - > index ) ;
pending = a - > requestCount ;
ia = missing > pending ? missing - pending : ( tor - > blockCountInPiece + pending ) ;
missing = tr_cpMissingBlocksInPiece ( & tor - > completion , b - > index ) ;
pending = b - > requestCount ;
ib = missing > pending ? missing - pending : ( tor - > blockCountInPiece + pending ) ;
if ( ia < ib ) return - 1 ;
if ( ia > ib ) return 1 ;
/* secondary key: higher priorities go first */
ia = tor - > info . pieces [ a - > index ] . priority ;
ib = tor - > info . pieces [ b - > index ] . priority ;
if ( ia > ib ) return - 1 ;
if ( ia < ib ) return 1 ;
/* tertiary key: rarest first. */
ia = rep [ a - > index ] ;
ib = rep [ b - > index ] ;
if ( ia < ib ) return - 1 ;
if ( ia > ib ) return 1 ;
/* quaternary key: random */
if ( a - > salt < b - > salt ) return - 1 ;
if ( a - > salt > b - > salt ) return 1 ;
/* okay, they're equal */
return 0 ;
2009-02-25 13:04:51 +00:00
}
2009-11-08 23:20:00 +00:00
static int
2012-12-05 17:29:46 +00:00
comparePieceByIndex ( const void * va , const void * vb )
2008-10-25 02:20:16 +00:00
{
2013-01-27 21:03:52 +00:00
const struct weighted_piece * a = va ;
const struct weighted_piece * b = vb ;
if ( a - > index < b - > index ) return - 1 ;
if ( a - > index > b - > index ) return 1 ;
return 0 ;
2009-11-01 02:10:47 +00:00
}
2009-02-18 17:19:36 +00:00
2009-11-08 23:20:00 +00:00
static void
2013-01-27 21:03:52 +00:00
pieceListSort ( tr_swarm * s , enum piece_sort_state state )
2009-11-01 02:10:47 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( state = = PIECES_SORTED_BY_INDEX
| | state = = PIECES_SORTED_BY_WEIGHT ) ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
if ( state = = PIECES_SORTED_BY_WEIGHT )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
setComparePieceByWeightTorrent ( s ) ;
qsort ( s - > pieces , s - > pieceCount , sizeof ( struct weighted_piece ) , comparePieceByWeight ) ;
}
else
{
qsort ( s - > pieces , s - > pieceCount , sizeof ( struct weighted_piece ) , comparePieceByIndex ) ;
2011-02-17 05:14:53 +00:00
}
2011-02-15 16:04:56 +00:00
2013-01-27 21:03:52 +00:00
s - > pieceSortState = state ;
2009-11-02 00:17:30 +00:00
}
2010-03-07 22:56:14 +00:00
/**
2011-02-17 05:14:53 +00:00
* These functions are useful for testing , but too expensive for nightly builds .
2010-03-07 22:56:14 +00:00
* let ' s leave it disabled but add an easy hook to compile it back in
*/
2011-02-17 13:00:11 +00:00
# if 1
2011-02-17 05:14:53 +00:00
# define assertWeightedPiecesAreSorted(t)
# define assertReplicationCountIsExact(t)
# else
2010-03-07 22:56:14 +00:00
static void
2012-12-05 17:29:46 +00:00
assertWeightedPiecesAreSorted ( Torrent * t )
2010-03-07 22:56:14 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! t - > endgame )
2010-03-07 22:56:14 +00:00
{
int i ;
2012-12-05 17:29:46 +00:00
setComparePieceByWeightTorrent ( t ) ;
for ( i = 0 ; i < t - > pieceCount - 1 ; + + i )
assert ( comparePieceByWeight ( & t - > pieces [ i ] , & t - > pieces [ i + 1 ] ) < = 0 ) ;
2010-03-07 22:56:14 +00:00
}
}
2011-02-17 05:14:53 +00:00
static void
2012-12-05 17:29:46 +00:00
assertReplicationCountIsExact ( Torrent * t )
2011-02-17 05:14:53 +00:00
{
/* This assert might fail due to errors of implementations in other
* clients . It happens when receiving duplicate bitfields / HaveAll / HaveNone
* from a client . If a such a behavior is noticed ,
* a bug report should be filled to the faulty client . */
size_t piece_i ;
const uint16_t * rep = t - > pieceReplication ;
const size_t piece_count = t - > pieceReplicationSize ;
2012-12-05 17:29:46 +00:00
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
const int peer_count = tr_ptrArraySize ( & t - > peers ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
assert ( piece_count = = t - > tor - > info . pieceCount ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
for ( piece_i = 0 ; piece_i < piece_count ; + + piece_i )
2011-02-17 05:14:53 +00:00
{
int peer_i ;
uint16_t r = 0 ;
2012-12-05 17:29:46 +00:00
for ( peer_i = 0 ; peer_i < peer_count ; + + peer_i )
if ( tr_bitsetHas ( & peers [ peer_i ] - > have , piece_i ) )
2011-02-17 05:14:53 +00:00
+ + r ;
2012-12-05 17:29:46 +00:00
assert ( rep [ piece_i ] = = r ) ;
2011-02-17 05:14:53 +00:00
}
}
2010-03-07 22:56:14 +00:00
# endif
2009-11-08 23:20:00 +00:00
static struct weighted_piece *
2013-01-27 21:03:52 +00:00
pieceListLookup ( tr_swarm * s , tr_piece_index_t index )
2009-11-02 00:17:30 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < s - > pieceCount ; + + i )
if ( s - > pieces [ i ] . index = = index )
return & s - > pieces [ i ] ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
return NULL ;
2009-11-01 02:10:47 +00:00
}
2009-02-18 17:19:36 +00:00
2009-11-01 02:10:47 +00:00
static void
2013-01-27 21:03:52 +00:00
pieceListRebuild ( tr_swarm * s )
2009-11-01 02:10:47 +00:00
{
2013-01-27 21:03:52 +00:00
if ( ! tr_torrentIsSeed ( s - > tor ) )
2009-11-02 00:17:30 +00:00
{
2013-01-27 21:03:52 +00:00
tr_piece_index_t i ;
tr_piece_index_t * pool ;
tr_piece_index_t poolCount = 0 ;
const tr_torrent * tor = s - > tor ;
const tr_info * inf = tr_torrentInfo ( tor ) ;
struct weighted_piece * pieces ;
int pieceCount ;
/* build the new list */
pool = tr_new ( tr_piece_index_t , inf - > pieceCount ) ;
for ( i = 0 ; i < inf - > pieceCount ; + + i )
if ( ! inf - > pieces [ i ] . dnd )
if ( ! tr_cpPieceIsComplete ( & tor - > completion , i ) )
pool [ poolCount + + ] = i ;
pieceCount = poolCount ;
pieces = tr_new0 ( struct weighted_piece , pieceCount ) ;
for ( i = 0 ; i < poolCount ; + + i )
{
struct weighted_piece * piece = pieces + i ;
piece - > index = pool [ i ] ;
piece - > requestCount = 0 ;
piece - > salt = tr_cryptoWeakRandInt ( 4096 ) ;
2009-11-08 23:20:00 +00:00
}
2009-11-02 00:17:30 +00:00
2013-01-27 21:03:52 +00:00
/* if we already had a list of pieces, merge it into
* the new list so we don ' t lose its requestCounts */
if ( s - > pieces ! = NULL )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
struct weighted_piece * o = s - > pieces ;
struct weighted_piece * oend = o + s - > pieceCount ;
struct weighted_piece * n = pieces ;
struct weighted_piece * nend = n + pieceCount ;
pieceListSort ( s , PIECES_SORTED_BY_INDEX ) ;
while ( o ! = oend & & n ! = nend )
{
if ( o - > index < n - > index )
+ + o ;
else if ( o - > index > n - > index )
+ + n ;
else
* n + + = * o + + ;
2009-11-08 23:20:00 +00:00
}
2008-10-11 04:07:50 +00:00
2013-01-27 21:03:52 +00:00
tr_free ( s - > pieces ) ;
2009-11-08 23:20:00 +00:00
}
2008-02-10 04:03:19 +00:00
2013-01-27 21:03:52 +00:00
s - > pieces = pieces ;
s - > pieceCount = pieceCount ;
2010-01-12 20:17:22 +00:00
2013-01-27 21:03:52 +00:00
pieceListSort ( s , PIECES_SORTED_BY_WEIGHT ) ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
/* cleanup */
tr_free ( pool ) ;
2008-02-10 04:03:19 +00:00
}
}
2009-11-08 23:20:00 +00:00
static void
2013-01-27 21:03:52 +00:00
pieceListRemovePiece ( tr_swarm * s , tr_piece_index_t piece )
2008-10-25 15:19:46 +00:00
{
2013-01-27 21:03:52 +00:00
struct weighted_piece * p ;
2010-03-03 04:16:18 +00:00
2013-01-27 21:03:52 +00:00
if ( ( p = pieceListLookup ( s , piece ) ) )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
const int pos = p - s - > pieces ;
2009-11-02 00:17:30 +00:00
2013-01-27 21:03:52 +00:00
tr_removeElementFromArray ( s - > pieces ,
pos ,
sizeof ( struct weighted_piece ) ,
s - > pieceCount - - ) ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
if ( s - > pieceCount = = 0 )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
tr_free ( s - > pieces ) ;
s - > pieces = NULL ;
2009-11-02 00:17:30 +00:00
}
}
}
2009-10-27 20:06:55 +00:00
static void
2013-01-27 21:03:52 +00:00
pieceListResortPiece ( tr_swarm * s , struct weighted_piece * p )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
int pos ;
bool isSorted = true ;
2010-03-03 04:16:18 +00:00
2013-01-27 21:03:52 +00:00
if ( p = = NULL )
return ;
2010-03-03 04:16:18 +00:00
2013-01-27 21:03:52 +00:00
/* is the torrent already sorted? */
pos = p - s - > pieces ;
setComparePieceByWeightTorrent ( s ) ;
if ( isSorted & & ( pos > 0 ) & & ( comparePieceByWeight ( p - 1 , p ) > 0 ) )
isSorted = false ;
if ( isSorted & & ( pos < s - > pieceCount - 1 ) & & ( comparePieceByWeight ( p , p + 1 ) > 0 ) )
isSorted = false ;
2010-01-12 20:17:22 +00:00
2013-01-27 21:03:52 +00:00
if ( s - > pieceSortState ! = PIECES_SORTED_BY_WEIGHT )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
pieceListSort ( s , PIECES_SORTED_BY_WEIGHT ) ;
isSorted = true ;
2011-02-17 05:14:53 +00:00
}
2013-01-27 21:03:52 +00:00
/* if it's not sorted, move it around */
if ( ! isSorted )
2010-01-12 20:17:22 +00:00
{
2013-01-27 21:03:52 +00:00
bool exact ;
const struct weighted_piece tmp = * p ;
2009-10-27 20:06:55 +00:00
2013-01-27 21:03:52 +00:00
tr_removeElementFromArray ( s - > pieces ,
pos ,
sizeof ( struct weighted_piece ) ,
s - > pieceCount - - ) ;
2010-01-12 20:17:22 +00:00
2013-01-27 21:03:52 +00:00
pos = tr_lowerBound ( & tmp , s - > pieces , s - > pieceCount ,
sizeof ( struct weighted_piece ) ,
comparePieceByWeight , & exact ) ;
2010-01-12 20:17:22 +00:00
2013-01-27 21:03:52 +00:00
memmove ( & s - > pieces [ pos + 1 ] ,
& s - > pieces [ pos ] ,
sizeof ( struct weighted_piece ) * ( s - > pieceCount + + - pos ) ) ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
s - > pieces [ pos ] = tmp ;
2010-03-03 04:16:18 +00:00
}
2010-01-12 20:17:22 +00:00
2013-01-27 21:03:52 +00:00
assertWeightedPiecesAreSorted ( s ) ;
2010-03-03 04:16:18 +00:00
}
2010-01-12 20:17:22 +00:00
2010-03-03 04:16:18 +00:00
static void
2013-01-27 21:03:52 +00:00
pieceListRemoveRequest ( tr_swarm * s , tr_block_index_t block )
2010-03-03 04:16:18 +00:00
{
2013-01-27 21:03:52 +00:00
struct weighted_piece * p ;
const tr_piece_index_t index = tr_torBlockPiece ( s - > tor , block ) ;
2010-01-12 20:17:22 +00:00
2013-01-27 21:03:52 +00:00
if ( ( ( p = pieceListLookup ( s , index ) ) ) & & ( p - > requestCount > 0 ) )
2010-03-03 04:16:18 +00:00
{
2013-01-27 21:03:52 +00:00
- - p - > requestCount ;
pieceListResortPiece ( s , p ) ;
2010-01-12 20:17:22 +00:00
}
2011-02-17 05:14:53 +00:00
}
2010-03-03 04:16:18 +00:00
2011-02-17 05:14:53 +00:00
/****
* * * * *
2012-12-05 17:29:46 +00:00
* * * * * Replication count ( for rarest first policy )
2011-02-17 05:14:53 +00:00
* * * * *
* * * */
/**
* Increase the replication count of this piece and sort it if the
* piece list is already sorted
*/
static void
2013-01-27 21:03:52 +00:00
tr_incrReplicationOfPiece ( tr_swarm * s , const size_t index )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( replicationExists ( s ) ) ;
assert ( s - > pieceReplicationSize = = s - > tor - > info . pieceCount ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
/* One more replication of this piece is present in the swarm */
+ + s - > pieceReplication [ index ] ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
/* we only resort the piece if the list is already sorted */
if ( s - > pieceSortState = = PIECES_SORTED_BY_WEIGHT )
pieceListResortPiece ( s , pieceListLookup ( s , index ) ) ;
2011-02-17 05:14:53 +00:00
}
/**
* Increases the replication count of pieces present in the bitfield
*/
static void
2013-01-27 21:03:52 +00:00
tr_incrReplicationFromBitfield ( tr_swarm * s , const tr_bitfield * b )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
size_t i ;
uint16_t * rep = s - > pieceReplication ;
const size_t n = s - > tor - > info . pieceCount ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
assert ( replicationExists ( s ) ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
if ( tr_bitfieldHas ( b , i ) )
+ + rep [ i ] ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
if ( s - > pieceSortState = = PIECES_SORTED_BY_WEIGHT )
invalidatePieceSorting ( s ) ;
2011-02-17 05:14:53 +00:00
}
/**
* Increase the replication count of every piece
*/
static void
2013-01-27 21:03:52 +00:00
tr_incrReplication ( tr_swarm * s )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
const int n = s - > pieceReplicationSize ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
assert ( replicationExists ( s ) ) ;
assert ( s - > pieceReplicationSize = = s - > tor - > info . pieceCount ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
+ + s - > pieceReplication [ i ] ;
2011-02-17 05:14:53 +00:00
}
/**
* Decrease the replication count of pieces present in the bitset .
*/
static void
2013-01-27 21:03:52 +00:00
tr_decrReplicationFromBitfield ( tr_swarm * s , const tr_bitfield * b )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
const int n = s - > pieceReplicationSize ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
assert ( replicationExists ( s ) ) ;
assert ( s - > pieceReplicationSize = = s - > tor - > info . pieceCount ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
if ( tr_bitfieldHasAll ( b ) )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
- - s - > pieceReplication [ i ] ;
2011-02-17 05:14:53 +00:00
}
2013-01-27 21:03:52 +00:00
else if ( ! tr_bitfieldHasNone ( b ) )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
if ( tr_bitfieldHas ( b , i ) )
- - s - > pieceReplication [ i ] ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
if ( s - > pieceSortState = = PIECES_SORTED_BY_WEIGHT )
invalidatePieceSorting ( s ) ;
2011-02-17 05:14:53 +00:00
}
2009-11-08 23:20:00 +00:00
}
/**
* * *
* */
void
2012-12-05 17:29:46 +00:00
tr_peerMgrRebuildRequests ( tr_torrent * tor )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
pieceListRebuild ( tor - > swarm ) ;
2009-11-08 23:20:00 +00:00
}
void
2012-12-05 17:29:46 +00:00
tr_peerMgrGetNextRequests ( tr_torrent * tor ,
2009-11-08 23:20:00 +00:00
tr_peer * peer ,
int numwant ,
tr_block_index_t * setme ,
2011-07-10 15:24:51 +00:00
int * numgot ,
2012-12-05 17:29:46 +00:00
bool get_intervals )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
int got ;
tr_swarm * s ;
struct weighted_piece * pieces ;
const tr_bitfield * const have = & peer - > have ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
/* sanity clause */
assert ( tr_isTorrent ( tor ) ) ;
assert ( numwant > 0 ) ;
2009-02-18 17:19:36 +00:00
2013-01-27 21:03:52 +00:00
/* walk through the pieces and find blocks that should be requested */
got = 0 ;
s = tor - > swarm ;
2008-06-07 21:26:41 +00:00
2013-01-27 21:03:52 +00:00
/* prep the pieces list */
if ( s - > pieces = = NULL )
pieceListRebuild ( s ) ;
2010-01-12 20:17:22 +00:00
2013-01-27 21:03:52 +00:00
if ( s - > pieceSortState ! = PIECES_SORTED_BY_WEIGHT )
pieceListSort ( s , PIECES_SORTED_BY_WEIGHT ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
assertReplicationCountIsExact ( s ) ;
assertWeightedPiecesAreSorted ( s ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
updateEndgame ( s ) ;
pieces = s - > pieces ;
for ( i = 0 ; i < s - > pieceCount & & got < numwant ; + + i )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
struct weighted_piece * p = pieces + i ;
2009-02-18 22:25:13 +00:00
2013-01-27 21:03:52 +00:00
/* if the peer has this piece that we want... */
if ( tr_bitfieldHas ( have , p - > index ) )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
tr_block_index_t b ;
tr_block_index_t first ;
tr_block_index_t last ;
tr_ptrArray peerArr = TR_PTR_ARRAY_INIT ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
tr_torGetPieceBlockRange ( tor , p - > index , & first , & last ) ;
2011-02-23 03:54:04 +00:00
2013-01-27 21:03:52 +00:00
for ( b = first ; b < = last & & ( got < numwant | | ( get_intervals & & setme [ 2 * got - 1 ] = = b - 1 ) ) ; + + b )
2008-06-07 21:26:41 +00:00
{
2013-01-27 21:03:52 +00:00
int peerCount ;
tr_peer * * peers ;
2011-02-15 16:04:56 +00:00
2013-01-27 21:03:52 +00:00
/* don't request blocks we've already got */
if ( tr_cpBlockIsComplete ( & tor - > completion , b ) )
continue ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
/* always add peer if this block has no peers yet */
tr_ptrArrayClear ( & peerArr ) ;
getBlockRequestPeers ( s , b , & peerArr ) ;
peers = ( tr_peer * * ) tr_ptrArrayPeek ( & peerArr , & peerCount ) ;
if ( peerCount ! = 0 )
2011-02-15 16:04:56 +00:00
{
2013-01-27 21:03:52 +00:00
/* don't make a second block request until the endgame */
if ( ! s - > endgame )
continue ;
/* don't have more than two peers requesting this block */
if ( peerCount > 1 )
continue ;
/* don't send the same request to the same peer twice */
if ( peer = = peers [ 0 ] )
continue ;
/* in the endgame allow an additional peer to download a
block but only if the peer seems to be handling requests
relatively fast */
if ( peer - > pendingReqsToPeer + numwant - got < s - > endgame )
continue ;
2011-02-15 16:04:56 +00:00
}
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
/* update the caller's table */
if ( ! get_intervals )
{
setme [ got + + ] = b ;
2011-07-10 15:24:51 +00:00
}
2013-01-27 21:03:52 +00:00
/* if intervals are requested two array entries are necessarry:
one for the interval ' s starting block and one for its end block */
else if ( got & & setme [ 2 * got - 1 ] = = b - 1 & & b ! = first )
{
/* expand the last interval */
+ + setme [ 2 * got - 1 ] ;
2011-07-10 15:24:51 +00:00
}
2013-01-27 21:03:52 +00:00
else
{
/* begin a new interval */
setme [ 2 * got ] = setme [ 2 * got + 1 ] = b ;
+ + got ;
2011-07-10 15:24:51 +00:00
}
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
/* update our own tables */
requestListAdd ( s , b , peer ) ;
+ + p - > requestCount ;
2007-09-20 16:32:01 +00:00
}
2011-02-15 16:04:56 +00:00
2013-01-27 21:03:52 +00:00
tr_ptrArrayDestruct ( & peerArr , NULL ) ;
2007-09-20 16:32:01 +00:00
}
}
2013-01-27 21:03:52 +00:00
/* In most cases we've just changed the weights of a small number of pieces.
* So rather than qsort ( ) ing the entire array , it ' s faster to apply an
* adaptive insertion sort algorithm . */
if ( got > 0 )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
/* not enough requests || last piece modified */
if ( i = = s - > pieceCount )
- - i ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
setComparePieceByWeightTorrent ( s ) ;
while ( - - i > = 0 )
2010-01-12 20:17:22 +00:00
{
2013-01-27 21:03:52 +00:00
bool exact ;
/* relative position! */
const int newpos = tr_lowerBound ( & s - > pieces [ i ] , & s - > pieces [ i + 1 ] ,
s - > pieceCount - ( i + 1 ) ,
sizeof ( struct weighted_piece ) ,
comparePieceByWeight , & exact ) ;
if ( newpos > 0 )
2010-01-12 20:17:22 +00:00
{
2013-01-27 21:03:52 +00:00
const struct weighted_piece piece = s - > pieces [ i ] ;
memmove ( & s - > pieces [ i ] ,
& s - > pieces [ i + 1 ] ,
sizeof ( struct weighted_piece ) * ( newpos ) ) ;
s - > pieces [ i + newpos ] = piece ;
2010-01-12 20:17:22 +00:00
}
}
2009-11-02 00:17:30 +00:00
}
2013-01-27 21:03:52 +00:00
assertWeightedPiecesAreSorted ( t ) ;
* numgot = got ;
2007-09-20 16:32:01 +00:00
}
2011-03-22 15:19:54 +00:00
bool
2012-12-05 17:29:46 +00:00
tr_peerMgrDidPeerRequest ( const tr_torrent * tor ,
2009-11-08 23:20:00 +00:00
const tr_peer * peer ,
2012-12-05 17:29:46 +00:00
tr_block_index_t block )
2008-10-11 04:07:50 +00:00
{
2013-01-27 21:03:52 +00:00
return requestListLookup ( ( tr_swarm * ) tor - > swarm , block , peer ) ! = NULL ;
2009-11-08 23:20:00 +00:00
}
2008-10-11 04:07:50 +00:00
2009-11-08 23:20:00 +00:00
/* cancel requests that are too old */
2009-12-10 05:52:46 +00:00
static void
2012-12-05 17:29:46 +00:00
refillUpkeep ( int foo UNUSED , short bar UNUSED , void * vmgr )
2009-11-08 23:20:00 +00:00
{
time_t now ;
time_t too_old ;
tr_torrent * tor ;
2011-04-28 17:46:31 +00:00
int cancel_buflen = 0 ;
struct block_request * cancel = NULL ;
2009-11-08 23:20:00 +00:00
tr_peerMgr * mgr = vmgr ;
2012-12-05 17:29:46 +00:00
managerLock ( mgr ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
now = tr_time ( ) ;
2009-11-08 23:20:00 +00:00
too_old = now - REQUEST_TTL_SECS ;
2011-04-28 17:46:31 +00:00
/* alloc the temporary "cancel" buffer */
tor = NULL ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
2013-01-27 21:03:52 +00:00
cancel_buflen = MAX ( cancel_buflen , tor - > swarm - > requestCount ) ;
2012-12-05 17:29:46 +00:00
if ( cancel_buflen > 0 )
cancel = tr_new ( struct block_request , cancel_buflen ) ;
2011-04-28 17:46:31 +00:00
/* prune requests that are too old */
2009-11-08 23:20:00 +00:00
tor = NULL ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s = tor - > swarm ;
const int n = s - > requestCount ;
2012-12-05 17:29:46 +00:00
if ( n > 0 )
2009-11-08 23:20:00 +00:00
{
int keepCount = 0 ;
int cancelCount = 0 ;
const struct block_request * it ;
const struct block_request * end ;
2013-01-27 21:03:52 +00:00
for ( it = s - > requests , end = it + n ; it ! = end ; + + it )
2010-01-20 18:48:52 +00:00
{
2013-02-04 16:23:33 +00:00
tr_peerMsgs * msgs = PEER_MSGS ( it - > peer ) ;
if ( ( msgs ! = NULL ) & & ( it - > sentAt < = too_old ) & & ! tr_peerMsgsIsReadingBlock ( msgs , it - > block ) )
2009-11-08 23:20:00 +00:00
cancel [ cancelCount + + ] = * it ;
else
2010-01-20 18:48:52 +00:00
{
2013-01-27 21:03:52 +00:00
if ( it ! = & s - > requests [ keepCount ] )
s - > requests [ keepCount ] = * it ;
2010-01-20 18:48:52 +00:00
keepCount + + ;
}
}
2009-11-08 23:20:00 +00:00
/* prune out the ones we aren't keeping */
2013-01-27 21:03:52 +00:00
s - > requestCount = keepCount ;
2008-10-11 04:07:50 +00:00
2009-11-08 23:20:00 +00:00
/* send cancel messages for all the "cancel" ones */
2013-02-04 16:23:33 +00:00
for ( it = cancel , end = it + cancelCount ; it ! = end ; + + it )
{
tr_peerMsgs * msgs = PEER_MSGS ( it - > peer ) ;
if ( msgs ! = NULL )
{
tr_historyAdd ( & it - > peer - > cancelsSentToPeer , now , 1 ) ;
tr_peerMsgsCancel ( msgs , it - > block ) ;
decrementPendingReqCount ( it ) ;
2010-01-25 04:54:04 +00:00
}
}
2008-12-30 08:20:16 +00:00
2009-11-08 23:20:00 +00:00
/* decrement the pending request counts for the timed-out blocks */
2012-12-05 17:29:46 +00:00
for ( it = cancel , end = it + cancelCount ; it ! = end ; + + it )
2013-01-27 21:03:52 +00:00
pieceListRemoveRequest ( s , it - > block ) ;
2009-11-08 23:20:00 +00:00
}
}
2012-12-05 17:29:46 +00:00
tr_free ( cancel ) ;
tr_timerAddMsec ( mgr - > refillUpkeepTimer , REFILL_UPKEEP_PERIOD_MSEC ) ;
managerUnlock ( mgr ) ;
2008-10-11 04:07:50 +00:00
}
2007-11-13 05:36:43 +00:00
static void
2013-01-27 21:03:52 +00:00
addStrike ( tr_swarm * s , tr_peer * peer )
2007-11-13 05:36:43 +00:00
{
2013-01-27 21:03:52 +00:00
tordbg ( s , " increasing peer %s strike count to %d " ,
tr_atomAddrStr ( peer - > atom ) , peer - > strikes + 1 ) ;
2007-11-13 05:36:43 +00:00
2013-01-27 21:03:52 +00:00
if ( + + peer - > strikes > = MAX_BAD_PIECES_PER_PEER )
2007-11-13 05:36:43 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom = peer - > atom ;
atom - > flags2 | = MYFLAG_BANNED ;
peer - > doPurge = 1 ;
tordbg ( s , " banning peer %s " , tr_atomAddrStr ( atom ) ) ;
2007-11-13 05:36:43 +00:00
}
}
2008-12-02 17:10:54 +00:00
static void
2013-01-27 21:03:52 +00:00
peerSuggestedPiece ( tr_swarm * s UNUSED ,
2008-12-22 00:52:44 +00:00
tr_peer * peer UNUSED ,
tr_piece_index_t pieceIndex UNUSED ,
2012-12-05 17:29:46 +00:00
int isFastAllowed UNUSED )
2008-12-02 17:10:54 +00:00
{
2008-12-22 00:52:44 +00:00
#if 0
2012-12-05 17:29:46 +00:00
assert ( t ) ;
assert ( peer ) ;
assert ( peer - > msgs ) ;
2008-12-02 17:10:54 +00:00
/* is this a valid piece? */
2012-12-05 17:29:46 +00:00
if ( pieceIndex > = t - > tor - > info . pieceCount )
2008-12-02 17:10:54 +00:00
return ;
/* don't ask for it if we've already got it */
2012-12-05 17:29:46 +00:00
if ( tr_cpPieceIsComplete ( t - > tor - > completion , pieceIndex ) )
2008-12-02 17:10:54 +00:00
return ;
/* don't ask for it if they don't have it */
2012-12-05 17:29:46 +00:00
if ( ! tr_bitfieldHas ( peer - > have , pieceIndex ) )
2008-12-02 17:10:54 +00:00
return ;
/* don't ask for it if we're choked and it's not fast */
2012-12-05 17:29:46 +00:00
if ( ! isFastAllowed & & peer - > clientIsChoked )
2008-12-02 17:10:54 +00:00
return ;
/* request the blocks that we don't have in this piece */
{
2011-02-23 03:54:04 +00:00
tr_block_index_t b ;
tr_block_index_t first ;
tr_block_index_t last ;
2008-12-02 17:10:54 +00:00
const tr_torrent * tor = t - > tor ;
2012-12-05 17:29:46 +00:00
tr_torGetPieceBlockRange ( t - > tor , pieceIndex , & first , & last ) ;
2011-02-23 03:54:04 +00:00
2012-12-05 17:29:46 +00:00
for ( b = first ; b < = last ; + + b )
2008-12-02 17:10:54 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! tr_cpBlockIsComplete ( tor - > completion , b ) )
2008-12-02 17:10:54 +00:00
{
2012-12-05 17:29:46 +00:00
const uint32_t offset = getBlockOffsetInPiece ( tor , b ) ;
const uint32_t length = tr_torBlockCountBytes ( tor , b ) ;
tr_peerMsgsAddRequest ( peer - > msgs , pieceIndex , offset , length ) ;
incrementPieceRequests ( t , pieceIndex ) ;
2008-12-02 17:10:54 +00:00
}
}
}
2008-12-22 00:52:44 +00:00
# endif
2008-12-02 17:10:54 +00:00
}
2009-11-08 23:20:00 +00:00
static void
2013-01-27 21:03:52 +00:00
removeRequestFromTables ( tr_swarm * s , tr_block_index_t block , const tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
requestListRemove ( s , block , peer ) ;
pieceListRemoveRequest ( s , block ) ;
2009-11-08 23:20:00 +00:00
}
/* peer choked us, or maybe it disconnected.
either way we need to remove all its requests */
static void
2013-01-27 21:03:52 +00:00
peerDeclinedAllRequests ( tr_swarm * s , const tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
2013-01-27 21:03:52 +00:00
int i , n ;
tr_block_index_t * blocks = tr_new ( tr_block_index_t , s - > requestCount ) ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
for ( i = n = 0 ; i < s - > requestCount ; + + i )
if ( peer = = s - > requests [ i ] . peer )
blocks [ n + + ] = s - > requests [ i ] . block ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
removeRequestFromTables ( s , blocks [ i ] , peer ) ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
tr_free ( blocks ) ;
2009-11-08 23:20:00 +00:00
}
2013-01-26 23:08:51 +00:00
static void
2013-01-27 21:03:52 +00:00
cancelAllRequestsForBlock ( tr_swarm * s ,
tr_block_index_t block ,
tr_peer * no_notify )
2013-01-26 23:08:51 +00:00
{
int i ;
int peerCount ;
tr_peer * * peers ;
tr_ptrArray peerArr ;
peerArr = TR_PTR_ARRAY_INIT ;
2013-01-27 21:03:52 +00:00
getBlockRequestPeers ( s , block , & peerArr ) ;
2013-01-26 23:08:51 +00:00
peers = ( tr_peer * * ) tr_ptrArrayPeek ( & peerArr , & peerCount ) ;
for ( i = 0 ; i < peerCount ; + + i )
{
tr_peer * p = peers [ i ] ;
2013-02-04 16:23:33 +00:00
if ( ( p ! = no_notify ) & & ( p ! = NULL ) )
2013-01-26 23:08:51 +00:00
{
tr_historyAdd ( & p - > cancelsSentToPeer , tr_time ( ) , 1 ) ;
2013-02-04 16:23:33 +00:00
tr_peerMsgsCancel ( PEER_MSGS ( p ) , block ) ;
2013-01-26 23:08:51 +00:00
}
2013-01-27 21:03:52 +00:00
removeRequestFromTables ( s , block , p ) ;
2013-01-26 23:08:51 +00:00
}
tr_ptrArrayDestruct ( & peerArr , NULL ) ;
}
void
tr_peerMgrPieceCompleted ( tr_torrent * tor , tr_piece_index_t p )
{
2013-02-04 16:23:33 +00:00
int i ;
2013-01-30 20:06:12 +00:00
bool pieceCameFromPeers = false ;
tr_swarm * const s = tor - > swarm ;
2013-02-04 16:23:33 +00:00
const int n = tr_ptrArraySize ( & s - > peers ) ;
2013-01-26 23:08:51 +00:00
2013-01-30 20:06:12 +00:00
/* walk through our peers */
2013-02-04 16:23:33 +00:00
for ( i = 0 ; i < n ; + + i )
2013-01-30 20:06:12 +00:00
{
2013-02-04 16:23:33 +00:00
tr_peer * peer = tr_ptrArrayNth ( & s - > peers , i ) ;
2013-01-30 20:06:12 +00:00
/* notify the peer that we now have this piece */
2013-02-04 16:23:33 +00:00
tr_peerMsgsHave ( PEER_MSGS ( peer ) , p ) ;
2013-01-30 20:06:12 +00:00
if ( ! pieceCameFromPeers )
2013-02-04 16:23:33 +00:00
pieceCameFromPeers = tr_bitfieldHas ( & peer - > blame , p ) ;
2013-01-30 20:06:12 +00:00
}
if ( pieceCameFromPeers ) /* webseed downloads don't belong in announce totals */
tr_announcerAddBytes ( tor , TR_ANN_DOWN , tr_torPieceCountBytes ( tor , p ) ) ;
2013-01-26 23:08:51 +00:00
/* bookkeeping */
2013-01-27 21:03:52 +00:00
pieceListRemovePiece ( s , p ) ;
s - > needsCompletenessCheck = true ;
2013-01-26 23:08:51 +00:00
}
2011-03-07 14:33:45 +00:00
2008-06-07 21:26:41 +00:00
static void
2013-01-27 21:03:52 +00:00
peerCallbackFunc ( tr_peer * peer , const tr_peer_event * e , void * vs )
2008-06-07 21:26:41 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s = vs ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
swarmLock ( s ) ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
assert ( peer ! = NULL ) ;
2011-02-25 01:48:46 +00:00
2013-01-27 21:03:52 +00:00
switch ( e - > eventType )
2007-09-20 16:32:01 +00:00
{
2013-01-30 18:00:03 +00:00
case TR_PEER_PEER_GOT_PIECE_DATA :
2008-09-23 19:11:04 +00:00
{
2013-01-27 21:03:52 +00:00
const time_t now = tr_time ( ) ;
tr_torrent * tor = s - > tor ;
2008-11-17 04:00:57 +00:00
2013-01-30 18:00:03 +00:00
tor - > uploadedCur + = e - > length ;
tr_announcerAddBytes ( tor , TR_ANN_UP , e - > length ) ;
tr_torrentSetActivityDate ( tor , now ) ;
tr_torrentSetDirty ( tor ) ;
tr_statsAddUploaded ( tor - > session , e - > length ) ;
2008-11-17 04:00:57 +00:00
2013-01-30 18:00:03 +00:00
if ( peer - > atom ! = NULL )
peer - > atom - > piece_data_time = now ;
2008-11-17 04:00:57 +00:00
2013-01-30 18:00:03 +00:00
break ;
}
case TR_PEER_CLIENT_GOT_PIECE_DATA :
{
const time_t now = tr_time ( ) ;
tr_torrent * tor = s - > tor ;
tor - > downloadedCur + = e - > length ;
tr_torrentSetActivityDate ( tor , now ) ;
tr_torrentSetDirty ( tor ) ;
tr_statsAddDownloaded ( tor - > session , e - > length ) ;
if ( peer - > atom ! = NULL )
2013-01-27 21:03:52 +00:00
peer - > atom - > piece_data_time = now ;
2008-11-17 04:00:57 +00:00
2013-01-27 21:03:52 +00:00
break ;
2008-01-05 18:17:56 +00:00
}
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_HAVE :
if ( replicationExists ( s ) )
{
tr_incrReplicationOfPiece ( s , e - > pieceIndex ) ;
assertReplicationCountIsExact ( s ) ;
}
break ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_HAVE_ALL :
if ( replicationExists ( s ) )
{
tr_incrReplication ( s ) ;
assertReplicationCountIsExact ( s ) ;
}
break ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_HAVE_NONE :
/* noop */
break ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_BITFIELD :
assert ( e - > bitfield ! = NULL ) ;
if ( replicationExists ( s ) )
{
tr_incrReplicationFromBitfield ( s , e - > bitfield ) ;
assertReplicationCountIsExact ( s ) ;
}
break ;
case TR_PEER_CLIENT_GOT_REJ :
{
tr_block_index_t b = _tr_block ( s - > tor , e - > pieceIndex , e - > offset ) ;
if ( b < s - > tor - > blockCount )
removeRequestFromTables ( s , b , peer ) ;
else
tordbg ( s , " Peer %s sent an out-of-range reject message " ,
tr_atomAddrStr ( peer - > atom ) ) ;
break ;
2011-03-21 16:42:32 +00:00
}
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_CHOKE :
peerDeclinedAllRequests ( s , peer ) ;
break ;
2009-11-08 23:20:00 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_PORT :
if ( peer - > atom )
peer - > atom - > port = e - > port ;
break ;
2009-10-29 16:10:03 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_SUGGEST :
peerSuggestedPiece ( s , peer , e - > pieceIndex , false ) ;
break ;
2008-12-02 17:10:54 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_ALLOWED_FAST :
peerSuggestedPiece ( s , peer , e - > pieceIndex , true ) ;
break ;
2008-12-02 17:10:54 +00:00
2013-01-27 21:03:52 +00:00
case TR_PEER_CLIENT_GOT_BLOCK :
{
2013-01-30 18:00:03 +00:00
tr_torrent * tor = s - > tor ;
const tr_piece_index_t p = e - > pieceIndex ;
const tr_block_index_t block = _tr_block ( tor , p , e - > offset ) ;
2013-01-27 21:03:52 +00:00
cancelAllRequestsForBlock ( s , block , peer ) ;
tr_historyAdd ( & peer - > blocksSentToClient , tr_time ( ) , 1 ) ;
2013-01-30 18:00:03 +00:00
pieceListResortPiece ( s , pieceListLookup ( s , p ) ) ;
tr_torrentGotBlock ( tor , block ) ;
2013-01-27 21:03:52 +00:00
break ;
}
case TR_PEER_ERROR :
if ( ( e - > err = = ERANGE ) | | ( e - > err = = EMSGSIZE ) | | ( e - > err = = ENOTCONN ) )
2013-01-26 23:08:51 +00:00
{
2013-01-27 21:03:52 +00:00
/* some protocol error from the peer */
peer - > doPurge = 1 ;
tordbg ( s , " setting %s doPurge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error " ,
tr_atomAddrStr ( peer - > atom ) ) ;
2013-01-26 23:08:51 +00:00
}
2013-01-27 21:03:52 +00:00
else
{
tordbg ( s , " unhandled error: %s " , tr_strerror ( e - > err ) ) ;
}
break ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
default :
assert ( 0 ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
swarmUnlock ( s ) ;
2007-09-20 16:32:01 +00:00
}
2009-11-26 05:13:58 +00:00
static int
2012-12-05 17:29:46 +00:00
getDefaultShelfLife ( uint8_t from )
2009-11-26 05:13:58 +00:00
{
/* in general, peers obtained from firsthand contact
* are better than those from secondhand , etc etc */
2012-12-05 17:29:46 +00:00
switch ( from )
2009-11-26 05:13:58 +00:00
{
2009-11-26 18:38:37 +00:00
case TR_PEER_FROM_INCOMING : return 60 * 60 * 6 ;
case TR_PEER_FROM_LTEP : return 60 * 60 * 6 ;
case TR_PEER_FROM_TRACKER : return 60 * 60 * 3 ;
case TR_PEER_FROM_DHT : return 60 * 60 * 3 ;
2009-11-26 05:13:58 +00:00
case TR_PEER_FROM_PEX : return 60 * 60 * 2 ;
case TR_PEER_FROM_RESUME : return 60 * 60 ;
2010-05-08 08:42:45 +00:00
case TR_PEER_FROM_LPD : return 10 * 60 ;
2009-11-26 18:38:37 +00:00
default : return 60 * 60 ;
2009-11-26 05:13:58 +00:00
}
}
2007-10-01 05:32:34 +00:00
static void
2013-01-27 21:03:52 +00:00
ensureAtomExists ( tr_swarm * s ,
2009-11-26 05:13:58 +00:00
const tr_address * addr ,
const tr_port port ,
const uint8_t flags ,
2010-04-20 21:54:03 +00:00
const int8_t seedProbability ,
2012-12-05 17:29:46 +00:00
const uint8_t from )
2007-10-01 05:32:34 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * a ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_address_is_valid ( addr ) ) ;
assert ( from < TR_PEER_FROM__MAX ) ;
2009-09-10 03:07:54 +00:00
2013-01-27 21:03:52 +00:00
a = getExistingAtom ( s , addr ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
if ( a = = NULL )
2007-10-01 05:32:34 +00:00
{
2013-01-27 21:03:52 +00:00
const int jitter = tr_cryptoWeakRandInt ( 60 * 10 ) ;
a = tr_new0 ( struct peer_atom , 1 ) ;
a - > addr = * addr ;
a - > port = port ;
a - > flags = flags ;
a - > fromFirst = from ;
a - > fromBest = from ;
a - > shelf_date = tr_time ( ) + getDefaultShelfLife ( from ) + jitter ;
a - > blocklisted = - 1 ;
atomSetSeedProbability ( a , seedProbability ) ;
tr_ptrArrayInsertSorted ( & s - > pool , a , compareAtomsByAddress ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
tordbg ( s , " got a new atom: %s " , tr_atomAddrStr ( a ) ) ;
2007-10-01 05:32:34 +00:00
}
2013-01-27 21:03:52 +00:00
else
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
if ( from < a - > fromBest )
a - > fromBest = from ;
2011-03-04 23:26:10 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > seedProbability = = - 1 )
atomSetSeedProbability ( a , seedProbability ) ;
2011-01-16 15:51:48 +00:00
2013-01-27 21:03:52 +00:00
a - > flags | = flags ;
2010-04-20 21:54:03 +00:00
}
2007-10-01 05:32:34 +00:00
}
2008-01-20 03:21:51 +00:00
static int
2012-12-05 17:29:46 +00:00
getMaxPeerCount ( const tr_torrent * tor )
2008-01-20 03:21:51 +00:00
{
2013-01-27 21:03:52 +00:00
return tor - > maxConnectedPeers ;
2008-01-20 03:21:51 +00:00
}
2008-09-05 05:14:49 +00:00
static int
2013-01-27 21:03:52 +00:00
getPeerCount ( const tr_swarm * s )
2008-09-05 05:14:49 +00:00
{
2013-01-27 21:03:52 +00:00
return tr_ptrArraySize ( & s - > peers ) ; /* + tr_ptrArraySize (&t->outgoingHandshakes); */
2008-09-05 05:14:49 +00:00
}
2013-02-04 16:23:33 +00:00
static void
createBitTorrentPeer ( tr_torrent * tor ,
struct tr_peerIo * io ,
struct peer_atom * atom ,
tr_quark client )
{
tr_peer * peer ;
tr_swarm * swarm ;
assert ( atom ! = NULL ) ;
assert ( tr_isTorrent ( tor ) ) ;
assert ( tor - > swarm ! = NULL ) ;
swarm = tor - > swarm ;
peer = ( tr_peer * ) tr_peerMsgsNew ( tor , io , peerCallbackFunc , swarm ) ;
peer - > atom = atom ;
peer - > client = client ;
atom - > peer = peer ;
tr_ptrArrayInsertSorted ( & swarm - > peers , peer , peerCompare ) ;
2013-05-27 21:04:48 +00:00
+ + tor - > peerCount ;
+ + tor - > peerFromCount [ atom - > fromFirst ] ;
assert ( tor - > peerCount = = tr_ptrArraySize ( & swarm - > peers ) ) ;
assert ( tor - > peerFromCount [ atom - > fromFirst ] < = tor - > peerCount ) ;
2013-02-04 16:23:33 +00:00
}
2007-10-02 16:12:44 +00:00
/* FIXME: this is kind of a mess. */
2011-03-22 15:19:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
myHandshakeDoneCB ( tr_handshake * handshake ,
2008-12-20 22:19:34 +00:00
tr_peerIo * io ,
2011-03-22 15:19:54 +00:00
bool readAnythingFromPeer ,
bool isConnected ,
2008-09-23 19:11:04 +00:00
const uint8_t * peer_id ,
2012-12-05 17:29:46 +00:00
void * vmanager )
2008-09-23 19:11:04 +00:00
{
2013-01-27 21:03:52 +00:00
bool ok = isConnected ;
bool success = false ;
tr_port port ;
const tr_address * addr ;
tr_peerMgr * manager = vmanager ;
tr_swarm * s ;
tr_handshake * ours ;
assert ( io ) ;
assert ( tr_isBool ( ok ) ) ;
s = tr_peerIoHasTorrentHash ( io )
? getExistingSwarm ( manager , tr_peerIoGetTorrentHash ( io ) )
: NULL ;
if ( tr_peerIoIsIncoming ( io ) )
ours = tr_ptrArrayRemoveSorted ( & manager - > incomingHandshakes ,
handshake , handshakeCompare ) ;
else if ( s )
ours = tr_ptrArrayRemoveSorted ( & s - > outgoingHandshakes ,
handshake , handshakeCompare ) ;
else
ours = handshake ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
assert ( ours ) ;
assert ( ours = = handshake ) ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
if ( s )
swarmLock ( s ) ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
addr = tr_peerIoGetAddress ( io , & port ) ;
2007-10-02 16:12:44 +00:00
2013-01-27 21:03:52 +00:00
if ( ! ok | | ! s | | ! s - > isRunning )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
if ( s )
2008-09-23 19:11:04 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom = getExistingAtom ( s , addr ) ;
if ( atom )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
+ + atom - > numFails ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
if ( ! readAnythingFromPeer )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
tordbg ( s , " marking peer %s as unreachable... numFails is %d " , tr_atomAddrStr ( atom ) , ( int ) atom - > numFails ) ;
atom - > flags2 | = MYFLAG_UNREACHABLE ;
2010-04-20 21:54:03 +00:00
}
}
2007-11-08 04:11:09 +00:00
}
2007-09-20 16:32:01 +00:00
}
2013-01-27 21:03:52 +00:00
else /* looking good */
2007-09-29 06:37:03 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
ensureAtomExists ( s , addr , port , 0 , - 1 , TR_PEER_FROM_INCOMING ) ;
atom = getExistingAtom ( s , addr ) ;
atom - > time = tr_time ( ) ;
atom - > piece_data_time = 0 ;
atom - > lastConnectionAt = tr_time ( ) ;
2007-10-11 00:09:58 +00:00
2013-01-27 21:03:52 +00:00
if ( ! tr_peerIoIsIncoming ( io ) )
2010-12-14 18:33:48 +00:00
{
2013-01-27 21:03:52 +00:00
atom - > flags | = ADDED_F_CONNECTABLE ;
atom - > flags2 & = ~ MYFLAG_UNREACHABLE ;
2010-12-14 18:33:48 +00:00
}
2013-01-27 21:03:52 +00:00
/* In principle, this flag specifies whether the peer groks uTP,
not whether it ' s currently connected over uTP . */
if ( io - > utp_socket )
atom - > flags | = ADDED_F_UTP_FLAGS ;
2011-02-18 00:24:48 +00:00
2013-01-27 21:03:52 +00:00
if ( atom - > flags2 & MYFLAG_BANNED )
2007-10-08 01:31:27 +00:00
{
2013-01-27 21:03:52 +00:00
tordbg ( s , " banned peer %s tried to reconnect " ,
tr_atomAddrStr ( atom ) ) ;
2007-10-08 01:31:27 +00:00
}
2013-01-27 21:03:52 +00:00
else if ( tr_peerIoIsIncoming ( io ) & & ( getPeerCount ( s ) > = getMaxPeerCount ( s - > tor ) ) )
2007-11-09 15:19:12 +00:00
{
}
2013-01-27 21:03:52 +00:00
else
2007-10-08 01:31:27 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peer * peer = atom - > peer ;
2007-10-11 00:09:58 +00:00
2013-01-27 21:03:52 +00:00
if ( peer ) /* we already have this peer */
2007-10-11 00:09:58 +00:00
{
}
2013-01-27 21:03:52 +00:00
else
2007-10-11 00:09:58 +00:00
{
2013-02-04 16:23:33 +00:00
tr_quark client ;
tr_peerIo * io ;
char buf [ 128 ] ;
2013-01-27 21:03:52 +00:00
2013-02-04 16:23:33 +00:00
if ( peer_id ! = NULL )
client = tr_quark_new ( tr_clientForId ( buf , sizeof ( buf ) , peer_id ) , - 1 ) ;
2013-01-27 21:03:52 +00:00
else
2013-02-04 16:23:33 +00:00
client = TR_KEY_NONE ;
2008-11-25 21:35:17 +00:00
2013-02-04 16:23:33 +00:00
io = tr_handshakeStealIO ( handshake ) ; /* this steals its refcount too, which is
balanced by our unref in peerDelete ( ) */
tr_peerIoSetParent ( io , & s - > tor - > bandwidth ) ;
createBitTorrentPeer ( s - > tor , io , atom , client ) ;
2008-09-19 17:03:25 +00:00
2013-01-27 21:03:52 +00:00
success = true ;
2007-10-11 00:09:58 +00:00
}
2007-09-20 16:32:01 +00:00
}
}
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
if ( s ! = NULL )
swarmUnlock ( s ) ;
2008-09-19 17:03:25 +00:00
2013-01-27 21:03:52 +00:00
return success ;
2007-09-20 16:32:01 +00:00
}
void
2013-01-27 21:03:52 +00:00
tr_peerMgrAddIncoming ( tr_peerMgr * manager ,
tr_address * addr ,
tr_port port ,
int socket ,
2012-12-05 17:29:46 +00:00
struct UTPSocket * utp_socket )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
tr_session * session ;
2009-10-23 03:41:36 +00:00
2013-01-27 21:03:52 +00:00
managerLock ( manager ) ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isSession ( manager - > session ) ) ;
session = manager - > session ;
2009-10-23 03:41:36 +00:00
2013-01-27 21:03:52 +00:00
if ( tr_sessionIsAddressBlocked ( session , addr ) )
2008-03-30 00:57:55 +00:00
{
2013-01-27 21:03:52 +00:00
tr_logAddDebug ( " Banned IP address \" %s \" tried to connect to us " , tr_address_to_string ( addr ) ) ;
if ( socket > = 0 )
tr_netClose ( session , socket ) ;
else
UTP_Close ( utp_socket ) ;
2008-03-30 00:57:55 +00:00
}
2013-01-27 21:03:52 +00:00
else if ( getExistingHandshake ( & manager - > incomingHandshakes , addr ) )
2007-10-25 13:38:34 +00:00
{
2013-01-27 21:03:52 +00:00
if ( socket > = 0 )
tr_netClose ( session , socket ) ;
else
UTP_Close ( utp_socket ) ;
2007-10-25 13:38:34 +00:00
}
2013-01-27 21:03:52 +00:00
else /* we don't have a connection to them yet... */
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peerIo * io ;
tr_handshake * handshake ;
2007-10-02 16:12:44 +00:00
2013-01-27 21:03:52 +00:00
io = tr_peerIoNewIncoming ( session , & session - > bandwidth , addr , port , socket , utp_socket ) ;
2007-10-15 16:01:42 +00:00
2013-01-27 21:03:52 +00:00
handshake = tr_handshakeNew ( io ,
session - > encryptionMode ,
myHandshakeDoneCB ,
manager ) ;
2007-10-02 16:12:44 +00:00
2013-01-27 21:03:52 +00:00
tr_peerIoUnref ( io ) ; /* balanced by the implicit ref in tr_peerIoNewIncoming () */
2009-01-05 06:45:08 +00:00
2013-01-27 21:03:52 +00:00
tr_ptrArrayInsertSorted ( & manager - > incomingHandshakes , handshake ,
handshakeCompare ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
managerUnlock ( manager ) ;
2007-09-20 16:32:01 +00:00
}
void
2012-12-05 17:29:46 +00:00
tr_peerMgrAddPex ( tr_torrent * tor , uint8_t from ,
const tr_pex * pex , int8_t seedProbability )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
if ( tr_isPex ( pex ) ) /* safeguard against corrupt data */
2008-12-17 03:38:02 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s = tor - > swarm ;
managerLock ( s - > manager ) ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
if ( ! tr_sessionIsAddressBlocked ( s - > manager - > session , & pex - > addr ) )
if ( tr_address_is_valid_for_peers ( & pex - > addr , pex - > port ) )
ensureAtomExists ( s , & pex - > addr , pex - > port , pex - > flags , seedProbability , from ) ;
2008-12-22 00:52:44 +00:00
2013-01-27 21:03:52 +00:00
managerUnlock ( s - > manager ) ;
2008-12-17 03:38:02 +00:00
}
2007-09-20 16:32:01 +00:00
}
2010-04-20 21:54:03 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerMgrMarkAllAsSeeds ( tr_torrent * tor )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s = tor - > swarm ;
const int n = tr_ptrArraySize ( & s - > pool ) ;
struct peer_atom * * it = ( struct peer_atom * * ) tr_ptrArrayBase ( & s - > pool ) ;
struct peer_atom * * end = it + n ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
while ( it ! = end )
atomSetSeed ( s , * it + + ) ;
2010-04-20 21:54:03 +00:00
}
2008-04-19 15:07:59 +00:00
tr_pex *
2013-01-27 21:03:52 +00:00
tr_peerMgrCompactToPex ( const void * compact ,
2008-09-23 19:11:04 +00:00
size_t compactLen ,
const uint8_t * added_f ,
size_t added_f_len ,
2013-01-27 21:03:52 +00:00
size_t * pexCount )
2008-09-23 19:11:04 +00:00
{
2013-01-27 21:03:52 +00:00
size_t i ;
size_t n = compactLen / 6 ;
const uint8_t * walk = compact ;
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
2008-08-09 16:17:59 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
2008-09-23 19:11:04 +00:00
{
2013-01-27 21:03:52 +00:00
pex [ i ] . addr . type = TR_AF_INET ;
memcpy ( & pex [ i ] . addr . addr , walk , 4 ) ; walk + = 4 ;
memcpy ( & pex [ i ] . port , walk , 2 ) ; walk + = 2 ;
if ( added_f & & ( n = = added_f_len ) )
pex [ i ] . flags = added_f [ i ] ;
2007-09-20 16:32:01 +00:00
}
2008-08-10 14:58:11 +00:00
2013-01-27 21:03:52 +00:00
* pexCount = n ;
return pex ;
2007-09-20 16:32:01 +00:00
}
2008-12-15 00:17:08 +00:00
tr_pex *
2012-12-05 17:29:46 +00:00
tr_peerMgrCompact6ToPex ( const void * compact ,
2008-12-15 00:17:08 +00:00
size_t compactLen ,
const uint8_t * added_f ,
size_t added_f_len ,
2012-12-05 17:29:46 +00:00
size_t * pexCount )
2008-12-15 00:17:08 +00:00
{
2013-01-27 21:03:52 +00:00
size_t i ;
size_t n = compactLen / 18 ;
const uint8_t * walk = compact ;
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
2009-08-10 20:04:08 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
2008-12-15 00:17:08 +00:00
{
2013-01-27 21:03:52 +00:00
pex [ i ] . addr . type = TR_AF_INET6 ;
memcpy ( & pex [ i ] . addr . addr . addr6 . s6_addr , walk , 16 ) ; walk + = 16 ;
memcpy ( & pex [ i ] . port , walk , 2 ) ; walk + = 2 ;
if ( added_f & & ( n = = added_f_len ) )
pex [ i ] . flags = added_f [ i ] ;
2008-12-15 00:17:08 +00:00
}
2009-08-10 20:04:08 +00:00
2013-01-27 21:03:52 +00:00
* pexCount = n ;
return pex ;
2008-12-15 00:17:08 +00:00
}
tr_pex *
2013-01-27 21:03:52 +00:00
tr_peerMgrArrayToPex ( const void * array ,
size_t arrayLen ,
2012-12-05 17:29:46 +00:00
size_t * pexCount )
2008-12-15 00:17:08 +00:00
{
2013-01-27 21:03:52 +00:00
size_t i ;
size_t n = arrayLen / ( sizeof ( tr_address ) + 2 ) ;
const uint8_t * walk = array ;
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
2009-08-10 20:04:08 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n ; + + i )
{
memcpy ( & pex [ i ] . addr , walk , sizeof ( tr_address ) ) ;
memcpy ( & pex [ i ] . port , walk + sizeof ( tr_address ) , 2 ) ;
pex [ i ] . flags = 0x00 ;
walk + = sizeof ( tr_address ) + 2 ;
2008-12-15 00:17:08 +00:00
}
2009-08-10 20:04:08 +00:00
2013-01-27 21:03:52 +00:00
* pexCount = n ;
return pex ;
2008-12-15 00:17:08 +00:00
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2013-01-26 23:08:51 +00:00
void
tr_peerMgrGotBadPiece ( tr_torrent * tor , tr_piece_index_t pieceIndex )
2007-09-20 16:32:01 +00:00
{
2013-01-26 23:08:51 +00:00
int i ;
int n ;
2013-01-27 21:03:52 +00:00
tr_swarm * s = tor - > swarm ;
2013-01-26 23:08:51 +00:00
const uint32_t byteCount = tr_torPieceCountBytes ( tor , pieceIndex ) ;
2007-10-08 01:31:27 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 , n = tr_ptrArraySize ( & s - > peers ) ; i ! = n ; + + i )
2013-01-26 23:08:51 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peer * peer = tr_ptrArrayNth ( & s - > peers , i ) ;
2007-10-08 01:31:27 +00:00
2013-01-26 23:08:51 +00:00
if ( tr_bitfieldHas ( & peer - > blame , pieceIndex ) )
2007-10-08 01:31:27 +00:00
{
2013-01-27 21:03:52 +00:00
tordbg ( s , " peer %s contributed to corrupt piece (%d); now has %d strikes " ,
2013-01-26 23:08:51 +00:00
tr_atomAddrStr ( peer - > atom ) , pieceIndex , ( int ) peer - > strikes + 1 ) ;
2013-01-27 21:03:52 +00:00
addStrike ( s , peer ) ;
2007-10-08 01:31:27 +00:00
}
}
2013-01-26 23:08:51 +00:00
tr_announcerAddBytes ( tor , TR_ANN_CORRUPT , byteCount ) ;
2007-09-20 16:32:01 +00:00
}
int
2012-12-05 17:29:46 +00:00
tr_pexCompare ( const void * va , const void * vb )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
const tr_pex * a = va ;
const tr_pex * b = vb ;
2008-12-16 23:31:05 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isPex ( a ) ) ;
assert ( tr_isPex ( b ) ) ;
2008-12-16 23:31:05 +00:00
2013-01-27 21:03:52 +00:00
if ( ( i = tr_address_compare ( & a - > addr , & b - > addr ) ) )
return i ;
2008-12-16 23:31:05 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > port ! = b - > port )
return a - > port < b - > port ? - 1 : 1 ;
2008-09-23 19:11:04 +00:00
2013-01-27 21:03:52 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
2009-09-10 02:20:35 +00:00
/* better goes first */
static int
2012-12-05 17:29:46 +00:00
compareAtomsByUsefulness ( const void * va , const void * vb )
2009-09-10 02:20:35 +00:00
{
2013-01-27 21:03:52 +00:00
const struct peer_atom * a = * ( const struct peer_atom * * ) va ;
const struct peer_atom * b = * ( const struct peer_atom * * ) vb ;
2009-09-10 02:20:35 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isAtom ( a ) ) ;
assert ( tr_isAtom ( b ) ) ;
2009-09-10 02:20:35 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > piece_data_time ! = b - > piece_data_time )
return a - > piece_data_time > b - > piece_data_time ? - 1 : 1 ;
if ( a - > fromBest ! = b - > fromBest )
return a - > fromBest < b - > fromBest ? - 1 : 1 ;
if ( a - > numFails ! = b - > numFails )
return a - > numFails < b - > numFails ? - 1 : 1 ;
2009-09-10 02:20:35 +00:00
2013-01-27 21:03:52 +00:00
return 0 ;
2009-09-10 02:20:35 +00:00
}
2011-03-29 15:23:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
isAtomInteresting ( const tr_torrent * tor , struct peer_atom * atom )
2011-03-29 15:23:54 +00:00
{
2013-01-27 21:03:52 +00:00
if ( tr_torrentIsSeed ( tor ) & & atomIsSeed ( atom ) )
return false ;
2011-03-29 15:23:54 +00:00
2013-01-27 21:03:52 +00:00
if ( peerIsInUse ( tor - > swarm , atom ) )
return true ;
2011-03-29 15:23:54 +00:00
2013-01-27 21:03:52 +00:00
if ( isAtomBlocklisted ( tor - > session , atom ) )
return false ;
2011-03-29 15:23:54 +00:00
2013-01-27 21:03:52 +00:00
if ( atom - > flags2 & MYFLAG_BANNED )
return false ;
2011-03-29 15:23:54 +00:00
2013-01-27 21:03:52 +00:00
return true ;
2011-03-29 15:23:54 +00:00
}
2007-09-20 16:32:01 +00:00
int
2012-12-05 17:29:46 +00:00
tr_peerMgrGetPeers ( tr_torrent * tor ,
2009-11-20 07:47:31 +00:00
tr_pex * * setme_pex ,
uint8_t af ,
uint8_t list_mode ,
2012-12-05 17:29:46 +00:00
int maxCount )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
int n ;
int count = 0 ;
int atomCount = 0 ;
const tr_swarm * s = tor - > swarm ;
struct peer_atom * * atoms = NULL ;
tr_pex * pex ;
tr_pex * walk ;
2009-11-20 07:47:31 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( setme_pex ! = NULL ) ;
assert ( af = = TR_AF_INET | | af = = TR_AF_INET6 ) ;
assert ( list_mode = = TR_PEERS_CONNECTED | | list_mode = = TR_PEERS_INTERESTING ) ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
managerLock ( s - > manager ) ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
/**
* * * build a list of atoms
* */
2009-11-20 07:47:31 +00:00
2013-01-27 21:03:52 +00:00
if ( list_mode = = TR_PEERS_CONNECTED ) /* connected peers only */
2008-10-05 22:51:18 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & s - > peers ) ;
atomCount = tr_ptrArraySize ( & s - > peers ) ;
atoms = tr_new ( struct peer_atom * , atomCount ) ;
for ( i = 0 ; i < atomCount ; + + i )
atoms [ i ] = peers [ i ] - > atom ;
2009-11-20 07:47:31 +00:00
}
2013-01-27 21:03:52 +00:00
else /* TR_PEERS_INTERESTING */
2009-11-20 07:47:31 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
struct peer_atom * * atomBase = ( struct peer_atom * * ) tr_ptrArrayBase ( & s - > pool ) ;
n = tr_ptrArraySize ( & s - > pool ) ;
atoms = tr_new ( struct peer_atom * , n ) ;
for ( i = 0 ; i < n ; + + i )
if ( isAtomInteresting ( tor , atomBase [ i ] ) )
atoms [ atomCount + + ] = atomBase [ i ] ;
2009-11-20 07:47:31 +00:00
}
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
qsort ( atoms , atomCount , sizeof ( struct peer_atom * ) , compareAtomsByUsefulness ) ;
2009-09-10 02:20:35 +00:00
2013-01-27 21:03:52 +00:00
/**
* * * add the first N of them into our return list
* */
2009-11-20 07:47:31 +00:00
2013-01-27 21:03:52 +00:00
n = MIN ( atomCount , maxCount ) ;
pex = walk = tr_new0 ( tr_pex , n ) ;
2009-11-20 07:47:31 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < atomCount & & count < n ; + + i )
2009-11-20 07:47:31 +00:00
{
2013-01-27 21:03:52 +00:00
const struct peer_atom * atom = atoms [ i ] ;
if ( atom - > addr . type = = af )
2008-10-05 22:51:18 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( tr_address_is_valid ( & atom - > addr ) ) ;
walk - > addr = atom - > addr ;
walk - > port = atom - > port ;
walk - > flags = atom - > flags ;
+ + count ;
+ + walk ;
2008-10-05 22:51:18 +00:00
}
2009-11-20 07:47:31 +00:00
}
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
qsort ( pex , count , sizeof ( tr_pex ) , tr_pexCompare ) ;
2009-09-10 02:20:35 +00:00
2013-01-27 21:03:52 +00:00
assert ( ( walk - pex ) = = count ) ;
* setme_pex = pex ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
/* cleanup */
tr_free ( atoms ) ;
managerUnlock ( s - > manager ) ;
return count ;
2007-09-20 16:32:01 +00:00
}
2012-12-05 17:29:46 +00:00
static void atomPulse ( int , short , void * ) ;
static void bandwidthPulse ( int , short , void * ) ;
static void rechokePulse ( int , short , void * ) ;
static void reconnectPulse ( int , short , void * ) ;
2009-12-10 05:52:46 +00:00
static struct event *
2012-12-05 17:29:46 +00:00
createTimer ( tr_session * session , int msec , void ( * callback ) ( int , short , void * ) , void * cbdata )
2009-12-10 05:52:46 +00:00
{
2013-01-27 21:03:52 +00:00
struct event * timer = evtimer_new ( session - > event_base , callback , cbdata ) ;
tr_timerAddMsec ( timer , msec ) ;
return timer ;
2009-12-10 05:52:46 +00:00
}
2009-11-26 05:13:58 +00:00
2009-05-13 20:54:35 +00:00
static void
2012-12-05 17:29:46 +00:00
ensureMgrTimersExist ( struct tr_peerMgr * m )
2009-05-13 20:54:35 +00:00
{
2013-01-27 21:03:52 +00:00
if ( m - > atomTimer = = NULL )
m - > atomTimer = createTimer ( m - > session , ATOM_PERIOD_MSEC , atomPulse , m ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
if ( m - > bandwidthTimer = = NULL )
m - > bandwidthTimer = createTimer ( m - > session , BANDWIDTH_PERIOD_MSEC , bandwidthPulse , m ) ;
2009-05-13 20:54:35 +00:00
2013-01-27 21:03:52 +00:00
if ( m - > rechokeTimer = = NULL )
m - > rechokeTimer = createTimer ( m - > session , RECHOKE_PERIOD_MSEC , rechokePulse , m ) ;
2009-05-13 20:54:35 +00:00
2013-01-27 21:03:52 +00:00
if ( m - > refillUpkeepTimer = = NULL )
m - > refillUpkeepTimer = createTimer ( m - > session , REFILL_UPKEEP_PERIOD_MSEC , refillUpkeep , m ) ;
2009-05-13 20:54:35 +00:00
}
2007-09-20 16:32:01 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerMgrStartTorrent ( tr_torrent * tor )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
tr_swarm * s ;
2009-02-11 16:34:35 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2011-01-18 23:44:36 +00:00
2013-01-27 21:03:52 +00:00
s = tor - > swarm ;
ensureMgrTimersExist ( s - > manager ) ;
2009-02-11 16:34:35 +00:00
2013-01-27 21:03:52 +00:00
s - > isRunning = true ;
s - > maxPeers = tor - > maxConnectedPeers ;
s - > pieceSortState = PIECES_UNSORTED ;
2009-02-11 16:34:35 +00:00
2013-01-27 21:03:52 +00:00
rechokePulse ( 0 , 0 , s - > manager ) ;
2007-09-20 16:32:01 +00:00
}
2013-05-27 21:04:48 +00:00
static void removeAllPeers ( tr_swarm * ) ;
2007-09-29 06:37:03 +00:00
static void
2013-01-27 21:03:52 +00:00
stopSwarm ( tr_swarm * swarm )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
swarm - > isRunning = false ;
2007-10-02 02:01:57 +00:00
2013-01-27 21:03:52 +00:00
replicationFree ( swarm ) ;
invalidatePieceSorting ( swarm ) ;
2011-02-17 05:14:53 +00:00
2013-05-27 21:04:48 +00:00
removeAllPeers ( swarm ) ;
2007-10-02 02:01:57 +00:00
2013-01-27 21:03:52 +00:00
/* disconnect the handshakes. handshakeAbort calls handshakeDoneCB (),
* which removes the handshake from t - > outgoingHandshakes . . . */
while ( ! tr_ptrArrayEmpty ( & swarm - > outgoingHandshakes ) )
tr_handshakeAbort ( tr_ptrArrayNth ( & swarm - > outgoingHandshakes , 0 ) ) ;
2007-09-29 06:37:03 +00:00
}
2008-09-23 19:11:04 +00:00
2007-09-29 06:37:03 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerMgrStopTorrent ( tr_torrent * tor )
2007-09-29 06:37:03 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2009-01-13 21:00:05 +00:00
2013-01-27 21:03:52 +00:00
stopSwarm ( tor - > swarm ) ;
2007-09-20 16:32:01 +00:00
}
void
2012-12-05 17:29:46 +00:00
tr_peerMgrAddTorrent ( tr_peerMgr * manager , tr_torrent * tor )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
assert ( tor - > swarm = = NULL ) ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
tor - > swarm = swarmNew ( manager , tor ) ;
2007-09-20 16:32:01 +00:00
}
void
2012-12-05 17:29:46 +00:00
tr_peerMgrRemoveTorrent ( tr_torrent * tor )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
stopSwarm ( tor - > swarm ) ;
swarmFree ( tor - > swarm ) ;
2007-09-20 16:32:01 +00:00
}
2011-02-24 14:35:45 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerUpdateProgress ( tr_torrent * tor , tr_peer * peer )
2011-02-24 14:35:45 +00:00
{
2013-01-27 21:03:52 +00:00
const tr_bitfield * have = & peer - > have ;
2011-02-24 14:35:45 +00:00
2013-01-27 21:03:52 +00:00
if ( tr_bitfieldHasAll ( have ) )
2011-02-24 14:35:45 +00:00
{
2013-01-27 21:03:52 +00:00
peer - > progress = 1.0 ;
2011-02-24 14:35:45 +00:00
}
2013-01-27 21:03:52 +00:00
else if ( tr_bitfieldHasNone ( have ) )
2011-02-24 14:35:45 +00:00
{
2013-01-27 21:03:52 +00:00
peer - > progress = 0.0 ;
2011-02-24 14:35:45 +00:00
}
2013-01-27 21:03:52 +00:00
else
2011-02-24 14:35:45 +00:00
{
2013-01-27 21:03:52 +00:00
const float true_count = tr_bitfieldCountTrueBits ( have ) ;
2011-02-24 14:35:45 +00:00
2013-01-27 21:03:52 +00:00
if ( tr_torrentHasMetadata ( tor ) )
2012-07-01 02:00:02 +00:00
{
2013-01-27 21:03:52 +00:00
peer - > progress = true_count / tor - > info . pieceCount ;
2012-07-01 02:00:02 +00:00
}
2013-01-27 21:03:52 +00:00
else /* without pieceCount, this result is only a best guess... */
2012-07-01 02:00:02 +00:00
{
2013-01-27 21:03:52 +00:00
peer - > progress = true_count / ( have - > bit_count + 1 ) ;
2012-07-01 02:00:02 +00:00
}
2011-02-24 14:35:45 +00:00
}
2013-01-27 21:03:52 +00:00
/* clamp the progress range */
if ( peer - > progress < 0.0 )
peer - > progress = 0.0 ;
if ( peer - > progress > 1.0 )
peer - > progress = 1.0 ;
2012-07-01 02:00:02 +00:00
2013-01-27 21:03:52 +00:00
if ( peer - > atom & & ( peer - > progress > = 1.0 ) )
atomSetSeed ( tor - > swarm , peer - > atom ) ;
2011-02-24 14:35:45 +00:00
}
void
2012-12-05 17:29:46 +00:00
tr_peerMgrOnTorrentGotMetainfo ( tr_torrent * tor )
2011-02-24 14:35:45 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
int peerCount ;
tr_peer * * peers ;
2011-03-04 23:26:10 +00:00
2013-01-27 21:03:52 +00:00
/* the webseed list may have changed... */
rebuildWebseedArray ( tor - > swarm , tor ) ;
2012-10-05 22:04:08 +00:00
2013-01-27 21:03:52 +00:00
/* some peer_msgs' progress fields may not be accurate if we
didn ' t have the metadata before now . . . so refresh them all . . . */
peerCount = tr_ptrArraySize ( & tor - > swarm - > peers ) ;
peers = ( tr_peer * * ) tr_ptrArrayBase ( & tor - > swarm - > peers ) ;
for ( i = 0 ; i < peerCount ; + + i )
tr_peerUpdateProgress ( tor , peers [ i ] ) ;
2013-05-27 21:04:48 +00:00
/* update the bittorrent peers' willingnes... */
for ( i = 0 ; i < peerCount ; + + i )
{
tr_peerMsgsUpdateActive ( tr_peerMsgsCast ( peers [ i ] ) , TR_UP ) ;
tr_peerMsgsUpdateActive ( tr_peerMsgsCast ( peers [ i ] ) , TR_DOWN ) ;
}
2011-02-24 14:35:45 +00:00
}
2007-09-20 16:32:01 +00:00
void
2012-12-14 20:04:37 +00:00
tr_peerMgrTorrentAvailability ( const tr_torrent * tor ,
int8_t * tab ,
unsigned int tabCount )
2011-01-18 22:51:29 +00:00
{
2012-12-14 20:04:37 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2012-12-12 20:22:57 +00:00
assert ( tab ! = NULL ) ;
assert ( tabCount > 0 ) ;
2007-09-20 16:32:01 +00:00
2012-12-14 20:04:37 +00:00
memset ( tab , 0 , tabCount ) ;
if ( tr_torrentHasMetadata ( tor ) )
2007-09-20 16:32:01 +00:00
{
2012-12-14 20:04:37 +00:00
tr_piece_index_t i ;
2013-01-27 21:03:52 +00:00
const int peerCount = tr_ptrArraySize ( & tor - > swarm - > peers ) ;
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & tor - > swarm - > peers ) ;
2012-12-14 20:04:37 +00:00
const float interval = tor - > info . pieceCount / ( float ) tabCount ;
const bool isSeed = tr_cpGetStatus ( & tor - > completion ) = = TR_SEED ;
2011-01-18 22:51:29 +00:00
2012-12-14 20:04:37 +00:00
for ( i = 0 ; i < tabCount ; + + i )
2011-01-18 22:51:29 +00:00
{
2012-12-14 20:04:37 +00:00
const int piece = i * interval ;
2011-01-18 22:51:29 +00:00
2012-12-14 20:04:37 +00:00
if ( isSeed | | tr_cpPieceIsComplete ( & tor - > completion , piece ) )
2012-12-12 20:22:57 +00:00
{
2012-12-14 20:04:37 +00:00
tab [ i ] = - 1 ;
}
else if ( peerCount )
{
int j ;
for ( j = 0 ; j < peerCount ; + + j )
if ( tr_bitfieldHas ( & peers [ j ] - > have , piece ) )
+ + tab [ i ] ;
2011-01-18 22:51:29 +00:00
}
2007-09-20 16:32:01 +00:00
}
}
}
2011-03-28 16:31:05 +00:00
static bool
2012-12-05 17:29:46 +00:00
peerIsSeed ( const tr_peer * peer )
2007-09-27 03:03:38 +00:00
{
2013-02-04 16:23:33 +00:00
if ( peer - > progress > = 1.0 )
return true ;
2011-01-18 23:44:36 +00:00
2013-02-04 16:23:33 +00:00
if ( peer - > atom & & atomIsSeed ( peer - > atom ) )
return true ;
2007-09-29 06:37:03 +00:00
2013-02-04 16:23:33 +00:00
return false ;
2011-03-28 16:31:05 +00:00
}
2011-07-02 13:20:17 +00:00
/* count how many bytes we want that connected peers have */
2011-03-28 16:31:05 +00:00
uint64_t
2012-12-05 17:29:46 +00:00
tr_peerMgrGetDesiredAvailable ( const tr_torrent * tor )
2011-03-28 16:31:05 +00:00
{
2013-01-27 21:03:52 +00:00
size_t i ;
size_t n ;
uint64_t desiredAvailable ;
const tr_swarm * s = tor - > swarm ;
2011-03-28 16:31:05 +00:00
2013-01-27 21:03:52 +00:00
/* common shortcuts... */
2011-03-28 16:31:05 +00:00
2013-01-27 21:03:52 +00:00
if ( tr_torrentIsSeed ( s - > tor ) )
return 0 ;
2007-09-27 03:03:38 +00:00
2013-01-27 21:03:52 +00:00
if ( ! tr_torrentHasMetadata ( tor ) )
return 0 ;
2011-03-28 16:31:05 +00:00
2013-01-27 21:03:52 +00:00
n = tr_ptrArraySize ( & s - > peers ) ;
if ( n = = 0 )
{
return 0 ;
}
else
{
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & s - > peers ) ;
for ( i = 0 ; i < n ; + + i )
if ( peers [ i ] - > atom & & atomIsSeed ( peers [ i ] - > atom ) )
return tr_cpLeftUntilDone ( & tor - > completion ) ;
2011-03-28 16:31:05 +00:00
}
2013-01-27 21:03:52 +00:00
if ( ! s - > pieceReplication | | ! s - > pieceReplicationSize )
return 0 ;
2011-03-28 16:31:05 +00:00
2013-01-27 21:03:52 +00:00
/* do it the hard way */
2011-03-28 16:31:05 +00:00
2013-01-27 21:03:52 +00:00
desiredAvailable = 0 ;
for ( i = 0 , n = MIN ( tor - > info . pieceCount , s - > pieceReplicationSize ) ; i < n ; + + i )
if ( ! tor - > info . pieces [ i ] . dnd & & ( s - > pieceReplication [ i ] > 0 ) )
desiredAvailable + = tr_cpMissingBytesInPiece ( & s - > tor - > completion , i ) ;
2011-03-28 16:31:05 +00:00
2013-01-27 21:03:52 +00:00
assert ( desiredAvailable < = tor - > info . totalSize ) ;
return desiredAvailable ;
2007-09-27 03:03:38 +00:00
}
2007-09-20 16:32:01 +00:00
2010-07-04 06:07:21 +00:00
double *
2012-12-14 20:04:37 +00:00
tr_peerMgrWebSpeeds_KBps ( const tr_torrent * tor )
2008-06-10 01:38:12 +00:00
{
2012-12-30 22:06:45 +00:00
unsigned int i ;
2013-02-04 16:23:33 +00:00
tr_swarm * s ;
unsigned int n ;
2012-12-12 20:22:57 +00:00
double * ret = NULL ;
2012-12-14 20:04:37 +00:00
const uint64_t now = tr_time_msec ( ) ;
2008-06-10 01:38:12 +00:00
2012-12-14 20:04:37 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2012-12-12 20:22:57 +00:00
2013-01-27 21:03:52 +00:00
s = tor - > swarm ;
2013-02-04 16:23:33 +00:00
n = tr_ptrArraySize ( & s - > webseeds ) ;
ret = tr_new0 ( double , n ) ;
2012-12-12 20:22:57 +00:00
2013-01-27 21:03:52 +00:00
assert ( s - > manager ! = NULL ) ;
2013-02-04 16:23:33 +00:00
assert ( n = = tor - > info . webseedCount ) ;
2012-12-12 20:22:57 +00:00
2013-02-04 16:23:33 +00:00
for ( i = 0 ; i < n ; + + i )
2012-12-14 20:04:37 +00:00
{
2013-02-04 16:23:33 +00:00
unsigned int Bps = 0 ;
if ( tr_peerIsTransferringPieces ( tr_ptrArrayNth ( & s - > webseeds , i ) , now , TR_DOWN , & Bps ) )
2012-12-14 20:04:37 +00:00
ret [ i ] = Bps / ( double ) tr_speed_K ;
else
ret [ i ] = - 1.0 ;
2010-07-04 06:07:21 +00:00
}
2008-06-10 01:38:12 +00:00
2012-12-12 20:22:57 +00:00
return ret ;
2007-09-20 16:32:01 +00:00
}
struct tr_peer_stat *
2012-12-14 20:04:37 +00:00
tr_peerMgrPeerStats ( const tr_torrent * tor , int * setmeCount )
2007-09-20 16:32:01 +00:00
{
2012-12-14 20:04:37 +00:00
int i ;
2012-12-12 20:22:57 +00:00
int size = 0 ;
2012-12-14 20:04:37 +00:00
tr_peer_stat * ret ;
2013-01-27 21:03:52 +00:00
const tr_swarm * s ;
2013-02-04 16:23:33 +00:00
tr_peer * * peers ;
2012-12-14 20:04:37 +00:00
const time_t now = tr_time ( ) ;
const uint64_t now_msec = tr_time_msec ( ) ;
2012-12-12 20:22:57 +00:00
2012-12-14 20:04:37 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2013-01-27 21:03:52 +00:00
assert ( tor - > swarm - > manager ! = NULL ) ;
2012-12-12 20:22:57 +00:00
2013-01-27 21:03:52 +00:00
s = tor - > swarm ;
2013-02-04 16:23:33 +00:00
peers = ( tr_peer * * ) tr_ptrArrayBase ( & s - > peers ) ;
2013-01-27 21:03:52 +00:00
size = tr_ptrArraySize ( & s - > peers ) ;
2012-12-14 20:04:37 +00:00
ret = tr_new0 ( tr_peer_stat , size ) ;
2012-12-12 20:22:57 +00:00
2012-12-14 20:04:37 +00:00
for ( i = 0 ; i < size ; + + i )
{
char * pch ;
2013-02-04 16:23:33 +00:00
tr_peer * peer = peers [ i ] ;
tr_peerMsgs * msgs = PEER_MSGS ( peer ) ;
2012-12-14 20:04:37 +00:00
const struct peer_atom * atom = peer - > atom ;
tr_peer_stat * stat = ret + i ;
tr_address_to_string_with_buf ( & atom - > addr , stat - > addr , sizeof ( stat - > addr ) ) ;
2012-12-22 20:35:19 +00:00
tr_strlcpy ( stat - > client , tr_quark_get_string ( peer - > client , NULL ) , sizeof ( stat - > client ) ) ;
2012-12-14 20:04:37 +00:00
stat - > port = ntohs ( peer - > atom - > port ) ;
stat - > from = atom - > fromFirst ;
stat - > progress = peer - > progress ;
2013-02-04 16:23:33 +00:00
stat - > isUTP = tr_peerMsgsIsUtpConnection ( msgs ) ;
stat - > isEncrypted = tr_peerMsgsIsEncrypted ( msgs ) ;
2012-12-14 20:04:37 +00:00
stat - > rateToPeer_KBps = toSpeedKBps ( tr_peerGetPieceSpeed_Bps ( peer , now_msec , TR_CLIENT_TO_PEER ) ) ;
stat - > rateToClient_KBps = toSpeedKBps ( tr_peerGetPieceSpeed_Bps ( peer , now_msec , TR_PEER_TO_CLIENT ) ) ;
2013-02-04 16:23:33 +00:00
stat - > peerIsChoked = tr_peerMsgsIsPeerChoked ( msgs ) ;
stat - > peerIsInterested = tr_peerMsgsIsPeerInterested ( msgs ) ;
stat - > clientIsChoked = tr_peerMsgsIsClientChoked ( msgs ) ;
stat - > clientIsInterested = tr_peerMsgsIsClientInterested ( msgs ) ;
stat - > isIncoming = tr_peerMsgsIsIncomingConnection ( msgs ) ;
2013-05-27 21:04:48 +00:00
stat - > isDownloadingFrom = tr_peerMsgsIsActive ( msgs , TR_PEER_TO_CLIENT ) ;
stat - > isUploadingTo = tr_peerMsgsIsActive ( msgs , TR_CLIENT_TO_PEER ) ;
2012-12-14 20:04:37 +00:00
stat - > isSeed = peerIsSeed ( peer ) ;
stat - > blocksToPeer = tr_historyGet ( & peer - > blocksSentToPeer , now , CANCEL_HISTORY_SEC ) ;
stat - > blocksToClient = tr_historyGet ( & peer - > blocksSentToClient , now , CANCEL_HISTORY_SEC ) ;
stat - > cancelsToPeer = tr_historyGet ( & peer - > cancelsSentToPeer , now , CANCEL_HISTORY_SEC ) ;
stat - > cancelsToClient = tr_historyGet ( & peer - > cancelsSentToClient , now , CANCEL_HISTORY_SEC ) ;
stat - > pendingReqsToPeer = peer - > pendingReqsToPeer ;
stat - > pendingReqsToClient = peer - > pendingReqsToClient ;
pch = stat - > flagStr ;
if ( stat - > isUTP ) * pch + + = ' T ' ;
2013-02-04 16:23:33 +00:00
if ( s - > optimistic = = msgs ) * pch + + = ' O ' ;
2012-12-14 20:04:37 +00:00
if ( stat - > isDownloadingFrom ) * pch + + = ' D ' ;
else if ( stat - > clientIsInterested ) * pch + + = ' d ' ;
if ( stat - > isUploadingTo ) * pch + + = ' U ' ;
else if ( stat - > peerIsInterested ) * pch + + = ' u ' ;
if ( ! stat - > clientIsChoked & & ! stat - > clientIsInterested ) * pch + + = ' K ' ;
if ( ! stat - > peerIsChoked & & ! stat - > peerIsInterested ) * pch + + = ' ? ' ;
if ( stat - > isEncrypted ) * pch + + = ' E ' ;
if ( stat - > from = = TR_PEER_FROM_DHT ) * pch + + = ' H ' ;
else if ( stat - > from = = TR_PEER_FROM_PEX ) * pch + + = ' X ' ;
if ( stat - > isIncoming ) * pch + + = ' I ' ;
* pch = ' \0 ' ;
2012-12-12 20:22:57 +00:00
}
2007-09-29 06:37:03 +00:00
2012-12-12 20:22:57 +00:00
* setmeCount = size ;
return ret ;
2007-09-20 16:32:01 +00:00
}
2011-04-29 23:25:12 +00:00
/***
* * * *
* * * *
* * */
2007-09-20 16:32:01 +00:00
2010-09-25 00:34:15 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerMgrClearInterest ( tr_torrent * tor )
2010-09-25 00:34:15 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
tr_swarm * s = tor - > swarm ;
const int peerCount = tr_ptrArraySize ( & s - > peers ) ;
2010-09-25 00:34:15 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2010-09-25 00:34:15 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < peerCount ; + + i )
2013-02-04 16:23:33 +00:00
tr_peerMsgsSetInterested ( tr_ptrArrayNth ( & s - > peers , i ) , false ) ;
2010-09-25 00:34:15 +00:00
}
2010-03-08 04:29:58 +00:00
/* does this peer have any pieces that we want? */
2011-03-22 15:19:54 +00:00
static bool
2012-12-12 20:22:57 +00:00
isPeerInteresting ( tr_torrent * const tor ,
const bool * const piece_is_interesting ,
const tr_peer * const peer )
2010-03-08 04:29:58 +00:00
{
2012-12-12 20:22:57 +00:00
tr_piece_index_t i , n ;
2010-03-08 04:29:58 +00:00
2012-12-12 20:22:57 +00:00
/* these cases should have already been handled by the calling code... */
assert ( ! tr_torrentIsSeed ( tor ) ) ;
assert ( tr_torrentIsPieceTransferAllowed ( tor , TR_PEER_TO_CLIENT ) ) ;
2010-03-08 04:29:58 +00:00
2012-12-12 20:22:57 +00:00
if ( peerIsSeed ( peer ) )
return true ;
2010-03-08 04:29:58 +00:00
2012-12-12 20:22:57 +00:00
for ( i = 0 , n = tor - > info . pieceCount ; i < n ; + + i )
if ( piece_is_interesting [ i ] & & tr_bitfieldHas ( & peer - > have , i ) )
return true ;
2010-03-08 04:29:58 +00:00
2012-12-12 20:22:57 +00:00
return false ;
2010-03-08 04:29:58 +00:00
}
2011-04-29 23:25:12 +00:00
typedef enum
{
2013-01-27 21:03:52 +00:00
RECHOKE_STATE_GOOD ,
RECHOKE_STATE_UNTESTED ,
RECHOKE_STATE_BAD
2011-04-29 23:25:12 +00:00
}
tr_rechoke_state ;
struct tr_rechoke_info
{
2013-01-27 21:03:52 +00:00
tr_peer * peer ;
int salt ;
int rechoke_state ;
2011-04-29 23:25:12 +00:00
} ;
static int
2012-12-05 17:29:46 +00:00
compare_rechoke_info ( const void * va , const void * vb )
2011-04-29 23:25:12 +00:00
{
2013-01-27 21:03:52 +00:00
const struct tr_rechoke_info * a = va ;
const struct tr_rechoke_info * b = vb ;
2011-04-29 23:25:12 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > rechoke_state ! = b - > rechoke_state )
return a - > rechoke_state - b - > rechoke_state ;
2011-04-29 23:25:12 +00:00
2013-01-27 21:03:52 +00:00
return a - > salt - b - > salt ;
2011-04-29 23:25:12 +00:00
}
2010-03-08 04:29:58 +00:00
/* determines who we send "interested" messages to */
static void
2013-01-27 21:03:52 +00:00
rechokeDownloads ( tr_swarm * s )
{
int i ;
int maxPeers = 0 ;
int rechoke_count = 0 ;
struct tr_rechoke_info * rechoke = NULL ;
const int MIN_INTERESTING_PEERS = 5 ;
const int peerCount = tr_ptrArraySize ( & s - > peers ) ;
const time_t now = tr_time ( ) ;
2010-10-01 18:16:01 +00:00
2013-01-27 21:03:52 +00:00
/* some cases where this function isn't necessary */
if ( tr_torrentIsSeed ( s - > tor ) )
return ;
if ( ! tr_torrentIsPieceTransferAllowed ( s - > tor , TR_PEER_TO_CLIENT ) )
return ;
2010-03-08 04:29:58 +00:00
2013-01-27 21:03:52 +00:00
/* decide HOW MANY peers to be interested in */
{
int blocks = 0 ;
int cancels = 0 ;
time_t timeSinceCancel ;
2011-05-10 03:50:54 +00:00
2013-01-27 21:03:52 +00:00
/* Count up how many blocks & cancels each peer has.
*
* There are two situations where we send out cancels - -
*
* 1. We ' ve got unresponsive peers , which is handled by deciding
* - which - peers to be interested in .
*
* 2. We ' ve hit our bandwidth cap , which is handled by deciding
* - how many - peers to be interested in .
*
* We ' re working on 2. here , so we need to ignore unresponsive
* peers in our calculations lest they confuse Transmission into
* thinking it ' s hit its bandwidth cap .
*/
for ( i = 0 ; i < peerCount ; + + i )
{
const tr_peer * peer = tr_ptrArrayNth ( & s - > peers , i ) ;
const int b = tr_historyGet ( & peer - > blocksSentToClient , now , CANCEL_HISTORY_SEC ) ;
const int c = tr_historyGet ( & peer - > cancelsSentToPeer , now , CANCEL_HISTORY_SEC ) ;
if ( b = = 0 ) /* ignore unresponsive peers, as described above */
continue ;
blocks + = b ;
cancels + = c ;
}
if ( cancels > 0 )
{
/* cancelRate: of the block requests we've recently made, the percentage we cancelled.
* higher values indicate more congestion . */
const double cancelRate = cancels / ( double ) ( cancels + blocks ) ;
const double mult = 1 - MIN ( cancelRate , 0.5 ) ;
maxPeers = s - > interestedCount * mult ;
tordbg ( s , " cancel rate is %.3f -- reducing the "
" number of peers we're interested in by %.0f percent " ,
cancelRate , mult * 100 ) ;
s - > lastCancel = now ;
}
timeSinceCancel = now - s - > lastCancel ;
if ( timeSinceCancel )
{
const int maxIncrease = 15 ;
const time_t maxHistory = 2 * CANCEL_HISTORY_SEC ;
const double mult = MIN ( timeSinceCancel , maxHistory ) / ( double ) maxHistory ;
const int inc = maxIncrease * mult ;
maxPeers = s - > maxPeers + inc ;
tordbg ( s , " time since last cancel is %li -- increasing the "
" number of peers we're interested in by %d " ,
timeSinceCancel , inc ) ;
}
}
/* don't let the previous section's number tweaking go too far... */
if ( maxPeers < MIN_INTERESTING_PEERS )
maxPeers = MIN_INTERESTING_PEERS ;
if ( maxPeers > s - > tor - > maxConnectedPeers )
maxPeers = s - > tor - > maxConnectedPeers ;
s - > maxPeers = maxPeers ;
if ( peerCount > 0 )
{
bool * piece_is_interesting ;
const tr_torrent * const tor = s - > tor ;
const int n = tor - > info . pieceCount ;
/* build a bitfield of interesting pieces... */
piece_is_interesting = tr_new ( bool , n ) ;
for ( i = 0 ; i < n ; i + + )
piece_is_interesting [ i ] = ! tor - > info . pieces [ i ] . dnd & & ! tr_cpPieceIsComplete ( & tor - > completion , i ) ;
/* decide WHICH peers to be interested in (based on their cancel-to-block ratio) */
for ( i = 0 ; i < peerCount ; + + i )
2011-04-29 23:25:12 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peer * peer = tr_ptrArrayNth ( & s - > peers , i ) ;
2011-05-10 03:50:54 +00:00
2013-01-27 21:03:52 +00:00
if ( ! isPeerInteresting ( s - > tor , piece_is_interesting , peer ) )
2011-05-10 03:50:54 +00:00
{
2013-02-04 16:23:33 +00:00
tr_peerMsgsSetInterested ( PEER_MSGS ( peer ) , false ) ;
2011-05-10 03:50:54 +00:00
}
2013-01-27 21:03:52 +00:00
else
2011-05-10 03:50:54 +00:00
{
2013-01-27 21:03:52 +00:00
tr_rechoke_state rechoke_state ;
const int blocks = tr_historyGet ( & peer - > blocksSentToClient , now , CANCEL_HISTORY_SEC ) ;
const int cancels = tr_historyGet ( & peer - > cancelsSentToPeer , now , CANCEL_HISTORY_SEC ) ;
if ( ! blocks & & ! cancels )
rechoke_state = RECHOKE_STATE_UNTESTED ;
else if ( ! cancels )
rechoke_state = RECHOKE_STATE_GOOD ;
else if ( ! blocks )
rechoke_state = RECHOKE_STATE_BAD ;
else if ( ( cancels * 10 ) < blocks )
rechoke_state = RECHOKE_STATE_GOOD ;
else
rechoke_state = RECHOKE_STATE_BAD ;
if ( rechoke = = NULL )
rechoke = tr_new ( struct tr_rechoke_info , peerCount ) ;
rechoke [ rechoke_count ] . peer = peer ;
rechoke [ rechoke_count ] . rechoke_state = rechoke_state ;
rechoke [ rechoke_count ] . salt = tr_cryptoWeakRandInt ( INT_MAX ) ;
rechoke_count + + ;
2011-05-10 03:50:54 +00:00
}
2010-03-17 17:07:40 +00:00
2011-04-29 23:25:12 +00:00
}
2010-03-08 04:29:58 +00:00
2013-01-27 21:03:52 +00:00
tr_free ( piece_is_interesting ) ;
2010-03-08 04:29:58 +00:00
}
2013-01-27 21:03:52 +00:00
/* now that we know which & how many peers to be interested in... update the peer interest */
qsort ( rechoke , rechoke_count , sizeof ( struct tr_rechoke_info ) , compare_rechoke_info ) ;
s - > interestedCount = MIN ( maxPeers , rechoke_count ) ;
for ( i = 0 ; i < rechoke_count ; + + i )
2013-02-04 16:23:33 +00:00
tr_peerMsgsSetInterested ( PEER_MSGS ( rechoke [ i ] . peer ) , i < s - > interestedCount ) ;
2010-03-17 17:07:40 +00:00
2013-01-27 21:03:52 +00:00
/* cleanup */
tr_free ( rechoke ) ;
2010-03-08 04:29:58 +00:00
}
/**
* * *
* */
2007-10-03 16:42:43 +00:00
struct ChokeData
2007-09-20 16:32:01 +00:00
{
2013-02-04 16:23:33 +00:00
bool isInterested ;
bool wasChoked ;
bool isChoked ;
int rate ;
int salt ;
tr_peerMsgs * msgs ;
2007-10-03 16:42:43 +00:00
} ;
2007-09-20 16:32:01 +00:00
static int
2012-12-05 17:29:46 +00:00
compareChoke ( const void * va , const void * vb )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
const struct ChokeData * a = va ;
const struct ChokeData * b = vb ;
2008-06-27 02:42:44 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > rate ! = b - > rate ) /* prefer higher overall speeds */
return a - > rate > b - > rate ? - 1 : 1 ;
2008-11-15 00:46:51 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > wasChoked ! = b - > wasChoked ) /* prefer unchoked */
return a - > wasChoked ? 1 : - 1 ;
2008-06-27 02:42:44 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > salt ! = b - > salt ) /* random order */
return a - > salt - b - > salt ;
2010-06-27 01:24:48 +00:00
2013-01-27 21:03:52 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
2010-03-06 14:56:15 +00:00
/* is this a new connection? */
2013-02-04 16:23:33 +00:00
static bool
isNew ( const tr_peerMsgs * msgs )
2008-01-11 02:09:20 +00:00
{
2013-02-04 16:23:33 +00:00
return ( msgs ! = NULL ) & & ( tr_peerMsgsGetConnectionAge ( msgs ) < 45 ) ;
2008-01-11 02:09:20 +00:00
}
2010-06-23 04:36:16 +00:00
/* get a rate for deciding which peers to choke and unchoke. */
static int
2012-12-05 17:29:46 +00:00
getRate ( const tr_torrent * tor , struct peer_atom * atom , uint64_t now )
2010-06-23 04:36:16 +00:00
{
2013-01-27 21:03:52 +00:00
unsigned int Bps ;
2010-06-23 04:36:16 +00:00
2013-01-27 21:03:52 +00:00
if ( tr_torrentIsSeed ( tor ) )
Bps = tr_peerGetPieceSpeed_Bps ( atom - > peer , now , TR_CLIENT_TO_PEER ) ;
2010-06-23 04:36:16 +00:00
2013-01-27 21:03:52 +00:00
/* downloading a private torrent... take upload speed into account
* because there may only be a small window of opportunity to share */
else if ( tr_torrentIsPrivate ( tor ) )
Bps = tr_peerGetPieceSpeed_Bps ( atom - > peer , now , TR_PEER_TO_CLIENT )
+ tr_peerGetPieceSpeed_Bps ( atom - > peer , now , TR_CLIENT_TO_PEER ) ;
2010-06-23 04:36:16 +00:00
2013-01-27 21:03:52 +00:00
/* downloading a public torrent */
else
Bps = tr_peerGetPieceSpeed_Bps ( atom - > peer , now , TR_PEER_TO_CLIENT ) ;
2010-06-23 04:36:16 +00:00
2013-01-27 21:03:52 +00:00
/* convert it to bytes per second */
return Bps ;
2010-06-23 04:36:16 +00:00
}
2011-03-22 15:19:54 +00:00
static inline bool
2012-12-05 17:29:46 +00:00
isBandwidthMaxedOut ( const tr_bandwidth * b ,
const uint64_t now_msec , tr_direction dir )
2010-09-19 01:04:49 +00:00
{
2013-01-27 21:03:52 +00:00
if ( ! tr_bandwidthIsLimited ( b , dir ) )
{
return false ;
}
else
{
const unsigned int got = tr_bandwidthGetPieceSpeed_Bps ( b , now_msec , dir ) ;
const unsigned int want = tr_bandwidthGetDesiredSpeed_Bps ( b , dir ) ;
return got > = want ;
2010-09-19 01:04:49 +00:00
}
}
2007-09-20 16:32:01 +00:00
static void
2013-01-27 21:03:52 +00:00
rechokeUploads ( tr_swarm * s , const uint64_t now )
{
int i , size , unchokedInterested ;
const int peerCount = tr_ptrArraySize ( & s - > peers ) ;
tr_peer * * peers = ( tr_peer * * ) tr_ptrArrayBase ( & s - > peers ) ;
struct ChokeData * choke = tr_new0 ( struct ChokeData , peerCount ) ;
const tr_session * session = s - > manager - > session ;
const int chokeAll = ! tr_torrentIsPieceTransferAllowed ( s - > tor , TR_CLIENT_TO_PEER ) ;
const bool isMaxedOut = isBandwidthMaxedOut ( & s - > tor - > bandwidth , now , TR_UP ) ;
assert ( swarmIsLocked ( s ) ) ;
/* an optimistic unchoke peer's "optimistic"
* state lasts for N calls to rechokeUploads ( ) . */
if ( s - > optimisticUnchokeTimeScaler > 0 )
s - > optimisticUnchokeTimeScaler - - ;
else
s - > optimistic = NULL ;
2010-10-13 03:56:25 +00:00
2013-01-27 21:03:52 +00:00
/* sort the peers by preference and rate */
for ( i = 0 , size = 0 ; i < peerCount ; + + i )
2007-09-22 00:22:10 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peer * peer = peers [ i ] ;
2013-02-04 16:23:33 +00:00
tr_peerMsgs * msgs = PEER_MSGS ( peer ) ;
2013-01-27 21:03:52 +00:00
struct peer_atom * atom = peer - > atom ;
2008-12-02 19:46:51 +00:00
2013-01-27 21:03:52 +00:00
if ( peerIsSeed ( peer ) ) /* choke seeds and partial seeds */
2008-12-02 19:46:51 +00:00
{
2013-02-04 16:23:33 +00:00
tr_peerMsgsSetChoke ( PEER_MSGS ( peer ) , true ) ;
2008-12-02 19:46:51 +00:00
}
2013-01-27 21:03:52 +00:00
else if ( chokeAll ) /* choke everyone if we're not uploading */
2008-12-02 19:46:51 +00:00
{
2013-02-04 16:23:33 +00:00
tr_peerMsgsSetChoke ( PEER_MSGS ( peer ) , true ) ;
2008-12-02 19:46:51 +00:00
}
2013-02-04 16:23:33 +00:00
else if ( msgs ! = s - > optimistic )
2008-12-02 19:46:51 +00:00
{
2013-01-27 21:03:52 +00:00
struct ChokeData * n = & choke [ size + + ] ;
2013-02-04 16:23:33 +00:00
n - > msgs = msgs ;
n - > isInterested = tr_peerMsgsIsPeerInterested ( msgs ) ;
n - > wasChoked = tr_peerMsgsIsPeerChoked ( msgs ) ;
2013-01-27 21:03:52 +00:00
n - > rate = getRate ( s - > tor , atom , now ) ;
n - > salt = tr_cryptoWeakRandInt ( INT_MAX ) ;
n - > isChoked = true ;
2007-11-18 06:15:13 +00:00
}
2007-09-20 16:32:01 +00:00
}
2007-09-22 00:22:10 +00:00
2013-01-27 21:03:52 +00:00
qsort ( choke , size , sizeof ( struct ChokeData ) , compareChoke ) ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
/**
* Reciprocation and number of uploads capping is managed by unchoking
* the N peers which have the best upload rate and are interested .
* This maximizes the client ' s download rate . These N peers are
* referred to as downloaders , because they are interested in downloading
* from the client .
*
* Peers which have a better upload rate ( as compared to the downloaders )
* but aren ' t interested get unchoked . If they become interested , the
* downloader with the worst upload rate gets choked . If a client has
* a complete file , it uses its upload rate rather than its download
* rate to decide which peers to unchoke .
*
* If our bandwidth is maxed out , don ' t unchoke any more peers .
*/
unchokedInterested = 0 ;
for ( i = 0 ; i < size & & unchokedInterested < session - > uploadSlotsPerTorrent ; + + i )
{
choke [ i ] . isChoked = isMaxedOut ? choke [ i ] . wasChoked : false ;
if ( choke [ i ] . isInterested )
+ + unchokedInterested ;
2007-11-18 06:15:13 +00:00
}
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
/* optimistic unchoke */
if ( ! s - > optimistic & & ! isMaxedOut & & ( i < size ) )
2008-01-11 02:09:20 +00:00
{
2013-01-27 21:03:52 +00:00
int n ;
struct ChokeData * c ;
tr_ptrArray randPool = TR_PTR_ARRAY_INIT ;
2008-06-03 04:29:56 +00:00
2013-01-27 21:03:52 +00:00
for ( ; i < size ; + + i )
2008-01-11 02:09:20 +00:00
{
2013-01-27 21:03:52 +00:00
if ( choke [ i ] . isInterested )
2008-06-03 04:29:56 +00:00
{
2013-02-04 16:23:33 +00:00
const tr_peerMsgs * msgs = choke [ i ] . msgs ;
2013-01-27 21:03:52 +00:00
int x = 1 , y ;
2013-02-04 16:23:33 +00:00
if ( isNew ( msgs ) ) x * = 3 ;
2013-01-27 21:03:52 +00:00
for ( y = 0 ; y < x ; + + y )
tr_ptrArrayAppend ( & randPool , & choke [ i ] ) ;
2008-06-03 04:29:56 +00:00
}
2008-01-11 02:09:20 +00:00
}
2008-06-03 04:29:56 +00:00
2013-01-27 21:03:52 +00:00
if ( ( n = tr_ptrArraySize ( & randPool ) ) )
2008-06-03 04:29:56 +00:00
{
2013-01-27 21:03:52 +00:00
c = tr_ptrArrayNth ( & randPool , tr_cryptoWeakRandInt ( n ) ) ;
c - > isChoked = false ;
2013-02-04 16:23:33 +00:00
s - > optimistic = c - > msgs ;
2013-01-27 21:03:52 +00:00
s - > optimisticUnchokeTimeScaler = OPTIMISTIC_UNCHOKE_MULTIPLIER ;
2008-06-03 04:29:56 +00:00
}
2013-01-27 21:03:52 +00:00
tr_ptrArrayDestruct ( & randPool , NULL ) ;
2007-09-20 16:32:01 +00:00
}
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < size ; + + i )
2013-02-04 16:23:33 +00:00
tr_peerMsgsSetChoke ( choke [ i ] . msgs , choke [ i ] . isChoked ) ;
2007-09-20 16:32:01 +00:00
2013-01-27 21:03:52 +00:00
/* cleanup */
tr_free ( choke ) ;
2007-09-20 16:32:01 +00:00
}
2009-12-10 05:52:46 +00:00
static void
2012-12-05 17:29:46 +00:00
rechokePulse ( int foo UNUSED , short bar UNUSED , void * vmgr )
2007-09-20 16:32:01 +00:00
{
2013-01-27 21:03:52 +00:00
tr_torrent * tor = NULL ;
tr_peerMgr * mgr = vmgr ;
const uint64_t now = tr_time_msec ( ) ;
2011-01-29 18:59:23 +00:00
2013-01-27 21:03:52 +00:00
managerLock ( mgr ) ;
2008-09-23 19:11:04 +00:00
2013-01-27 21:03:52 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
{
2013-05-27 21:04:48 +00:00
if ( tor - > isRunning & & tor - > peerCount )
2013-01-27 21:03:52 +00:00
{
tr_swarm * s = tor - > swarm ;
2013-05-27 21:04:48 +00:00
rechokeUploads ( s , now ) ;
rechokeDownloads ( s ) ;
2010-03-06 14:56:15 +00:00
}
}
2009-02-04 16:58:52 +00:00
2013-01-27 21:03:52 +00:00
tr_timerAddMsec ( mgr - > rechokeTimer , RECHOKE_PERIOD_MSEC ) ;
managerUnlock ( mgr ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-22 00:22:10 +00:00
2007-09-30 23:55:49 +00:00
/***
* * * *
2007-10-13 13:54:05 +00:00
* * * * Life and Death
2007-09-30 23:55:49 +00:00
* * * *
* * */
2011-03-22 15:19:54 +00:00
static bool
2013-01-27 21:03:52 +00:00
shouldPeerBeClosed ( const tr_swarm * s ,
2009-01-20 15:47:25 +00:00
const tr_peer * peer ,
2009-11-19 03:00:20 +00:00
int peerCount ,
2012-12-05 17:29:46 +00:00
const time_t now )
2007-09-30 23:55:49 +00:00
{
2013-01-27 21:03:52 +00:00
const tr_torrent * tor = s - > tor ;
const struct peer_atom * atom = peer - > atom ;
2007-09-22 14:18:52 +00:00
2013-01-27 21:03:52 +00:00
/* if it's marked for purging, close it */
if ( peer - > doPurge )
2008-09-23 19:11:04 +00:00
{
2013-01-27 21:03:52 +00:00
tordbg ( s , " purging peer %s because its doPurge flag is set " ,
tr_atomAddrStr ( atom ) ) ;
return true ;
2007-10-13 13:54:05 +00:00
}
2007-09-29 06:37:03 +00:00
2013-01-27 21:03:52 +00:00
/* disconnect if we're both seeds and enough time has passed for PEX */
if ( tr_torrentIsSeed ( tor ) & & peerIsSeed ( peer ) )
return ! tr_torrentAllowsPex ( tor ) | | ( now - atom - > time > = 30 ) ;
/* disconnect if it's been too long since piece data has been transferred.
* this is on a sliding scale based on number of available peers . . . */
{
const int relaxStrictnessIfFewerThanN = ( int ) ( ( getMaxPeerCount ( tor ) * 0.9 ) + 0.5 ) ;
/* if we have >= relaxIfFewerThan, strictness is 100%.
* if we have zero connections , strictness is 0 % */
const float strictness = peerCount > = relaxStrictnessIfFewerThanN
? 1.0
: peerCount / ( float ) relaxStrictnessIfFewerThanN ;
const int lo = MIN_UPLOAD_IDLE_SECS ;
const int hi = MAX_UPLOAD_IDLE_SECS ;
const int limit = hi - ( ( hi - lo ) * strictness ) ;
const int idleTime = now - MAX ( atom - > time , atom - > piece_data_time ) ;
2012-12-05 17:29:46 +00:00
/*fprintf (stderr, "strictness is %.3f, limit is %d seconds... time since connect is %d, time since piece is %d ... idleTime is %d, doPurge is %d\n", (double)strictness, limit, (int)(now - atom->time), (int)(now - atom->piece_data_time), idleTime, idleTime > limit);*/
2013-01-27 21:03:52 +00:00
if ( idleTime > limit )
{
tordbg ( s , " purging peer %s because it's been %d secs since we shared anything " ,
tr_atomAddrStr ( atom ) , idleTime ) ;
return true ;
}
}
2007-09-22 14:18:52 +00:00
2013-01-27 21:03:52 +00:00
return false ;
2007-10-13 13:54:05 +00:00
}
static tr_peer * *
2013-01-27 21:03:52 +00:00
getPeersToClose ( tr_swarm * s , const time_t now_sec , int * setmeSize )
2007-10-13 13:54:05 +00:00
{
2013-01-27 21:03:52 +00:00
int i , peerCount , outsize ;
struct tr_peer * * ret = NULL ;
tr_peer * * peers = ( tr_peer * * ) tr_ptrArrayPeek ( & s - > peers , & peerCount ) ;
2007-10-13 13:54:05 +00:00
2013-01-27 21:03:52 +00:00
assert ( swarmIsLocked ( s ) ) ;
2007-10-13 13:54:05 +00:00
2013-01-27 21:03:52 +00:00
for ( i = outsize = 0 ; i < peerCount ; + + i )
{
if ( shouldPeerBeClosed ( s , peers [ i ] , peerCount , now_sec ) )
{
if ( ret = = NULL )
ret = tr_new ( tr_peer * , peerCount ) ;
ret [ outsize + + ] = peers [ i ] ;
2011-04-27 19:06:06 +00:00
}
}
2007-10-13 13:54:05 +00:00
2013-01-27 21:03:52 +00:00
* setmeSize = outsize ;
return ret ;
2007-09-22 14:18:52 +00:00
}
2008-08-16 05:12:55 +00:00
static int
2012-12-05 17:29:46 +00:00
getReconnectIntervalSecs ( const struct peer_atom * atom , const time_t now )
2008-08-16 05:12:55 +00:00
{
2013-01-17 20:08:21 +00:00
int sec ;
const bool unreachable = ( atom - > flags2 & MYFLAG_UNREACHABLE ) ! = 0 ;
2008-08-16 05:12:55 +00:00
2013-01-17 20:08:21 +00:00
/* if we were recently connected to this peer and transferring piece
* data , try to reconnect to them sooner rather that later - - we don ' t
* want network troubles to get in the way of a good peer . */
if ( ! unreachable & & ( ( now - atom - > piece_data_time ) < = ( MINIMUM_RECONNECT_INTERVAL_SECS * 2 ) ) )
sec = MINIMUM_RECONNECT_INTERVAL_SECS ;
2008-09-05 05:14:49 +00:00
2013-01-17 20:08:21 +00:00
/* otherwise, the interval depends on how many times we've tried
* and failed to connect to the peer */
else
{
int step = atom - > numFails ;
2008-09-05 05:14:49 +00:00
2013-01-17 20:08:21 +00:00
/* penalize peers that were unreachable the last time we tried */
if ( unreachable )
step + = 2 ;
switch ( step )
{
case 0 : sec = 0 ; break ;
case 1 : sec = 10 ; break ;
case 2 : sec = 60 * 2 ; break ;
case 3 : sec = 60 * 15 ; break ;
case 4 : sec = 60 * 30 ; break ;
case 5 : sec = 60 * 60 ; break ;
default : sec = 60 * 120 ; break ;
}
2008-12-05 22:56:19 +00:00
}
2008-08-16 05:12:55 +00:00
2013-01-17 20:08:21 +00:00
dbgmsg ( " reconnect interval for %s is %d seconds " , tr_atomAddrStr ( atom ) , sec ) ;
return sec ;
2007-09-30 23:55:49 +00:00
}
2007-09-22 14:18:52 +00:00
2011-02-17 05:14:53 +00:00
static void
2013-01-27 21:03:52 +00:00
removePeer ( tr_swarm * s , tr_peer * peer )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peer * removed ;
struct peer_atom * atom = peer - > atom ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
assert ( swarmIsLocked ( s ) ) ;
assert ( atom ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
atom - > time = tr_time ( ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
removed = tr_ptrArrayRemoveSorted ( & s - > peers , peer , peerCompare ) ;
2013-05-27 21:04:48 +00:00
- - s - > tor - > peerCount ;
- - s - > tor - > peerFromCount [ atom - > fromFirst ] ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
if ( replicationExists ( s ) )
tr_decrReplicationFromBitfield ( s , & peer - > have ) ;
2011-02-17 05:14:53 +00:00
2013-01-27 21:03:52 +00:00
assert ( removed = = peer ) ;
2013-05-27 21:04:48 +00:00
assert ( s - > tor - > peerCount = = tr_ptrArraySize ( & s - > peers ) ) ;
assert ( s - > tor - > peerFromCount [ atom - > fromFirst ] > = 0 ) ;
2013-02-04 16:23:33 +00:00
tr_peerFree ( removed ) ;
2011-02-17 05:14:53 +00:00
}
2009-01-20 15:47:25 +00:00
static void
2013-01-27 21:03:52 +00:00
closePeer ( tr_swarm * s , tr_peer * peer )
2009-01-20 15:47:25 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom ;
2009-01-20 15:47:25 +00:00
2013-01-27 21:03:52 +00:00
assert ( s ! = NULL ) ;
assert ( peer ! = NULL ) ;
2009-01-20 15:47:25 +00:00
2013-01-27 21:03:52 +00:00
atom = peer - > atom ;
2009-05-09 06:08:21 +00:00
2013-01-27 21:03:52 +00:00
/* if we transferred piece data, then they might be good peers,
so reset their ` numFails ' weight to zero . otherwise we connected
to them fruitlessly , so mark it as another fail */
if ( atom - > piece_data_time )
{
tordbg ( s , " resetting atom %s numFails to 0 " , tr_atomAddrStr ( atom ) ) ;
atom - > numFails = 0 ;
}
else
{
+ + atom - > numFails ;
tordbg ( s , " incremented atom %s numFails to %d " , tr_atomAddrStr ( atom ) , ( int ) atom - > numFails ) ;
2010-04-20 21:54:03 +00:00
}
2009-01-20 15:47:25 +00:00
2013-02-04 16:23:33 +00:00
tordbg ( s , " removing bad peer %s " , tr_atomAddrStr ( peer - > atom ) ) ;
2013-01-27 21:03:52 +00:00
removePeer ( s , peer ) ;
2009-01-20 15:47:25 +00:00
}
2011-02-17 05:14:53 +00:00
static void
2013-01-27 21:03:52 +00:00
removeAllPeers ( tr_swarm * s )
2011-02-17 05:14:53 +00:00
{
2013-01-27 21:03:52 +00:00
while ( ! tr_ptrArrayEmpty ( & s - > peers ) )
removePeer ( s , tr_ptrArrayNth ( & s - > peers , 0 ) ) ;
2013-05-27 21:04:48 +00:00
assert ( ! s - > tor - > peerCount ) ;
2011-02-17 05:14:53 +00:00
}
2009-02-04 16:58:52 +00:00
static void
2013-01-27 21:03:52 +00:00
closeBadPeers ( tr_swarm * s , const time_t now_sec )
2007-09-30 23:55:49 +00:00
{
2013-01-27 21:03:52 +00:00
if ( ! tr_ptrArrayEmpty ( & s - > peers ) )
2011-04-07 20:15:49 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
int peerCount ;
struct tr_peer * * peers ;
peers = getPeersToClose ( s , now_sec , & peerCount ) ;
for ( i = 0 ; i < peerCount ; + + i )
closePeer ( s , peers [ i ] ) ;
tr_free ( peers ) ;
2011-04-07 20:15:49 +00:00
}
2009-02-04 16:58:52 +00:00
}
2007-09-30 23:55:49 +00:00
2009-07-05 18:28:36 +00:00
struct peer_liveliness
{
2013-01-27 21:03:52 +00:00
tr_peer * peer ;
void * clientData ;
time_t pieceDataTime ;
time_t time ;
int speed ;
bool doPurge ;
2009-07-05 18:28:36 +00:00
} ;
static int
2012-12-05 17:29:46 +00:00
comparePeerLiveliness ( const void * va , const void * vb )
2009-07-05 18:28:36 +00:00
{
2013-01-27 21:03:52 +00:00
const struct peer_liveliness * a = va ;
const struct peer_liveliness * b = vb ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > doPurge ! = b - > doPurge )
return a - > doPurge ? 1 : - 1 ;
2009-07-06 12:27:24 +00:00
2013-01-27 21:03:52 +00:00
if ( a - > speed ! = b - > speed ) /* faster goes first */
return a - > speed > b - > speed ? - 1 : 1 ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* the one to give us data more recently goes first */
if ( a - > pieceDataTime ! = b - > pieceDataTime )
return a - > pieceDataTime > b - > pieceDataTime ? - 1 : 1 ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* the one we connected to most recently goes first */
if ( a - > time ! = b - > time )
return a - > time > b - > time ? - 1 : 1 ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
return 0 ;
2009-07-05 18:28:36 +00:00
}
static void
2012-12-05 17:29:46 +00:00
sortPeersByLivelinessImpl ( tr_peer * * peers ,
2009-10-27 20:06:55 +00:00
void * * clientData ,
int n ,
uint64_t now ,
2012-12-05 17:29:46 +00:00
int ( * compare ) ( const void * va , const void * vb ) )
2009-07-05 18:28:36 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
struct peer_liveliness * lives , * l ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* build a sortable array of peer + extra info */
lives = l = tr_new0 ( struct peer_liveliness , n ) ;
for ( i = 0 ; i < n ; + + i , + + l )
2009-10-27 20:06:55 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peer * p = peers [ i ] ;
l - > peer = p ;
l - > doPurge = p - > doPurge ;
l - > pieceDataTime = p - > atom - > piece_data_time ;
l - > time = p - > atom - > time ;
l - > speed = tr_peerGetPieceSpeed_Bps ( p , now , TR_UP )
+ tr_peerGetPieceSpeed_Bps ( p , now , TR_DOWN ) ;
if ( clientData )
l - > clientData = clientData [ i ] ;
2009-07-05 18:28:36 +00:00
}
2013-01-27 21:03:52 +00:00
/* sort 'em */
assert ( n = = ( l - lives ) ) ;
qsort ( lives , n , sizeof ( struct peer_liveliness ) , compare ) ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* build the peer array */
for ( i = 0 , l = lives ; i < n ; + + i , + + l )
{
peers [ i ] = l - > peer ;
if ( clientData )
clientData [ i ] = l - > clientData ;
2009-07-05 18:28:36 +00:00
}
2013-01-27 21:03:52 +00:00
assert ( n = = ( l - lives ) ) ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* cleanup */
tr_free ( lives ) ;
2009-07-05 18:28:36 +00:00
}
2009-10-27 20:06:55 +00:00
static void
2012-12-05 17:29:46 +00:00
sortPeersByLiveliness ( tr_peer * * peers , void * * clientData , int n , uint64_t now )
2009-10-27 20:06:55 +00:00
{
2013-01-27 21:03:52 +00:00
sortPeersByLivelinessImpl ( peers , clientData , n , now , comparePeerLiveliness ) ;
2009-10-27 20:06:55 +00:00
}
2009-07-05 18:28:36 +00:00
static void
2013-01-27 21:03:52 +00:00
enforceTorrentPeerLimit ( tr_swarm * s , uint64_t now )
2009-07-05 18:28:36 +00:00
{
2013-01-27 21:03:52 +00:00
int n = tr_ptrArraySize ( & s - > peers ) ;
const int max = tr_torrentGetPeerLimit ( s - > tor ) ;
if ( n > max )
2009-07-05 18:28:36 +00:00
{
2013-01-27 21:03:52 +00:00
void * base = tr_ptrArrayBase ( & s - > peers ) ;
tr_peer * * peers = tr_memdup ( base , n * sizeof ( tr_peer * ) ) ;
sortPeersByLiveliness ( peers , NULL , n , now ) ;
while ( n > max )
closePeer ( s , peers [ - - n ] ) ;
tr_free ( peers ) ;
2009-07-05 18:28:36 +00:00
}
}
static void
2012-12-05 17:29:46 +00:00
enforceSessionPeerLimit ( tr_session * session , uint64_t now )
2009-07-05 18:28:36 +00:00
{
2013-01-27 21:03:52 +00:00
int n = 0 ;
tr_torrent * tor = NULL ;
const int max = tr_sessionGetPeerLimit ( session ) ;
/* count the total number of peers */
while ( ( tor = tr_torrentNext ( session , tor ) ) )
n + = tr_ptrArraySize ( & tor - > swarm - > peers ) ;
/* if there are too many, prune out the worst */
if ( n > max )
{
tr_peer * * peers = tr_new ( tr_peer * , n ) ;
tr_swarm * * swarms = tr_new ( tr_swarm * , n ) ;
/* populate the peer array */
n = 0 ;
tor = NULL ;
while ( ( tor = tr_torrentNext ( session , tor ) ) )
{
int i ;
tr_swarm * s = tor - > swarm ;
const int tn = tr_ptrArraySize ( & s - > peers ) ;
for ( i = 0 ; i < tn ; + + i , + + n )
{
peers [ n ] = tr_ptrArrayNth ( & s - > peers , i ) ;
swarms [ n ] = s ;
2009-07-05 18:28:36 +00:00
}
}
2009-08-10 20:04:08 +00:00
2013-01-27 21:03:52 +00:00
/* sort 'em */
sortPeersByLiveliness ( peers , ( void * * ) swarms , n , now ) ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* cull out the crappiest */
while ( n - - > max )
closePeer ( swarms [ n ] , peers [ n ] ) ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* cleanup */
tr_free ( swarms ) ;
tr_free ( peers ) ;
2009-07-05 18:28:36 +00:00
}
}
2012-12-05 17:29:46 +00:00
static void makeNewPeerConnections ( tr_peerMgr * mgr , const int max ) ;
2010-01-05 23:47:50 +00:00
2009-12-10 05:52:46 +00:00
static void
2012-12-05 17:29:46 +00:00
reconnectPulse ( int foo UNUSED , short bar UNUSED , void * vmgr )
2009-02-04 16:58:52 +00:00
{
2013-01-27 21:03:52 +00:00
tr_torrent * tor ;
tr_peerMgr * mgr = vmgr ;
const time_t now_sec = tr_time ( ) ;
const uint64_t now_msec = tr_time_msec ( ) ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/**
* * * enforce the per - session and per - torrent peer limits
* */
2009-12-12 17:05:31 +00:00
2013-01-27 21:03:52 +00:00
/* if we're over the per-torrent peer limits, cull some peers */
tor = NULL ;
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
if ( tor - > isRunning )
enforceTorrentPeerLimit ( tor - > swarm , now_msec ) ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* if we're over the per-session peer limits, cull some peers */
enforceSessionPeerLimit ( mgr - > session , now_msec ) ;
2009-07-05 18:28:36 +00:00
2013-01-27 21:03:52 +00:00
/* remove crappy peers */
tor = NULL ;
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
if ( ! tor - > swarm - > isRunning )
removeAllPeers ( tor - > swarm ) ;
else
closeBadPeers ( tor - > swarm , now_sec ) ;
2009-12-12 17:05:31 +00:00
2013-01-27 21:03:52 +00:00
/* try to make new peer connections */
makeNewPeerConnections ( mgr , MAX_CONNECTIONS_PER_PULSE ) ;
2007-09-22 00:22:10 +00:00
}
2008-09-17 19:44:24 +00:00
/****
* * * * *
2008-10-25 02:20:16 +00:00
* * * * * BANDWIDTH ALLOCATION
2008-09-17 19:44:24 +00:00
* * * * *
* * * */
2008-11-24 04:21:23 +00:00
static void
2012-12-05 17:29:46 +00:00
pumpAllPeers ( tr_peerMgr * mgr )
2008-11-24 04:21:23 +00:00
{
2013-01-27 21:03:52 +00:00
tr_torrent * tor = NULL ;
2008-11-24 04:21:23 +00:00
2013-01-27 21:03:52 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
2008-11-24 04:21:23 +00:00
{
2013-01-27 21:03:52 +00:00
int j ;
tr_swarm * s = tor - > swarm ;
2009-01-13 21:00:05 +00:00
2013-01-27 21:03:52 +00:00
for ( j = 0 ; j < tr_ptrArraySize ( & s - > peers ) ; + + j )
2013-02-04 16:23:33 +00:00
tr_peerMsgsPulse ( tr_ptrArrayNth ( & s - > peers , j ) ) ;
2008-11-24 04:21:23 +00:00
}
}
2012-12-28 20:10:03 +00:00
static void
queuePulseForeach ( void * vtor )
{
tr_torrent * tor = vtor ;
tr_torrentStartNow ( tor ) ;
if ( tor - > queue_started_callback ! = NULL )
( * tor - > queue_started_callback ) ( tor , tor - > queue_started_user_data ) ;
}
2011-08-01 22:24:24 +00:00
static void
2012-12-05 17:29:46 +00:00
queuePulse ( tr_session * session , tr_direction dir )
2011-08-01 22:24:24 +00:00
{
2012-12-28 20:10:03 +00:00
assert ( tr_isSession ( session ) ) ;
assert ( tr_isDirection ( dir ) ) ;
2011-08-01 22:24:24 +00:00
2012-12-28 20:10:03 +00:00
if ( tr_sessionGetQueueEnabled ( session , dir ) )
2011-08-01 22:24:24 +00:00
{
2012-12-28 20:10:03 +00:00
tr_ptrArray torrents = TR_PTR_ARRAY_INIT ;
tr_sessionGetNextQueuedTorrents ( session ,
dir ,
tr_sessionCountQueueFreeSlots ( session , dir ) ,
& torrents ) ;
tr_ptrArrayForeach ( & torrents , queuePulseForeach ) ;
tr_ptrArrayDestruct ( & torrents , NULL ) ;
2011-08-01 22:24:24 +00:00
}
}
2009-12-10 05:52:46 +00:00
static void
2012-12-05 17:29:46 +00:00
bandwidthPulse ( int foo UNUSED , short bar UNUSED , void * vmgr )
2008-09-17 19:44:24 +00:00
{
2013-01-27 21:03:52 +00:00
tr_torrent * tor ;
tr_peerMgr * mgr = vmgr ;
tr_session * session = mgr - > session ;
managerLock ( mgr ) ;
2008-09-17 19:44:24 +00:00
2013-01-27 21:03:52 +00:00
/* FIXME: this next line probably isn't necessary... */
pumpAllPeers ( mgr ) ;
2008-12-20 22:19:34 +00:00
2013-01-27 21:03:52 +00:00
/* allocate bandwidth to the peers */
tr_bandwidthAllocate ( & session - > bandwidth , TR_UP , BANDWIDTH_PERIOD_MSEC ) ;
tr_bandwidthAllocate ( & session - > bandwidth , TR_DOWN , BANDWIDTH_PERIOD_MSEC ) ;
2008-12-20 22:19:34 +00:00
2013-01-27 21:03:52 +00:00
/* torrent upkeep */
tor = NULL ;
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2011-05-10 14:41:59 +00:00
{
2013-01-27 21:03:52 +00:00
/* possibly stop torrents that have seeded enough */
tr_torrentCheckSeedLimit ( tor ) ;
2009-04-09 14:10:31 +00:00
2013-01-27 21:03:52 +00:00
/* run the completeness check for any torrents that need it */
if ( tor - > swarm - > needsCompletenessCheck )
{
tor - > swarm - > needsCompletenessCheck = false ;
tr_torrentRecheckCompleteness ( tor ) ;
2009-11-09 06:36:47 +00:00
}
2013-01-27 21:03:52 +00:00
/* stop torrents that are ready to stop, but couldn't be stopped
earlier during the peer - io callback call chain */
if ( tor - > isStopping )
tr_torrentStop ( tor ) ;
2013-05-27 21:04:48 +00:00
/* update the torrent's stats */
tor - > activeWebseedCount = countActiveWebseeds ( tor - > swarm ) ;
2011-05-10 14:41:59 +00:00
}
2009-08-13 17:25:26 +00:00
2013-01-27 21:03:52 +00:00
/* pump the queues */
queuePulse ( session , TR_UP ) ;
queuePulse ( session , TR_DOWN ) ;
2011-08-01 22:24:24 +00:00
2013-01-27 21:03:52 +00:00
reconnectPulse ( 0 , 0 , mgr ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
tr_timerAddMsec ( mgr - > bandwidthTimer , BANDWIDTH_PERIOD_MSEC ) ;
managerUnlock ( mgr ) ;
2008-09-17 19:44:24 +00:00
}
2009-11-26 05:13:58 +00:00
/***
* * * *
* * */
static int
2012-12-05 17:29:46 +00:00
compareAtomPtrsByAddress ( const void * va , const void * vb )
2009-11-26 05:13:58 +00:00
{
2013-01-27 21:03:52 +00:00
const struct peer_atom * a = * ( const struct peer_atom * * ) va ;
const struct peer_atom * b = * ( const struct peer_atom * * ) vb ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isAtom ( a ) ) ;
assert ( tr_isAtom ( b ) ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
return tr_address_compare ( & a - > addr , & b - > addr ) ;
2009-11-26 05:13:58 +00:00
}
/* best come first, worst go last */
static int
2012-12-05 17:29:46 +00:00
compareAtomPtrsByShelfDate ( const void * va , const void * vb )
2009-11-26 05:13:58 +00:00
{
2013-01-27 21:03:52 +00:00
time_t atime ;
time_t btime ;
const struct peer_atom * a = * ( const struct peer_atom * * ) va ;
const struct peer_atom * b = * ( const struct peer_atom * * ) vb ;
const int data_time_cutoff_secs = 60 * 60 ;
const time_t tr_now = tr_time ( ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_isAtom ( a ) ) ;
assert ( tr_isAtom ( b ) ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
/* primary key: the last piece data time *if* it was within the last hour */
atime = a - > piece_data_time ; if ( atime + data_time_cutoff_secs < tr_now ) atime = 0 ;
btime = b - > piece_data_time ; if ( btime + data_time_cutoff_secs < tr_now ) btime = 0 ;
if ( atime ! = btime )
return atime > btime ? - 1 : 1 ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
/* secondary key: shelf date. */
if ( a - > shelf_date ! = b - > shelf_date )
return a - > shelf_date > b - > shelf_date ? - 1 : 1 ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
return 0 ;
2009-11-26 05:13:58 +00:00
}
static int
2012-12-05 17:29:46 +00:00
getMaxAtomCount ( const tr_torrent * tor )
2009-11-26 05:13:58 +00:00
{
2013-01-17 01:10:59 +00:00
return MIN ( 50 , tor - > maxConnectedPeers * 3 ) ;
2009-11-26 05:13:58 +00:00
}
2009-12-10 05:52:46 +00:00
static void
2012-12-05 17:29:46 +00:00
atomPulse ( int foo UNUSED , short bar UNUSED , void * vmgr )
2009-11-26 05:13:58 +00:00
{
2013-01-27 21:03:52 +00:00
tr_torrent * tor = NULL ;
tr_peerMgr * mgr = vmgr ;
managerLock ( mgr ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
2009-11-26 05:13:58 +00:00
{
2013-01-27 21:03:52 +00:00
int atomCount ;
tr_swarm * s = tor - > swarm ;
const int maxAtomCount = getMaxAtomCount ( tor ) ;
struct peer_atom * * atoms = ( struct peer_atom * * ) tr_ptrArrayPeek ( & s - > pool , & atomCount ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
if ( atomCount > maxAtomCount ) /* we've got too many atoms... time to prune */
2009-11-26 05:13:58 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
int keepCount = 0 ;
int testCount = 0 ;
struct peer_atom * * keep = tr_new ( struct peer_atom * , atomCount ) ;
struct peer_atom * * test = tr_new ( struct peer_atom * , atomCount ) ;
/* keep the ones that are in use */
for ( i = 0 ; i < atomCount ; + + i )
{
struct peer_atom * atom = atoms [ i ] ;
if ( peerIsInUse ( s , atom ) )
keep [ keepCount + + ] = atom ;
else
test [ testCount + + ] = atom ;
2009-11-26 05:13:58 +00:00
}
2013-01-27 21:03:52 +00:00
/* if there's room, keep the best of what's left */
i = 0 ;
if ( keepCount < maxAtomCount )
{
qsort ( test , testCount , sizeof ( struct peer_atom * ) , compareAtomPtrsByShelfDate ) ;
while ( i < testCount & & keepCount < maxAtomCount )
keep [ keepCount + + ] = test [ i + + ] ;
2009-11-26 05:13:58 +00:00
}
2013-01-27 21:03:52 +00:00
/* free the culled atoms */
while ( i < testCount )
tr_free ( test [ i + + ] ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
/* rebuild Torrent.pool with what's left */
tr_ptrArrayDestruct ( & s - > pool , NULL ) ;
s - > pool = TR_PTR_ARRAY_INIT ;
qsort ( keep , keepCount , sizeof ( struct peer_atom * ) , compareAtomPtrsByAddress ) ;
for ( i = 0 ; i < keepCount ; + + i )
tr_ptrArrayAppend ( & s - > pool , keep [ i ] ) ;
2009-11-27 14:27:44 +00:00
2013-01-27 21:03:52 +00:00
tordbg ( s , " max atom count is %d... pruned from %d to %d \n " , maxAtomCount , atomCount , keepCount ) ;
2009-11-26 05:13:58 +00:00
2013-01-27 21:03:52 +00:00
/* cleanup */
tr_free ( test ) ;
tr_free ( keep ) ;
2009-11-26 05:13:58 +00:00
}
}
2013-01-27 21:03:52 +00:00
tr_timerAddMsec ( mgr - > atomTimer , ATOM_PERIOD_MSEC ) ;
managerUnlock ( mgr ) ;
2009-11-26 05:13:58 +00:00
}
2010-04-20 21:54:03 +00:00
/***
* * * *
* * * *
* * * *
* * */
/* is this atom someone that we'd want to initiate a connection to? */
2011-03-22 15:19:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
isPeerCandidate ( const tr_torrent * tor , struct peer_atom * atom , const time_t now )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
/* not if we're both seeds */
if ( tr_torrentIsSeed ( tor ) & & atomIsSeed ( atom ) )
return false ;
2010-07-04 20:40:34 +00:00
2013-01-27 21:03:52 +00:00
/* not if we've already got a connection to them... */
if ( peerIsInUse ( tor - > swarm , atom ) )
return false ;
2010-07-04 20:40:34 +00:00
2013-01-27 21:03:52 +00:00
/* not if we just tried them already */
if ( ( now - atom - > time ) < getReconnectIntervalSecs ( atom , now ) )
return false ;
2010-06-14 12:48:28 +00:00
2013-01-27 21:03:52 +00:00
/* not if they're blocklisted */
if ( isAtomBlocklisted ( tor - > session , atom ) )
return false ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
/* not if they're banned... */
if ( atom - > flags2 & MYFLAG_BANNED )
return false ;
2010-06-14 11:57:46 +00:00
2013-01-27 21:03:52 +00:00
return true ;
2010-04-20 21:54:03 +00:00
}
struct peer_candidate
{
2013-01-27 21:03:52 +00:00
uint64_t score ;
tr_torrent * tor ;
struct peer_atom * atom ;
2010-04-20 21:54:03 +00:00
} ;
2011-03-22 15:19:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
torrentWasRecentlyStarted ( const tr_torrent * tor )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
return difftime ( tr_time ( ) , tor - > startDate ) < 120 ;
2010-04-20 21:54:03 +00:00
}
2010-06-14 12:48:28 +00:00
static inline uint64_t
2012-12-05 17:29:46 +00:00
addValToKey ( uint64_t value , int width , uint64_t addme )
2010-06-14 01:56:03 +00:00
{
2013-01-27 21:03:52 +00:00
value = ( value < < ( uint64_t ) width ) ;
value | = addme ;
return value ;
2010-06-14 01:56:03 +00:00
}
/* smaller value is better */
static uint64_t
2012-12-05 17:29:46 +00:00
getPeerCandidateScore ( const tr_torrent * tor , const struct peer_atom * atom , uint8_t salt )
2010-06-14 01:56:03 +00:00
{
2013-01-27 21:03:52 +00:00
uint64_t i ;
uint64_t score = 0 ;
const bool failed = atom - > lastConnectionAt < atom - > lastConnectionAttemptAt ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
/* prefer peers we've connected to, or never tried, over peers we failed to connect to. */
i = failed ? 1 : 0 ;
score = addValToKey ( score , 1 , i ) ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
/* prefer the one we attempted least recently (to cycle through all peers) */
i = atom - > lastConnectionAttemptAt ;
score = addValToKey ( score , 32 , i ) ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
/* prefer peers belonging to a torrent of a higher priority */
switch ( tr_torrentGetPriority ( tor ) )
{
case TR_PRI_HIGH : i = 0 ; break ;
case TR_PRI_NORMAL : i = 1 ; break ;
case TR_PRI_LOW : i = 2 ; break ;
2010-06-14 01:56:03 +00:00
}
2013-01-27 21:03:52 +00:00
score = addValToKey ( score , 4 , i ) ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
/* prefer recently-started torrents */
i = torrentWasRecentlyStarted ( tor ) ? 0 : 1 ;
score = addValToKey ( score , 1 , i ) ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
/* prefer torrents we're downloading with */
i = tr_torrentIsSeed ( tor ) ? 1 : 0 ;
score = addValToKey ( score , 1 , i ) ;
2010-06-26 18:49:31 +00:00
2013-01-27 21:03:52 +00:00
/* prefer peers that are known to be connectible */
i = ( atom - > flags & ADDED_F_CONNECTABLE ) ? 0 : 1 ;
score = addValToKey ( score , 1 , i ) ;
2010-12-14 18:33:48 +00:00
2013-01-27 21:03:52 +00:00
/* prefer peers that we might have a chance of uploading to...
so lower seed probability is better */
if ( atom - > seedProbability = = 100 ) i = 101 ;
else if ( atom - > seedProbability = = - 1 ) i = 100 ;
else i = atom - > seedProbability ;
score = addValToKey ( score , 8 , i ) ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
/* Prefer peers that we got from more trusted sources.
* lower ` fromBest ' values indicate more trusted sources */
score = addValToKey ( score , 4 , atom - > fromBest ) ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
/* salt */
score = addValToKey ( score , 8 , salt ) ;
2010-06-14 01:56:03 +00:00
2013-01-27 21:03:52 +00:00
return score ;
2010-06-14 01:56:03 +00:00
}
static int
2012-12-28 20:10:03 +00:00
comparePeerCandidates ( const void * va , const void * vb )
2010-06-14 01:56:03 +00:00
{
2012-12-28 20:10:03 +00:00
int ret ;
const struct peer_candidate * a = va ;
const struct peer_candidate * b = vb ;
2010-06-14 01:56:03 +00:00
2012-12-28 20:10:03 +00:00
if ( a - > score < b - > score )
ret = - 1 ;
else if ( a - > score > b - > score )
ret = 1 ;
else
ret = 0 ;
2010-06-14 01:56:03 +00:00
2012-12-28 20:10:03 +00:00
return ret ;
2010-04-20 21:54:03 +00:00
}
2012-12-28 08:35:14 +00:00
/* Partial sorting -- selecting the k best candidates
Adapted from http : //en.wikipedia.org/wiki/Selection_algorithm */
2011-12-31 21:28:53 +00:00
static void
2012-12-28 20:10:03 +00:00
selectPeerCandidates ( struct peer_candidate * candidates , int candidate_count , int select_count )
2011-12-31 21:28:53 +00:00
{
2012-12-28 20:10:03 +00:00
tr_quickfindFirstK ( candidates ,
candidate_count ,
sizeof ( struct peer_candidate ) ,
comparePeerCandidates ,
select_count ) ;
2011-12-31 21:28:53 +00:00
}
# ifndef NDEBUG
static bool
2012-12-05 17:29:46 +00:00
checkBestScoresComeFirst ( const struct peer_candidate * candidates , int n , int k )
2011-12-31 21:28:53 +00:00
{
2013-01-27 21:03:52 +00:00
int i ;
uint64_t worstFirstScore = 0 ;
const int x = MIN ( n , k ) - 1 ;
2011-12-31 21:28:53 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < x ; i + + )
if ( worstFirstScore < candidates [ i ] . score )
worstFirstScore = candidates [ i ] . score ;
2011-12-31 21:28:53 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < x ; i + + )
assert ( candidates [ i ] . score < = worstFirstScore ) ;
2011-12-31 21:28:53 +00:00
2013-01-27 21:03:52 +00:00
for ( i = x + 1 ; i < n ; i + + )
assert ( candidates [ i ] . score > = worstFirstScore ) ;
2011-12-31 21:28:53 +00:00
2013-01-27 21:03:52 +00:00
return true ;
2011-12-31 21:28:53 +00:00
}
# endif /* NDEBUG */
2010-04-20 21:54:03 +00:00
/** @return an array of all the atoms we might want to connect to */
static struct peer_candidate *
2012-12-05 17:29:46 +00:00
getPeerCandidates ( tr_session * session , int * candidateCount , int max )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
int atomCount ;
int peerCount ;
tr_torrent * tor ;
struct peer_candidate * candidates ;
struct peer_candidate * walk ;
const time_t now = tr_time ( ) ;
const uint64_t now_msec = tr_time_msec ( ) ;
/* leave 5% of connection slots for incoming connections -- ticket #2609 */
const int maxCandidates = tr_sessionGetPeerLimit ( session ) * 0.95 ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
/* count how many peers and atoms we've got */
tor = NULL ;
atomCount = 0 ;
peerCount = 0 ;
while ( ( tor = tr_torrentNext ( session , tor ) ) )
{
atomCount + = tr_ptrArraySize ( & tor - > swarm - > pool ) ;
peerCount + = tr_ptrArraySize ( & tor - > swarm - > peers ) ;
2011-05-10 01:51:12 +00:00
}
2013-01-27 21:03:52 +00:00
/* don't start any new handshakes if we're full up */
if ( maxCandidates < = peerCount )
{
* candidateCount = 0 ;
return NULL ;
2010-04-20 21:54:03 +00:00
}
2013-01-27 21:03:52 +00:00
/* allocate an array of candidates */
walk = candidates = tr_new ( struct peer_candidate , atomCount ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
/* populate the candidate array */
tor = NULL ;
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
int i , nAtoms ;
struct peer_atom * * atoms ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
if ( ! tor - > swarm - > isRunning )
continue ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
/* if we've already got enough peers in this torrent... */
if ( tr_torrentGetPeerLimit ( tor ) < = tr_ptrArraySize ( & tor - > swarm - > peers ) )
continue ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
/* if we've already got enough speed in this torrent... */
if ( tr_torrentIsSeed ( tor ) & & isBandwidthMaxedOut ( & tor - > bandwidth , now_msec , TR_UP ) )
continue ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
atoms = ( struct peer_atom * * ) tr_ptrArrayPeek ( & tor - > swarm - > pool , & nAtoms ) ;
for ( i = 0 ; i < nAtoms ; + + i )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
struct peer_atom * atom = atoms [ i ] ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
if ( isPeerCandidate ( tor , atom , now ) )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
const uint8_t salt = tr_cryptoWeakRandInt ( 1024 ) ;
walk - > tor = tor ;
walk - > atom = atom ;
walk - > score = getPeerCandidateScore ( tor , atom , salt ) ;
+ + walk ;
2010-04-20 21:54:03 +00:00
}
}
}
2013-01-27 21:03:52 +00:00
* candidateCount = walk - candidates ;
if ( walk ! = candidates )
selectPeerCandidates ( candidates , walk - candidates , max ) ;
2011-12-31 21:28:53 +00:00
2013-01-27 21:03:52 +00:00
assert ( checkBestScoresComeFirst ( candidates , * candidateCount , max ) ) ;
return candidates ;
2010-04-20 21:54:03 +00:00
}
static void
2013-01-27 21:03:52 +00:00
initiateConnection ( tr_peerMgr * mgr , tr_swarm * s , struct peer_atom * atom )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
tr_peerIo * io ;
const time_t now = tr_time ( ) ;
bool utp = tr_sessionIsUTPEnabled ( mgr - > session ) & & ! atom - > utp_failed ;
2011-02-18 00:43:24 +00:00
2013-01-27 21:03:52 +00:00
if ( atom - > fromFirst = = TR_PEER_FROM_PEX )
/* PEX has explicit signalling for uTP support. If an atom
originally came from PEX and doesn ' t have the uTP flag , skip the
uTP connection attempt . Are we being optimistic here ? */
utp = utp & & ( atom - > flags & ADDED_F_UTP_FLAGS ) ;
2011-02-18 00:43:49 +00:00
2013-01-27 21:03:52 +00:00
tordbg ( s , " Starting an OUTGOING%s connection with %s " ,
utp ? " µTP " : " " , tr_atomAddrStr ( atom ) ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
io = tr_peerIoNewOutgoing ( mgr - > session ,
& mgr - > session - > bandwidth ,
& atom - > addr ,
atom - > port ,
s - > tor - > info . hash ,
s - > tor - > completeness = = TR_SEED ,
utp ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
if ( io = = NULL )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
tordbg ( s , " peerIo not created; marking peer %s as unreachable " , tr_atomAddrStr ( atom ) ) ;
atom - > flags2 | = MYFLAG_UNREACHABLE ;
atom - > numFails + + ;
2010-04-20 21:54:03 +00:00
}
2013-01-27 21:03:52 +00:00
else
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
tr_handshake * handshake = tr_handshakeNew ( io ,
mgr - > session - > encryptionMode ,
myHandshakeDoneCB ,
mgr ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
assert ( tr_peerIoGetTorrentHash ( io ) ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
tr_peerIoUnref ( io ) ; /* balanced by the initial ref
in tr_peerIoNewOutgoing ( ) */
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
tr_ptrArrayInsertSorted ( & s - > outgoingHandshakes , handshake ,
handshakeCompare ) ;
2010-04-20 21:54:03 +00:00
}
2013-01-27 21:03:52 +00:00
atom - > lastConnectionAttemptAt = now ;
atom - > time = now ;
2010-04-20 21:54:03 +00:00
}
static void
2012-12-05 17:29:46 +00:00
initiateCandidateConnection ( tr_peerMgr * mgr , struct peer_candidate * c )
2010-04-20 21:54:03 +00:00
{
#if 0
2013-01-27 21:03:52 +00:00
fprintf ( stderr , " Starting an OUTGOING connection with %s - [%s] seedProbability==%d; %s, %s \n " ,
tr_atomAddrStr ( c - > atom ) ,
tr_torrentName ( c - > tor ) ,
2012-12-05 17:29:46 +00:00
( int ) c - > atom - > seedProbability ,
2013-01-27 21:03:52 +00:00
tr_torrentIsPrivate ( c - > tor ) ? " private " : " public " ,
tr_torrentIsSeed ( c - > tor ) ? " seed " : " downloader " ) ;
2010-04-20 21:54:03 +00:00
# endif
2013-01-27 21:03:52 +00:00
initiateConnection ( mgr , c - > tor - > swarm , c - > atom ) ;
2010-04-20 21:54:03 +00:00
}
static void
2012-12-05 17:29:46 +00:00
makeNewPeerConnections ( struct tr_peerMgr * mgr , const int max )
2010-04-20 21:54:03 +00:00
{
2013-01-27 21:03:52 +00:00
int i , n ;
struct peer_candidate * candidates ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
candidates = getPeerCandidates ( mgr - > session , & n , max ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
for ( i = 0 ; i < n & & i < max ; + + i )
initiateCandidateConnection ( mgr , & candidates [ i ] ) ;
2010-04-20 21:54:03 +00:00
2013-01-27 21:03:52 +00:00
tr_free ( candidates ) ;
2010-04-20 21:54:03 +00:00
}