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"
# 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
{
2009-11-26 05:13:58 +00:00
/* how frequently to cull old atoms */
2012-12-05 17:29:46 +00:00
ATOM_PERIOD_MSEC = ( 60 * 1000 ) ,
2009-11-26 05:13:58 +00:00
2007-09-22 14:18:52 +00:00
/* how frequently to change which peers are choked */
2012-12-05 17:29:46 +00:00
RECHOKE_PERIOD_MSEC = ( 10 * 1000 ) ,
2007-09-22 14:18:52 +00:00
2010-10-13 03:56:25 +00:00
/* an optimistically unchoked peer is immune from rechoking
2012-12-05 17:29:46 +00:00
for this many calls to rechokeUploads ( ) . */
2010-10-13 03:56:25 +00:00
OPTIMISTIC_UNCHOKE_MULTIPLIER = 4 ,
2009-02-04 16:58:52 +00:00
/* how frequently to reallocate bandwidth */
BANDWIDTH_PERIOD_MSEC = 500 ,
2009-02-18 17:19:36 +00:00
/* how frequently to age out old piece request lists */
2012-12-05 17:29:46 +00:00
REFILL_UPKEEP_PERIOD_MSEC = ( 10 * 1000 ) ,
2009-02-18 17:19:36 +00:00
2009-02-04 16:58:52 +00:00
/* how frequently to decide which peers live and die */
RECONNECT_PERIOD_MSEC = 500 ,
2007-09-22 00:22:10 +00:00
2007-10-13 13:54:05 +00:00
/* when many peers are available, keep idle ones this long */
2012-12-05 17:29:46 +00:00
MIN_UPLOAD_IDLE_SECS = ( 60 ) ,
2007-10-13 13:54:05 +00:00
/* when few peers are available, keep idle ones this long */
2012-12-05 17:29:46 +00:00
MAX_UPLOAD_IDLE_SECS = ( 60 * 5 ) ,
2007-10-13 13:54:05 +00:00
2008-01-11 18:13:09 +00:00
/* max number of peers to ask for per second overall.
2010-06-26 17:54:19 +00:00
* this throttle is to avoid overloading the router */
MAX_CONNECTIONS_PER_SECOND = 12 ,
2008-01-11 18:13:09 +00:00
2010-04-20 21:54:03 +00:00
MAX_CONNECTIONS_PER_PULSE = ( int ) ( MAX_CONNECTIONS_PER_SECOND * ( RECONNECT_PERIOD_MSEC / 1000.0 ) ) ,
2007-10-08 01:31:27 +00:00
/* number of bad pieces a peer is allowed to send before we ban them */
2008-11-24 04:21:23 +00:00
MAX_BAD_PIECES_PER_PEER = 5 ,
2007-12-15 04:26:31 +00:00
2009-02-18 17:19:36 +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 ,
2010-12-14 18:33:48 +00:00
/* use for bitwise operations w/peer_atom.flags2 */
2007-12-15 04:26:31 +00:00
MYFLAG_BANNED = 1 ,
2010-12-14 18:33:48 +00:00
/* use for bitwise operations w/peer_atom.flags2 */
2008-09-17 19:44:24 +00:00
/* unreachable for now... but not banned.
* if they try to connect to us it ' s okay */
2008-09-05 05:14:49 +00:00
MYFLAG_UNREACHABLE = 2 ,
2008-09-17 19:44:24 +00:00
/* the minimum we'll wait before attempting to reconnect to a peer */
2009-12-16 18:20:01 +00:00
MINIMUM_RECONNECT_INTERVAL_SECS = 5 ,
/** how long we'll let requests we've made linger before we cancel them */
2010-03-22 02:27:57 +00:00
REQUEST_TTL_SECS = 120 ,
2010-03-08 04:29:58 +00:00
2010-11-16 15:17:34 +00:00
NO_BLOCKS_CANCEL_HISTORY = 120 ,
CANCEL_HISTORY_SEC = 60
2009-11-01 02:10:47 +00:00
} ;
2007-10-01 16:31:17 +00:00
2011-03-22 15:19:54 +00:00
const tr_peer_event TR_PEER_EVENT_INIT = { 0 , 0 , NULL , 0 , 0 , 0 , false , 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
* @ see tr_peermsgs
*/
2007-09-30 23:55:49 +00:00
struct peer_atom
2008-09-23 19:11:04 +00:00
{
2010-12-23 02:35:21 +00:00
uint8_t fromFirst ; /* where the peer was first found */
uint8_t fromBest ; /* the "best" value of where the peer has been found */
2010-04-20 21:54:03 +00:00
uint8_t flags ; /* these match the added_f flags */
2010-12-14 18:33:48 +00:00
uint8_t flags2 ; /* flags that aren't defined in added_f */
2010-04-20 21:54:03 +00:00
int8_t seedProbability ; /* how likely is this to be a seed... [0..100] or -1 for unknown */
2011-03-22 15:19:54 +00:00
int8_t blocklisted ; /* -1 for unknown, true for blocklisted, false for not blocklisted */
2010-04-20 21:54:03 +00:00
2008-12-02 03:41:58 +00:00
tr_port port ;
2011-03-22 15:19:54 +00:00
bool utp_failed ; /* We recently failed to connect over uTP */
2008-12-02 03:41:58 +00:00
uint16_t numFails ;
2010-04-20 21:54:03 +00:00
time_t time ; /* when the peer's connection status last changed */
2008-12-02 03:41:58 +00:00
time_t piece_data_time ;
2009-11-26 05:13:58 +00:00
2010-04-20 21:54:03 +00:00
time_t lastConnectionAttemptAt ;
time_t lastConnectionAt ;
2009-11-26 05:13:58 +00:00
/* 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 ;
2010-04-20 21:54:03 +00:00
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
{
2012-12-05 17:29:46 +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
{
2012-12-05 17:29:46 +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
{
2009-11-08 23:20:00 +00:00
tr_block_index_t block ;
tr_peer * peer ;
time_t sentAt ;
} ;
struct weighted_piece
{
tr_piece_index_t index ;
2010-01-12 20:17:22 +00:00
int16_t salt ;
2009-11-08 23:20:00 +00:00
int16_t requestCount ;
2009-02-18 17:19:36 +00:00
} ;
2011-02-17 05:14:53 +00:00
enum piece_sort_state
{
PIECES_UNSORTED ,
PIECES_SORTED_BY_INDEX ,
PIECES_SORTED_BY_WEIGHT
} ;
2010-01-19 19:37:00 +00:00
/** @brief Opaque, per-torrent data structure for peer connection information */
2009-01-13 21:00:05 +00:00
typedef struct tr_torrent_peers
2007-09-20 16:32:01 +00:00
{
2009-02-18 17:19:36 +00:00
tr_ptrArray outgoingHandshakes ; /* tr_handshake */
tr_ptrArray pool ; /* struct peer_atom */
tr_ptrArray peers ; /* tr_peer */
tr_ptrArray webseeds ; /* tr_webseed */
2009-06-24 03:54:11 +00:00
2009-02-18 17:19:36 +00:00
tr_torrent * tor ;
struct tr_peerMgr * manager ;
2009-06-24 03:54:11 +00:00
2010-10-13 03:56:25 +00:00
tr_peer * optimistic ; /* the optimistic peer, or NULL if none */
int optimisticUnchokeTimeScaler ;
2011-03-22 15:19:54 +00:00
bool isRunning ;
bool needsCompletenessCheck ;
2009-11-08 23:20:00 +00:00
struct block_request * requests ;
int requestCount ;
int requestAlloc ;
struct weighted_piece * pieces ;
int pieceCount ;
2011-02-17 05:14:53 +00:00
enum piece_sort_state pieceSortState ;
/* 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
int interestedCount ;
2010-10-01 18:16:01 +00:00
int maxPeers ;
2010-12-04 17:17:44 +00:00
time_t lastCancel ;
2011-02-15 16:04:56 +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
}
Torrent ;
struct tr_peerMgr
{
2009-12-10 05:52:46 +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 \
{ \
if ( tr_deepLoggingIsActive ( ) ) \
tr_deepLog ( __FILE__ , __LINE__ , tr_torrentName ( t - > tor ) , __VA_ARGS__ ) ; \
} \
while ( 0 )
# define dbgmsg(...) \
do \
{ \
if ( tr_deepLoggingIsActive ( ) ) \
tr_deepLog ( __FILE__ , __LINE__ , NULL , __VA_ARGS__ ) ; \
} \
while ( 0 )
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
{
2012-12-05 17:29:46 +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
{
2012-12-05 17:29:46 +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
2012-12-05 17:29:46 +00:00
torrentLock ( Torrent * torrent )
2007-09-29 06:37:03 +00:00
{
2012-12-05 17:29:46 +00:00
managerLock ( torrent - > 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
2012-12-05 17:29:46 +00:00
torrentUnlock ( Torrent * torrent )
2007-09-29 06:37:03 +00:00
{
2012-12-05 17:29:46 +00:00
managerUnlock ( torrent - > 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
2012-12-05 17:29:46 +00:00
torrentIsLocked ( const Torrent * t )
2007-09-29 06:37:03 +00:00
{
2012-12-05 17:29:46 +00:00
return tr_sessionIsLocked ( t - > 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
{
const tr_handshake * a = va ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +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
{
2012-12-05 17:29:46 +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
{
2012-12-05 17:29:46 +00:00
if ( tr_ptrArrayEmpty ( handshakes ) )
2010-06-14 11:57:46 +00:00
return NULL ;
2012-12-05 17:29:46 +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
{
const struct peer_atom * a = va ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +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
{
const struct peer_atom * b = vb ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
assert ( tr_isAtom ( b ) ) ;
2009-09-10 03:07:54 +00:00
2012-12-05 17:29:46 +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
{
return & peer - > atom - > addr ;
}
2007-09-20 16:32:01 +00:00
static Torrent *
2012-12-05 17:29:46 +00:00
getExistingTorrent ( tr_peerMgr * manager ,
const uint8_t * hash )
2007-09-20 16:32:01 +00:00
{
2012-12-05 17:29:46 +00:00
tr_torrent * tor = tr_torrentFindFromHash ( manager - > session , hash ) ;
2009-01-13 21:00:05 +00:00
return tor = = NULL ? NULL : tor - > torrentPeers ;
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
{
2012-12-05 17:29:46 +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 *
2012-12-05 17:29:46 +00:00
getExistingAtom ( const Torrent * t ,
const tr_address * addr )
2007-09-30 23:55:49 +00:00
{
2008-12-29 08:54:36 +00:00
Torrent * tt = ( Torrent * ) t ;
2012-12-05 17:29:46 +00:00
return tr_ptrArrayFindSorted ( & tt - > pool , addr , comparePeerAtomToAddress ) ;
2007-09-30 23:55:49 +00:00
}
2011-03-22 15:19:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
peerIsInUse ( const Torrent * ct , const struct peer_atom * atom )
2007-09-30 23:55:49 +00:00
{
2007-10-02 16:12:44 +00:00
Torrent * t = ( Torrent * ) ct ;
2012-12-05 17:29:46 +00:00
assert ( torrentIsLocked ( t ) ) ;
2007-09-30 23:55:49 +00:00
2012-12-05 17:29:46 +00:00
return ( atom - > peer ! = NULL )
| | getExistingHandshake ( & t - > outgoingHandshakes , & atom - > addr )
| | getExistingHandshake ( & t - > manager - > incomingHandshakes , & atom - > addr ) ;
2007-10-03 16:42:43 +00:00
}
2011-03-03 18:33:24 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerConstruct ( tr_peer * peer )
2007-10-03 16:42:43 +00:00
{
2012-12-05 17:29:46 +00:00
memset ( peer , 0 , sizeof ( tr_peer ) ) ;
2010-03-08 04:29:58 +00:00
2011-03-28 16:31:05 +00:00
peer - > have = TR_BITFIELD_INIT ;
2011-03-03 18:33:24 +00:00
}
static tr_peer *
2012-12-05 17:29:46 +00:00
peerNew ( struct peer_atom * atom )
2011-03-03 18:33:24 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peer * peer = tr_new ( tr_peer , 1 ) ;
tr_peerConstruct ( peer ) ;
2011-03-03 18:33:24 +00:00
peer - > atom = atom ;
atom - > peer = peer ;
2010-03-08 04:29:58 +00:00
2009-10-29 16:10:03 +00:00
return peer ;
2007-09-30 23:55:49 +00:00
}
2007-09-20 16:32:01 +00:00
static tr_peer *
2012-12-05 17:29:46 +00:00
getPeer ( Torrent * torrent , struct peer_atom * atom )
2007-09-20 16:32:01 +00:00
{
2007-09-29 06:37:03 +00:00
tr_peer * peer ;
2012-12-05 17:29:46 +00:00
assert ( torrentIsLocked ( torrent ) ) ;
2007-09-29 06:37:03 +00:00
2009-11-28 07:15:31 +00:00
peer = atom - > peer ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
if ( peer = = NULL )
2008-09-23 19:11:04 +00:00
{
2012-12-05 17:29:46 +00:00
peer = peerNew ( atom ) ;
tr_bitfieldConstruct ( & peer - > have , torrent - > tor - > info . pieceCount ) ;
tr_bitfieldConstruct ( & peer - > blame , torrent - > tor - > blockCount ) ;
tr_ptrArrayInsertSorted ( & torrent - > peers , peer , peerCompare ) ;
2007-09-20 16:32:01 +00:00
}
return peer ;
}
2012-12-05 17:29:46 +00:00
static void peerDeclinedAllRequests ( Torrent * , const tr_peer * ) ;
2009-11-08 23:20:00 +00:00
2011-03-03 18:33:24 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerDestruct ( tr_torrent * tor , tr_peer * peer )
2007-09-20 16:32:01 +00:00
{
2012-12-05 17:29:46 +00:00
assert ( peer ! = NULL ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
peerDeclinedAllRequests ( tor - > torrentPeers , peer ) ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
if ( peer - > msgs ! = NULL )
tr_peerMsgsFree ( peer - > msgs ) ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
if ( peer - > io ) {
tr_peerIoClear ( peer - > io ) ;
tr_peerIoUnref ( peer - > io ) ; /* balanced by the ref in handshakeDoneCB () */
2011-03-03 18:33:24 +00:00
}
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
tr_bitfieldDestruct ( & peer - > have ) ;
tr_bitfieldDestruct ( & peer - > blame ) ;
2011-03-04 04:45:12 +00:00
2012-12-05 17:29:46 +00:00
if ( peer - > atom )
2011-03-04 04:45:12 +00:00
peer - > atom - > peer = NULL ;
2011-03-03 18:33:24 +00:00
}
2008-11-06 02:56:51 +00:00
2011-03-03 18:33:24 +00:00
static void
2012-12-05 17:29:46 +00:00
peerDelete ( Torrent * t , tr_peer * peer )
2011-03-03 18:33:24 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peerDestruct ( t - > tor , peer ) ;
tr_free ( peer ) ;
2007-09-20 16:32:01 +00:00
}
2011-03-22 15:19:54 +00:00
static bool
2012-12-05 17:29:46 +00:00
replicationExists ( const Torrent * t )
2007-09-30 23:55:49 +00:00
{
2011-02-17 05:14:53 +00:00
return t - > pieceReplication ! = NULL ;
}
2007-09-30 23:55:49 +00:00
2011-02-17 05:14:53 +00:00
static void
2012-12-05 17:29:46 +00:00
replicationFree ( Torrent * t )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
tr_free ( t - > pieceReplication ) ;
2011-02-17 05:14:53 +00:00
t - > pieceReplication = NULL ;
t - > pieceReplicationSize = 0 ;
2007-09-30 23:55:49 +00:00
}
2007-10-01 16:50:51 +00:00
static void
2012-12-05 17:29:46 +00:00
replicationNew ( Torrent * t )
2007-10-01 16:50:51 +00:00
{
2011-02-17 05:14:53 +00:00
tr_piece_index_t piece_i ;
const tr_piece_index_t piece_count = t - > tor - > info . pieceCount ;
2012-12-05 17:29:46 +00:00
tr_peer * * peers = ( 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 ( ! replicationExists ( t ) ) ;
2011-02-17 05:14:53 +00:00
t - > pieceReplicationSize = piece_count ;
2012-12-05 17:29:46 +00:00
t - > pieceReplication = tr_new0 ( uint16_t , piece_count ) ;
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_bitfieldHas ( & peers [ peer_i ] - > have , piece_i ) )
2011-02-17 05:14:53 +00:00
+ + r ;
t - > pieceReplication [ piece_i ] = r ;
}
2007-10-01 16:50:51 +00:00
}
2007-09-20 16:32:01 +00:00
static void
2012-12-05 17:29:46 +00:00
torrentFree ( void * vt )
2007-09-20 16:32:01 +00:00
{
2008-09-17 19:44:24 +00:00
Torrent * t = vt ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
assert ( t ) ;
assert ( ! t - > isRunning ) ;
assert ( torrentIsLocked ( t ) ) ;
assert ( tr_ptrArrayEmpty ( & t - > outgoingHandshakes ) ) ;
assert ( tr_ptrArrayEmpty ( & t - > peers ) ) ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
tr_ptrArrayDestruct ( & t - > webseeds , ( PtrArrayForeachFunc ) tr_webseedFree ) ;
tr_ptrArrayDestruct ( & t - > pool , ( PtrArrayForeachFunc ) tr_free ) ;
tr_ptrArrayDestruct ( & t - > outgoingHandshakes , NULL ) ;
tr_ptrArrayDestruct ( & t - > peers , NULL ) ;
2007-10-02 16:12:44 +00:00
2012-12-05 17:29:46 +00:00
replicationFree ( t ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
tr_free ( t - > requests ) ;
tr_free ( t - > pieces ) ;
tr_free ( t ) ;
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
2012-12-05 17:29:46 +00:00
rebuildWebseedArray ( Torrent * t , tr_torrent * tor )
2012-10-05 22:04:08 +00:00
{
int i ;
const tr_info * inf = & tor - > info ;
/* clear the array */
2012-12-05 17:29:46 +00:00
tr_ptrArrayDestruct ( & t - > webseeds , ( PtrArrayForeachFunc ) tr_webseedFree ) ;
2012-10-05 22:04:08 +00:00
t - > webseeds = TR_PTR_ARRAY_INIT ;
/* repopulate it */
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < inf - > webseedCount ; + + i )
2012-10-05 22:04:08 +00:00
{
2012-12-05 17:29:46 +00:00
tr_webseed * w = tr_webseedNew ( tor , inf - > webseeds [ i ] , peerCallbackFunc , t ) ;
tr_ptrArrayAppend ( & t - > webseeds , w ) ;
2012-10-05 22:04:08 +00:00
}
}
2007-10-02 16:12:44 +00:00
static Torrent *
2012-12-05 17:29:46 +00:00
torrentNew ( tr_peerMgr * manager , tr_torrent * tor )
2007-10-02 16:12:44 +00:00
{
Torrent * t ;
2012-12-05 17:29:46 +00:00
t = tr_new0 ( Torrent , 1 ) ;
2007-10-02 16:12:44 +00:00
t - > manager = manager ;
t - > tor = tor ;
2008-12-29 08:54:36 +00:00
t - > pool = TR_PTR_ARRAY_INIT ;
t - > peers = TR_PTR_ARRAY_INIT ;
t - > webseeds = TR_PTR_ARRAY_INIT ;
t - > outgoingHandshakes = TR_PTR_ARRAY_INIT ;
2007-10-02 16:12:44 +00:00
2012-12-05 17:29:46 +00:00
rebuildWebseedArray ( t , tor ) ;
2008-06-07 21:26:41 +00:00
2007-10-02 16:12:44 +00:00
return t ;
}
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
{
2012-12-05 17:29:46 +00:00
tr_peerMgr * m = tr_new0 ( tr_peerMgr , 1 ) ;
2008-09-17 19:44:24 +00:00
m - > session = session ;
2008-12-29 08:54:36 +00:00
m - > incomingHandshakes = TR_PTR_ARRAY_INIT ;
2012-12-05 17:29:46 +00:00
ensureMgrTimersExist ( m ) ;
2009-05-13 20:54:35 +00:00
return m ;
}
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
{
2012-12-05 17:29:46 +00:00
if ( * t ! = NULL )
2009-12-10 05:52:46 +00:00
{
2012-12-05 17:29:46 +00:00
event_free ( * t ) ;
2009-12-10 05:52:46 +00:00
* t = NULL ;
}
}
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
{
2012-12-05 17:29:46 +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
{
2012-12-05 17:29:46 +00:00
managerLock ( manager ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
deleteTimers ( manager ) ;
2008-09-17 19:44:24 +00:00
2012-12-05 17:29:46 +00:00
/* free the handshakes. Abort invokes handshakeDoneCB (), which removes
2007-10-02 14:35:02 +00:00
* the item from manager - > handshakes , so this is a little roundabout . . . */
2012-12-05 17:29:46 +00:00
while ( ! tr_ptrArrayEmpty ( & manager - > incomingHandshakes ) )
tr_handshakeAbort ( tr_ptrArrayNth ( & manager - > incomingHandshakes , 0 ) ) ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
tr_ptrArrayDestruct ( & manager - > incomingHandshakes , NULL ) ;
2007-10-02 14:35:02 +00:00
2012-12-05 17:29:46 +00:00
managerUnlock ( manager ) ;
tr_free ( manager ) ;
2007-09-20 16:32:01 +00:00
}
2008-02-10 04:03:19 +00:00
static int
2012-12-05 17:29:46 +00:00
clientIsDownloadingFrom ( const tr_torrent * tor , const tr_peer * peer )
2008-02-10 04:03:19 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! tr_torrentHasMetadata ( tor ) )
2011-03-22 15:19:54 +00:00
return true ;
2009-11-24 15:51:16 +00:00
2008-02-10 04:03:19 +00:00
return peer - > clientIsInterested & & ! peer - > clientIsChoked ;
}
static int
2012-12-05 17:29:46 +00:00
clientIsUploadingTo ( const tr_peer * peer )
2008-02-10 04:03:19 +00:00
{
return peer - > peerIsInterested & & ! peer - > peerIsChoked ;
}
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
{
tr_torrent * tor = NULL ;
tr_session * session = mgr - > session ;
/* we cache whether or not a peer is blocklisted...
since the blocklist has changed , erase that cached value */
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2010-06-14 12:01:50 +00:00
{
int i ;
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
const int n = tr_ptrArraySize ( & t - > pool ) ;
for ( i = 0 ; i < n ; + + i ) {
struct peer_atom * atom = tr_ptrArrayNth ( & t - > pool , i ) ;
2010-06-14 12:01:50 +00:00
atom - > blocklisted = - 1 ;
}
}
}
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
{
2012-12-05 17:29:46 +00:00
if ( atom - > blocklisted < 0 )
atom - > blocklisted = tr_sessionIsAddressBlocked ( session , & atom - > addr ) ;
2010-06-14 12:01:50 +00:00
2012-12-05 17:29:46 +00:00
assert ( tr_isBool ( atom - > blocklisted ) ) ;
2010-06-14 12:01:50 +00:00
return atom - > blocklisted ;
}
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
{
2012-12-05 17:29:46 +00:00
assert ( atom ! = NULL ) ;
assert ( - 1 < = seedProbability & & seedProbability < = 100 ) ;
2010-04-20 21:54:03 +00:00
atom - > seedProbability = seedProbability ;
2012-12-05 17:29:46 +00:00
if ( seedProbability = = 100 )
2010-04-20 21:54:03 +00:00
atom - > flags | = ADDED_F_SEED_FLAG ;
2012-12-05 17:29:46 +00:00
else if ( seedProbability ! = - 1 )
2010-04-20 21:54:03 +00:00
atom - > flags & = ~ ADDED_F_SEED_FLAG ;
}
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
{
return atom - > seedProbability = = 100 ;
}
2011-02-24 14:35:45 +00:00
static void
2012-12-05 17:29:46 +00:00
atomSetSeed ( const Torrent * t , struct peer_atom * atom )
2011-02-24 14:35:45 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! atomIsSeed ( atom ) )
2011-02-24 14:35:45 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " marking peer %s as a seed " , tr_atomAddrStr ( atom ) ) ;
2011-02-24 14:35:45 +00:00
2012-12-05 17:29:46 +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
{
2011-03-22 15:19:54 +00:00
bool isSeed = false ;
2009-01-13 21:00:05 +00:00
const Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
const struct peer_atom * atom = getExistingAtom ( t , addr ) ;
2008-04-17 03:48:56 +00:00
2012-12-05 17:29:46 +00:00
if ( atom )
isSeed = atomIsSeed ( atom ) ;
2008-04-17 03:48:56 +00:00
return isSeed ;
}
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
{
2012-12-05 17:29:46 +00:00
struct peer_atom * atom = getExistingAtom ( tor - > torrentPeers , addr ) ;
2011-02-18 00:41:06 +00:00
2012-12-05 17:29:46 +00:00
if ( atom )
2011-02-18 00:41:06 +00:00
atom - > flags | = ADDED_F_UTP_FLAGS ;
}
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
{
2012-12-05 17:29:46 +00:00
struct peer_atom * atom = getExistingAtom ( tor - > torrentPeers , addr ) ;
2011-02-18 00:43:31 +00:00
2012-12-05 17:29:46 +00:00
if ( atom )
2011-02-18 00:43:31 +00:00
atom - > utp_failed = failed ;
}
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
* * *
2009-11-08 23:20:00 +00:00
* * * 1. Torrent : : requests , an array of " struct block_request " which keeps
* * * 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
* * *
2009-11-08 23:20:00 +00:00
* * * 2. Torrent : : 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
{
2009-11-08 23:20:00 +00:00
const struct block_request * a = va ;
const struct block_request * b = vb ;
2009-12-15 20:13:34 +00:00
/* primary key: block */
2012-12-05 17:29:46 +00:00
if ( a - > block < b - > block ) return - 1 ;
if ( a - > block > b - > block ) return 1 ;
2009-12-15 20:13:34 +00:00
/* secondary key: peer */
2012-12-05 17:29:46 +00:00
if ( a - > peer < b - > peer ) return - 1 ;
if ( a - > peer > b - > peer ) return 1 ;
2009-12-15 20:13:34 +00:00
2009-11-08 23:20:00 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
2009-11-08 23:20:00 +00:00
static void
2012-12-05 17:29:46 +00:00
requestListAdd ( Torrent * t , tr_block_index_t block , tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
struct block_request key ;
2009-11-02 00:17:30 +00:00
2009-11-08 23:20:00 +00:00
/* ensure enough room is available... */
2012-12-05 17:29:46 +00:00
if ( t - > requestCount + 1 > = t - > requestAlloc )
2009-11-08 23:20:00 +00:00
{
const int CHUNK_SIZE = 128 ;
t - > requestAlloc + = CHUNK_SIZE ;
2012-12-05 17:29:46 +00:00
t - > requests = tr_renew ( struct block_request ,
t - > requests , t - > requestAlloc ) ;
2009-11-08 23:20:00 +00:00
}
2007-09-20 16:32:01 +00:00
2009-11-08 23:20:00 +00:00
/* populate the record we're inserting */
key . block = block ;
key . peer = peer ;
2012-12-05 17:29:46 +00:00
key . sentAt = tr_time ( ) ;
2009-11-02 00:17:30 +00:00
2009-11-08 23:20:00 +00:00
/* insert the request to our array... */
{
2011-03-22 15:19:54 +00:00
bool exact ;
2012-12-05 17:29:46 +00:00
const int pos = tr_lowerBound ( & key , t - > requests , t - > requestCount ,
sizeof ( struct block_request ) ,
compareReqByBlock , & exact ) ;
assert ( ! exact ) ;
memmove ( t - > requests + pos + 1 ,
2010-02-22 15:07:14 +00:00
t - > requests + pos ,
2012-12-05 17:29:46 +00:00
sizeof ( struct block_request ) * ( t - > requestCount + + - pos ) ) ;
2010-02-22 15:07:14 +00:00
t - > requests [ pos ] = key ;
2009-11-08 23:20:00 +00:00
}
2009-12-16 18:20:01 +00:00
2012-12-05 17:29:46 +00:00
if ( peer ! = NULL )
2009-12-16 18:20:01 +00:00
{
+ + peer - > pendingReqsToPeer ;
2012-12-05 17:29:46 +00:00
assert ( peer - > pendingReqsToPeer > = 0 ) ;
2009-12-16 18:20:01 +00:00
}
2012-12-05 17:29:46 +00:00
/*fprintf (stderr, "added request of block %lu from peer %s... "
2009-12-15 21:33:24 +00:00
" there are now %d block \n " ,
2012-12-05 17:29:46 +00:00
( unsigned long ) block , tr_atomAddrStr ( peer - > atom ) , t - > 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 *
2012-12-05 17:29:46 +00:00
requestListLookup ( Torrent * t , tr_block_index_t block , const tr_peer * peer )
2008-10-25 02:20:16 +00:00
{
2009-11-08 23:20:00 +00:00
struct block_request key ;
key . block = block ;
2009-12-15 20:13:34 +00:00
key . peer = ( tr_peer * ) peer ;
2008-10-11 04:07:50 +00:00
2012-12-05 17:29:46 +00:00
return bsearch ( & key , t - > requests , t - > 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
2012-12-05 17:29:46 +00:00
getBlockRequestPeers ( Torrent * t , tr_block_index_t block ,
tr_ptrArray * peerArr )
2009-12-15 20:13:34 +00:00
{
2011-03-22 15:19:54 +00:00
bool exact ;
2011-02-15 16:04:56 +00:00
int i , pos ;
2009-12-15 20:13:34 +00:00
struct block_request key ;
key . block = block ;
key . peer = NULL ;
2012-12-05 17:29:46 +00:00
pos = tr_lowerBound ( & key , t - > requests , t - > requestCount ,
sizeof ( struct block_request ) ,
compareReqByBlock , & exact ) ;
2009-12-15 20:13:34 +00:00
2012-12-05 17:29:46 +00:00
assert ( ! exact ) ; /* shouldn't have a request with .peer == NULL */
2009-12-15 20:13:34 +00:00
2012-12-05 17:29:46 +00:00
for ( i = pos ; i < t - > requestCount ; + + i )
2011-02-15 16:04:56 +00:00
{
2012-12-05 17:29:46 +00:00
if ( t - > requests [ i ] . block ! = block )
2009-12-15 20:13:34 +00:00
break ;
2012-12-05 17:29:46 +00:00
tr_ptrArrayAppend ( peerArr , t - > 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
{
2012-12-05 17:29:46 +00:00
if ( b - > peer ! = NULL )
if ( b - > peer - > pendingReqsToPeer > 0 )
2010-01-25 05:19:54 +00:00
- - b - > peer - > pendingReqsToPeer ;
}
2009-11-08 23:20:00 +00:00
static void
2012-12-05 17:29:46 +00:00
requestListRemove ( Torrent * t , tr_block_index_t block , const tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
2012-12-05 17:29:46 +00:00
const struct block_request * b = requestListLookup ( t , block , peer ) ;
if ( b ! = NULL )
2008-10-11 04:07:50 +00:00
{
2009-11-08 23:20:00 +00:00
const int pos = b - t - > requests ;
2012-12-05 17:29:46 +00:00
assert ( pos < t - > requestCount ) ;
2009-12-16 18:20:01 +00:00
2012-12-05 17:29:46 +00:00
decrementPendingReqCount ( b ) ;
2009-12-16 18:20:01 +00:00
2012-12-05 17:29:46 +00:00
tr_removeElementFromArray ( t - > requests ,
2010-03-03 04:16:18 +00:00
pos ,
2012-12-05 17:29:46 +00:00
sizeof ( struct block_request ) ,
t - > requestCount - - ) ;
2010-03-03 04:16:18 +00:00
2012-12-05 17:29:46 +00:00
/*fprintf (stderr, "removing request of block %lu from peer %s... "
2009-12-15 21:33:24 +00:00
" 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
2012-12-05 17:29:46 +00:00
countActiveWebseeds ( const Torrent * t )
2011-02-17 05:14:53 +00:00
{
int activeCount = 0 ;
2012-12-05 17:29:46 +00:00
const tr_webseed * * w = ( const tr_webseed * * ) tr_ptrArrayBase ( & t - > webseeds ) ;
const tr_webseed * * const wend = w + tr_ptrArraySize ( & t - > webseeds ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
for ( ; w ! = wend ; + + w )
if ( tr_webseedIsActive ( * w ) )
2011-02-17 05:14:53 +00:00
+ + activeCount ;
return activeCount ;
}
2011-03-28 16:31:05 +00:00
static bool
2012-12-05 17:29:46 +00:00
testForEndgame ( const Torrent * t )
2011-03-28 16:31:05 +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 */
2012-12-05 17:29:46 +00:00
return ( t - > requestCount * t - > tor - > blockSize )
> = tr_cpLeftUntilDone ( & t - > tor - > completion ) ;
2011-03-28 16:31:05 +00:00
}
2011-02-17 05:14:53 +00:00
static void
2012-12-05 17:29:46 +00:00
updateEndgame ( Torrent * t )
2009-11-08 23:20:00 +00:00
{
2012-12-05 17:29:46 +00:00
assert ( t - > requestCount > = 0 ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
if ( ! testForEndgame ( t ) )
2011-02-17 05:14:53 +00:00
{
/* not in endgame */
t - > endgame = 0 ;
}
2012-12-05 17:29:46 +00:00
else if ( ! t - > endgame ) /* only recalculate when endgame first begins */
2011-02-17 05:14:53 +00:00
{
int numDownloading = 0 ;
2012-12-05 17:29:46 +00:00
const tr_peer * * p = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
const tr_peer * * const pend = p + tr_ptrArraySize ( & t - > peers ) ;
2011-02-17 05:14:53 +00:00
/* add the active bittorrent peers... */
2012-12-05 17:29:46 +00:00
for ( ; p ! = pend ; + + p )
if ( ( * p ) - > pendingReqsToPeer > 0 )
2011-02-17 05:14:53 +00:00
+ + numDownloading ;
/* add the active webseeds... */
2012-12-05 17:29:46 +00:00
numDownloading + = countActiveWebseeds ( t ) ;
2011-02-17 05:14:53 +00:00
/* average number of pending requests per downloading peer */
2012-12-05 17:29:46 +00:00
t - > endgame = t - > requestCount / MAX ( numDownloading , 1 ) ;
2011-02-17 05:14:53 +00:00
}
}
/****
* * * * *
* * * * * Piece List Manipulation / Accessors
* * * * *
* * * */
static inline void
2012-12-05 17:29:46 +00:00
invalidatePieceSorting ( Torrent * t )
2011-02-17 05:14:53 +00:00
{
t - > pieceSortState = PIECES_UNSORTED ;
}
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
2012-12-05 17:29:46 +00:00
setComparePieceByWeightTorrent ( Torrent * t )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! replicationExists ( t ) )
replicationNew ( t ) ;
2011-02-17 05:14:53 +00:00
weightTorrent = t - > tor ;
weightReplication = t - > pieceReplication ;
}
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
{
const struct weighted_piece * a = va ;
const struct weighted_piece * b = vb ;
int ia , ib , missing , pending ;
const tr_torrent * tor = weightTorrent ;
2011-02-17 05:14:53 +00:00
const uint16_t * rep = weightReplication ;
2009-11-02 00:17:30 +00:00
2009-11-08 23:20:00 +00:00
/* primary key: weight */
2012-12-05 17:29:46 +00:00
missing = tr_cpMissingBlocksInPiece ( & tor - > completion , a - > index ) ;
2009-11-08 23:20:00 +00:00
pending = a - > requestCount ;
2011-02-12 17:27:47 +00:00
ia = missing > pending ? missing - pending : ( tor - > blockCountInPiece + pending ) ;
2012-12-05 17:29:46 +00:00
missing = tr_cpMissingBlocksInPiece ( & tor - > completion , b - > index ) ;
2009-11-08 23:20:00 +00:00
pending = b - > requestCount ;
2011-02-12 17:27:47 +00:00
ib = missing > pending ? missing - pending : ( tor - > blockCountInPiece + pending ) ;
2012-12-05 17:29:46 +00:00
if ( ia < ib ) return - 1 ;
if ( ia > ib ) return 1 ;
2008-10-11 04:07:50 +00:00
2009-11-08 23:20:00 +00:00
/* secondary key: higher priorities go first */
ia = tor - > info . pieces [ a - > index ] . priority ;
ib = tor - > info . pieces [ b - > index ] . priority ;
2012-12-05 17:29:46 +00:00
if ( ia > ib ) return - 1 ;
if ( ia < ib ) return 1 ;
2009-11-08 23:20:00 +00:00
2011-02-17 05:14:53 +00:00
/* tertiary key: rarest first. */
ia = rep [ a - > index ] ;
ib = rep [ b - > index ] ;
2012-12-05 17:29:46 +00:00
if ( ia < ib ) return - 1 ;
if ( ia > ib ) return 1 ;
2011-02-17 05:14:53 +00:00
/* quaternary key: random */
2012-12-05 17:29:46 +00:00
if ( a - > salt < b - > salt ) return - 1 ;
if ( a - > salt > b - > salt ) return 1 ;
2009-12-24 01:02:54 +00:00
/* 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
{
2009-11-08 23:20:00 +00:00
const struct weighted_piece * a = va ;
const struct weighted_piece * b = vb ;
2012-12-05 17:29:46 +00:00
if ( a - > index < b - > index ) return - 1 ;
if ( a - > index > b - > index ) return 1 ;
2009-11-08 23:20:00 +00:00
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
2012-12-05 17:29:46 +00:00
pieceListSort ( Torrent * t , enum piece_sort_state state )
2009-11-01 02:10:47 +00:00
{
2012-12-05 17:29:46 +00:00
assert ( state = = PIECES_SORTED_BY_INDEX
| | state = = PIECES_SORTED_BY_WEIGHT ) ;
2009-11-08 23:20:00 +00:00
2010-10-11 21:44:46 +00:00
2012-12-05 17:29:46 +00:00
if ( state = = PIECES_SORTED_BY_WEIGHT )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
setComparePieceByWeightTorrent ( t ) ;
qsort ( t - > pieces , t - > pieceCount , sizeof ( struct weighted_piece ) , comparePieceByWeight ) ;
2011-02-17 05:14:53 +00:00
}
2010-10-11 21:44:46 +00:00
else
2012-12-05 17:29:46 +00:00
qsort ( t - > pieces , t - > pieceCount , sizeof ( struct weighted_piece ) , comparePieceByIndex ) ;
2011-02-15 16:04:56 +00:00
2011-02-17 05:14:53 +00:00
t - > 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 *
2012-12-05 17:29:46 +00:00
pieceListLookup ( Torrent * t , tr_piece_index_t index )
2009-11-02 00:17:30 +00:00
{
2010-03-03 04:16:18 +00:00
int i ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < t - > pieceCount ; + + i )
if ( t - > pieces [ i ] . index = = index )
2010-03-03 04:16:18 +00:00
return & t - > pieces [ i ] ;
2009-11-08 23:20:00 +00:00
2010-03-03 04:16:18 +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
2012-12-05 17:29:46 +00:00
pieceListRebuild ( Torrent * t )
2009-11-01 02:10:47 +00:00
{
2010-03-03 04:16:18 +00:00
2012-12-05 17:29:46 +00:00
if ( ! tr_torrentIsSeed ( t - > tor ) )
2009-11-02 00:17:30 +00:00
{
2009-11-08 23:20:00 +00:00
tr_piece_index_t i ;
tr_piece_index_t * pool ;
tr_piece_index_t poolCount = 0 ;
const tr_torrent * tor = t - > tor ;
2012-12-05 17:29:46 +00:00
const tr_info * inf = tr_torrentInfo ( tor ) ;
2009-11-08 23:20:00 +00:00
struct weighted_piece * pieces ;
int pieceCount ;
/* build the new list */
2012-12-05 17:29:46 +00:00
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 ) )
2009-11-08 23:20:00 +00:00
pool [ poolCount + + ] = i ;
pieceCount = poolCount ;
2012-12-05 17:29:46 +00:00
pieces = tr_new0 ( struct weighted_piece , pieceCount ) ;
for ( i = 0 ; i < poolCount ; + + i ) {
2009-11-08 23:20:00 +00:00
struct weighted_piece * piece = pieces + i ;
piece - > index = pool [ i ] ;
piece - > requestCount = 0 ;
2012-12-05 17:29:46 +00:00
piece - > salt = tr_cryptoWeakRandInt ( 4096 ) ;
2009-11-08 23:20:00 +00:00
}
2009-11-02 00:17:30 +00:00
2009-11-08 23:20:00 +00:00
/* if we already had a list of pieces, merge it into
* the new list so we don ' t lose its requestCounts */
2012-12-05 17:29:46 +00:00
if ( t - > pieces ! = NULL )
2009-11-08 23:20:00 +00:00
{
struct weighted_piece * o = t - > pieces ;
struct weighted_piece * oend = o + t - > pieceCount ;
struct weighted_piece * n = pieces ;
struct weighted_piece * nend = n + pieceCount ;
2012-12-05 17:29:46 +00:00
pieceListSort ( t , PIECES_SORTED_BY_INDEX ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
while ( o ! = oend & & n ! = nend ) {
if ( o - > index < n - > index )
2009-11-08 23:20:00 +00:00
+ + o ;
2012-12-05 17:29:46 +00:00
else if ( o - > index > n - > index )
2009-11-08 23:20:00 +00:00
+ + n ;
else
* n + + = * o + + ;
}
2008-10-11 04:07:50 +00:00
2012-12-05 17:29:46 +00:00
tr_free ( t - > pieces ) ;
2009-11-08 23:20:00 +00:00
}
2008-02-10 04:03:19 +00:00
2009-11-08 23:20:00 +00:00
t - > pieces = pieces ;
t - > pieceCount = pieceCount ;
2010-01-12 20:17:22 +00:00
2012-12-05 17:29:46 +00:00
pieceListSort ( t , PIECES_SORTED_BY_WEIGHT ) ;
2009-11-08 23:20:00 +00:00
/* cleanup */
2012-12-05 17:29:46 +00:00
tr_free ( pool ) ;
2008-02-10 04:03:19 +00:00
}
}
2009-11-08 23:20:00 +00:00
static void
2012-12-05 17:29:46 +00:00
pieceListRemovePiece ( Torrent * t , tr_piece_index_t piece )
2008-10-25 15:19:46 +00:00
{
2010-03-03 04:16:18 +00:00
struct weighted_piece * p ;
2012-12-05 17:29:46 +00:00
if ( ( p = pieceListLookup ( t , piece ) ) )
2009-11-08 23:20:00 +00:00
{
const int pos = p - t - > pieces ;
2009-11-02 00:17:30 +00:00
2012-12-05 17:29:46 +00:00
tr_removeElementFromArray ( t - > pieces ,
2010-03-03 04:16:18 +00:00
pos ,
2012-12-05 17:29:46 +00:00
sizeof ( struct weighted_piece ) ,
t - > pieceCount - - ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
if ( t - > pieceCount = = 0 )
2009-11-08 23:20:00 +00:00
{
2012-12-05 17:29:46 +00:00
tr_free ( t - > pieces ) ;
2009-11-08 23:20:00 +00:00
t - > pieces = NULL ;
2009-11-02 00:17:30 +00:00
}
}
}
2009-10-27 20:06:55 +00:00
static void
2012-12-05 17:29:46 +00:00
pieceListResortPiece ( Torrent * t , struct weighted_piece * p )
2009-11-08 23:20:00 +00:00
{
2010-03-03 04:16:18 +00:00
int pos ;
2011-03-22 15:19:54 +00:00
bool isSorted = true ;
2010-03-03 04:16:18 +00:00
2012-12-05 17:29:46 +00:00
if ( p = = NULL )
2010-03-03 04:16:18 +00:00
return ;
/* is the torrent already sorted? */
pos = p - t - > pieces ;
2012-12-05 17:29:46 +00:00
setComparePieceByWeightTorrent ( t ) ;
if ( isSorted & & ( pos > 0 ) & & ( comparePieceByWeight ( p - 1 , p ) > 0 ) )
2011-03-22 15:19:54 +00:00
isSorted = false ;
2012-12-05 17:29:46 +00:00
if ( isSorted & & ( pos < t - > pieceCount - 1 ) & & ( comparePieceByWeight ( p , p + 1 ) > 0 ) )
2011-03-22 15:19:54 +00:00
isSorted = false ;
2010-01-12 20:17:22 +00:00
2012-12-05 17:29:46 +00:00
if ( t - > pieceSortState ! = PIECES_SORTED_BY_WEIGHT )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
pieceListSort ( t , PIECES_SORTED_BY_WEIGHT ) ;
2011-03-22 15:19:54 +00:00
isSorted = true ;
2011-02-17 05:14:53 +00:00
}
2010-03-03 04:16:18 +00:00
/* if it's not sorted, move it around */
2012-12-05 17:29:46 +00:00
if ( ! isSorted )
2010-01-12 20:17:22 +00:00
{
2011-03-22 15:19:54 +00:00
bool exact ;
2010-03-03 04:16:18 +00:00
const struct weighted_piece tmp = * p ;
2009-10-27 20:06:55 +00:00
2012-12-05 17:29:46 +00:00
tr_removeElementFromArray ( t - > pieces ,
2010-03-03 04:16:18 +00:00
pos ,
2012-12-05 17:29:46 +00:00
sizeof ( struct weighted_piece ) ,
t - > pieceCount - - ) ;
2010-01-12 20:17:22 +00:00
2012-12-05 17:29:46 +00:00
pos = tr_lowerBound ( & tmp , t - > pieces , t - > pieceCount ,
sizeof ( struct weighted_piece ) ,
comparePieceByWeight , & exact ) ;
2010-01-12 20:17:22 +00:00
2012-12-05 17:29:46 +00:00
memmove ( & t - > pieces [ pos + 1 ] ,
2010-03-03 04:16:18 +00:00
& t - > pieces [ pos ] ,
2012-12-05 17:29:46 +00:00
sizeof ( struct weighted_piece ) * ( t - > pieceCount + + - pos ) ) ;
2009-11-08 23:20:00 +00:00
2010-03-03 04:16:18 +00:00
t - > pieces [ pos ] = tmp ;
}
2010-01-12 20:17:22 +00:00
2012-12-05 17:29:46 +00:00
assertWeightedPiecesAreSorted ( t ) ;
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
2012-12-05 17:29:46 +00:00
pieceListRemoveRequest ( Torrent * t , tr_block_index_t block )
2010-03-03 04:16:18 +00:00
{
struct weighted_piece * p ;
2012-12-05 17:29:46 +00:00
const tr_piece_index_t index = tr_torBlockPiece ( t - > tor , block ) ;
2010-01-12 20:17:22 +00:00
2012-12-05 17:29:46 +00:00
if ( ( ( p = pieceListLookup ( t , index ) ) ) & & ( p - > requestCount > 0 ) )
2010-03-03 04:16:18 +00:00
{
- - p - > requestCount ;
2012-12-05 17:29:46 +00:00
pieceListResortPiece ( t , 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
2012-12-05 17:29:46 +00:00
tr_incrReplicationOfPiece ( Torrent * t , const size_t index )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
assert ( replicationExists ( t ) ) ;
assert ( t - > pieceReplicationSize = = t - > tor - > info . pieceCount ) ;
2011-02-17 05:14:53 +00:00
/* One more replication of this piece is present in the swarm */
+ + t - > pieceReplication [ index ] ;
/* we only resort the piece if the list is already sorted */
2012-12-05 17:29:46 +00:00
if ( t - > pieceSortState = = PIECES_SORTED_BY_WEIGHT )
pieceListResortPiece ( t , pieceListLookup ( t , index ) ) ;
2011-02-17 05:14:53 +00:00
}
/**
* Increases the replication count of pieces present in the bitfield
*/
static void
2012-12-05 17:29:46 +00:00
tr_incrReplicationFromBitfield ( Torrent * t , const tr_bitfield * b )
2011-02-17 05:14:53 +00:00
{
size_t i ;
uint16_t * rep = t - > pieceReplication ;
const size_t n = t - > tor - > info . pieceCount ;
2012-12-05 17:29:46 +00:00
assert ( replicationExists ( t ) ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n ; + + i )
if ( tr_bitfieldHas ( b , i ) )
2011-02-17 12:57:36 +00:00
+ + rep [ i ] ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
if ( t - > pieceSortState = = PIECES_SORTED_BY_WEIGHT )
invalidatePieceSorting ( t ) ;
2011-02-17 05:14:53 +00:00
}
/**
* Increase the replication count of every piece
*/
static void
2012-12-05 17:29:46 +00:00
tr_incrReplication ( Torrent * t )
2011-02-17 05:14:53 +00:00
{
int i ;
const int n = t - > pieceReplicationSize ;
2012-12-05 17:29:46 +00:00
assert ( replicationExists ( t ) ) ;
assert ( t - > pieceReplicationSize = = t - > tor - > info . pieceCount ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n ; + + i )
2011-02-17 05:14:53 +00:00
+ + t - > pieceReplication [ i ] ;
}
/**
* Decrease the replication count of pieces present in the bitset .
*/
static void
2012-12-05 17:29:46 +00:00
tr_decrReplicationFromBitfield ( Torrent * t , const tr_bitfield * b )
2011-02-17 05:14:53 +00:00
{
int i ;
const int n = t - > pieceReplicationSize ;
2012-12-05 17:29:46 +00:00
assert ( replicationExists ( t ) ) ;
assert ( t - > pieceReplicationSize = = t - > tor - > info . pieceCount ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
if ( tr_bitfieldHasAll ( b ) )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n ; + + i )
2011-02-17 05:14:53 +00:00
- - t - > pieceReplication [ i ] ;
}
2012-12-05 17:29:46 +00:00
else if ( ! tr_bitfieldHasNone ( b ) )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n ; + + i )
if ( tr_bitfieldHas ( b , i ) )
2011-02-17 12:57:36 +00:00
- - t - > pieceReplication [ i ] ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
if ( t - > pieceSortState = = PIECES_SORTED_BY_WEIGHT )
invalidatePieceSorting ( t ) ;
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
{
2012-12-05 17:29:46 +00:00
assert ( tr_isTorrent ( tor ) ) ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
pieceListRebuild ( tor - > torrentPeers ) ;
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
{
int i ;
int got ;
Torrent * t ;
struct weighted_piece * pieces ;
2011-03-28 16:31:05 +00:00
const tr_bitfield * const have = & peer - > have ;
2007-09-29 06:37:03 +00:00
2009-11-08 23:20:00 +00:00
/* sanity clause */
2012-12-05 17:29:46 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( peer - > clientIsInterested ) ;
assert ( ! peer - > clientIsChoked ) ;
assert ( numwant > 0 ) ;
2009-02-18 17:19:36 +00:00
2009-11-08 23:20:00 +00:00
/* walk through the pieces and find blocks that should be requested */
got = 0 ;
t = tor - > torrentPeers ;
2008-06-07 21:26:41 +00:00
2009-11-08 23:20:00 +00:00
/* prep the pieces list */
2012-12-05 17:29:46 +00:00
if ( t - > pieces = = NULL )
pieceListRebuild ( t ) ;
2010-01-12 20:17:22 +00:00
2012-12-05 17:29:46 +00:00
if ( t - > pieceSortState ! = PIECES_SORTED_BY_WEIGHT )
pieceListSort ( t , PIECES_SORTED_BY_WEIGHT ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
assertReplicationCountIsExact ( t ) ;
assertWeightedPiecesAreSorted ( t ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
updateEndgame ( t ) ;
2009-11-08 23:20:00 +00:00
pieces = t - > pieces ;
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < t - > pieceCount & & got < numwant ; + + i )
2009-11-08 23:20:00 +00:00
{
struct weighted_piece * p = pieces + i ;
2009-02-18 22:25:13 +00:00
2009-11-08 23:20:00 +00:00
/* if the peer has this piece that we want... */
2012-12-05 17:29:46 +00:00
if ( tr_bitfieldHas ( have , p - > index ) )
2007-09-20 16:32:01 +00:00
{
2011-02-23 03:54:04 +00:00
tr_block_index_t b ;
tr_block_index_t first ;
tr_block_index_t last ;
2011-02-15 16:04:56 +00:00
tr_ptrArray peerArr = TR_PTR_ARRAY_INIT ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
tr_torGetPieceBlockRange ( tor , p - > index , & first , & last ) ;
2011-02-23 03:54:04 +00:00
2012-12-05 17:29:46 +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
{
2011-02-15 16:04:56 +00:00
int peerCount ;
tr_peer * * peers ;
2009-11-08 23:20:00 +00:00
/* don't request blocks we've already got */
2012-12-05 17:29:46 +00:00
if ( tr_cpBlockIsComplete ( & tor - > completion , b ) )
2009-11-08 23:20:00 +00:00
continue ;
2011-02-15 16:04:56 +00:00
/* always add peer if this block has no peers yet */
2012-12-05 17:29:46 +00:00
tr_ptrArrayClear ( & peerArr ) ;
getBlockRequestPeers ( t , b , & peerArr ) ;
peers = ( tr_peer * * ) tr_ptrArrayPeek ( & peerArr , & peerCount ) ;
if ( peerCount ! = 0 )
2011-02-15 16:04:56 +00:00
{
/* don't make a second block request until the endgame */
2012-12-05 17:29:46 +00:00
if ( ! t - > endgame )
2011-02-15 16:04:56 +00:00
continue ;
/* don't have more than two peers requesting this block */
2012-12-05 17:29:46 +00:00
if ( peerCount > 1 )
2011-02-15 16:04:56 +00:00
continue ;
/* don't send the same request to the same peer twice */
2012-12-05 17:29:46 +00:00
if ( peer = = peers [ 0 ] )
2011-02-15 16:04:56 +00:00
continue ;
/* in the endgame allow an additional peer to download a
block but only if the peer seems to be handling requests
relatively fast */
2012-12-05 17:29:46 +00:00
if ( peer - > pendingReqsToPeer + numwant - got < t - > endgame )
2011-02-15 16:04:56 +00:00
continue ;
}
2009-11-08 23:20:00 +00:00
2009-12-15 20:13:34 +00:00
/* update the caller's table */
2012-12-05 17:29:46 +00:00
if ( ! get_intervals ) {
2011-07-10 15:24:51 +00:00
setme [ got + + ] = b ;
}
/* if intervals are requested two array entries are necessarry:
one for the interval ' s starting block and one for its end block */
2012-12-05 17:29:46 +00:00
else if ( got & & setme [ 2 * got - 1 ] = = b - 1 & & b ! = first ) {
2011-07-10 15:24:51 +00:00
/* expand the last interval */
+ + setme [ 2 * got - 1 ] ;
}
else {
/* begin a new interval */
setme [ 2 * got ] = setme [ 2 * got + 1 ] = b ;
+ + got ;
}
2009-11-08 23:20:00 +00:00
/* update our own tables */
2012-12-05 17:29:46 +00:00
requestListAdd ( t , b , peer ) ;
2009-11-08 23:20:00 +00:00
+ + p - > requestCount ;
2007-09-20 16:32:01 +00:00
}
2011-02-15 16:04:56 +00:00
2012-12-05 17:29:46 +00:00
tr_ptrArrayDestruct ( & peerArr , NULL ) ;
2007-09-20 16:32:01 +00:00
}
}
2009-12-02 15:16:29 +00:00
/* In most cases we've just changed the weights of a small number of pieces.
2012-12-05 17:29:46 +00:00
* So rather than qsort ( ) ing the entire array , it ' s faster to apply an
2010-01-12 20:17:22 +00:00
* adaptive insertion sort algorithm . */
2012-12-05 17:29:46 +00:00
if ( got > 0 )
2009-11-08 23:20:00 +00:00
{
2010-01-12 20:17:22 +00:00
/* not enough requests || last piece modified */
2012-12-05 17:29:46 +00:00
if ( i = = t - > pieceCount ) - - i ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
setComparePieceByWeightTorrent ( t ) ;
while ( - - i > = 0 )
2010-01-12 20:17:22 +00:00
{
2011-03-22 15:19:54 +00:00
bool exact ;
2009-02-04 16:58:52 +00:00
2010-01-12 20:17:22 +00:00
/* relative position! */
2012-12-05 17:29:46 +00:00
const int newpos = tr_lowerBound ( & t - > pieces [ i ] , & t - > pieces [ i + 1 ] ,
2010-01-12 20:17:22 +00:00
t - > pieceCount - ( i + 1 ) ,
2012-12-05 17:29:46 +00:00
sizeof ( struct weighted_piece ) ,
comparePieceByWeight , & exact ) ;
if ( newpos > 0 )
2010-01-12 20:17:22 +00:00
{
const struct weighted_piece piece = t - > pieces [ i ] ;
2012-12-05 17:29:46 +00:00
memmove ( & t - > pieces [ i ] ,
2010-01-12 20:17:22 +00:00
& t - > pieces [ i + 1 ] ,
2012-12-05 17:29:46 +00:00
sizeof ( struct weighted_piece ) * ( newpos ) ) ;
2010-01-12 20:17:22 +00:00
t - > pieces [ i + newpos ] = piece ;
}
}
2009-11-02 00:17:30 +00:00
}
2012-12-05 17:29:46 +00:00
assertWeightedPiecesAreSorted ( t ) ;
2009-11-08 23:20:00 +00:00
* 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
{
2009-11-08 23:20:00 +00:00
const Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
return requestListLookup ( ( Torrent * ) t , 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 ) ) )
cancel_buflen = MAX ( cancel_buflen , tor - > torrentPeers - > requestCount ) ;
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
{
Torrent * t = tor - > torrentPeers ;
const int n = t - > 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 ;
2012-12-05 17:29:46 +00:00
for ( it = t - > requests , end = it + n ; it ! = end ; + + it )
2010-01-20 18:48:52 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ( it - > sentAt < = too_old ) & & it - > peer - > msgs & & ! tr_peerMsgsIsReadingBlock ( it - > peer - > msgs , it - > block ) )
2009-11-08 23:20:00 +00:00
cancel [ cancelCount + + ] = * it ;
else
2010-01-20 18:48:52 +00:00
{
2012-12-05 17:29:46 +00:00
if ( it ! = & t - > requests [ keepCount ] )
2010-01-20 18:48:52 +00:00
t - > requests [ keepCount ] = * it ;
keepCount + + ;
}
}
2009-11-08 23:20:00 +00:00
/* prune out the ones we aren't keeping */
t - > 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 */
2012-12-05 17:29:46 +00:00
for ( it = cancel , end = it + cancelCount ; it ! = end ; + + it ) {
if ( ( it - > peer ! = NULL ) & & ( it - > peer - > msgs ! = NULL ) ) {
tr_historyAdd ( & it - > peer - > cancelsSentToPeer , now , 1 ) ;
tr_peerMsgsCancel ( it - > peer - > 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 )
pieceListRemoveRequest ( t , 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
2012-12-05 17:29:46 +00:00
addStrike ( Torrent * t , tr_peer * peer )
2007-11-13 05:36:43 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " increasing peer %s strike count to %d " ,
tr_atomAddrStr ( peer - > atom ) , peer - > strikes + 1 ) ;
2007-11-13 05:36:43 +00:00
2012-12-05 17:29:46 +00:00
if ( + + peer - > strikes > = MAX_BAD_PIECES_PER_PEER )
2007-11-13 05:36:43 +00:00
{
2009-05-09 06:08:21 +00:00
struct peer_atom * atom = peer - > atom ;
2010-12-14 18:33:48 +00:00
atom - > flags2 | = MYFLAG_BANNED ;
2007-11-13 05:36:43 +00:00
peer - > doPurge = 1 ;
2012-12-05 17:29:46 +00:00
tordbg ( t , " banning peer %s " , tr_atomAddrStr ( atom ) ) ;
2007-11-13 05:36:43 +00:00
}
}
2007-09-20 16:32:01 +00:00
static void
2012-12-05 17:29:46 +00:00
gotBadPiece ( Torrent * t , tr_piece_index_t pieceIndex )
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
tr_torrent * tor = t - > tor ;
2012-12-05 17:29:46 +00:00
const uint32_t byteCount = tr_torPieceCountBytes ( tor , pieceIndex ) ;
2008-09-23 19:11:04 +00:00
2008-06-07 21:26:41 +00:00
tor - > corruptCur + = byteCount ;
2012-12-05 17:29:46 +00:00
tor - > downloadedCur - = MIN ( tor - > downloadedCur , byteCount ) ;
2010-02-08 16:47:30 +00:00
2012-12-05 17:29:46 +00:00
tr_announcerAddBytes ( tor , TR_ANN_CORRUPT , byteCount ) ;
2008-06-07 21:26:41 +00:00
}
2008-12-02 17:10:54 +00:00
static void
2012-12-05 17:29:46 +00:00
peerSuggestedPiece ( Torrent * t 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
2012-12-05 17:29:46 +00:00
removeRequestFromTables ( Torrent * t , tr_block_index_t block , const tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
2012-12-05 17:29:46 +00:00
requestListRemove ( t , block , peer ) ;
pieceListRemoveRequest ( t , 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
2012-12-05 17:29:46 +00:00
peerDeclinedAllRequests ( Torrent * t , const tr_peer * peer )
2009-11-08 23:20:00 +00:00
{
int i , n ;
2012-12-05 17:29:46 +00:00
tr_block_index_t * blocks = tr_new ( tr_block_index_t , t - > requestCount ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
for ( i = n = 0 ; i < t - > requestCount ; + + i )
if ( peer = = t - > requests [ i ] . peer )
2009-11-08 23:20:00 +00:00
blocks [ n + + ] = t - > requests [ i ] . block ;
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n ; + + i )
removeRequestFromTables ( t , blocks [ i ] , peer ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
tr_free ( blocks ) ;
2009-11-08 23:20:00 +00:00
}
2012-12-05 17:29:46 +00:00
static void tr_peerMgrSetBlame ( tr_torrent * , tr_piece_index_t , int ) ;
2011-03-07 14:33:45 +00:00
2008-06-07 21:26:41 +00:00
static void
2012-12-05 17:29:46 +00:00
peerCallbackFunc ( tr_peer * peer , const tr_peer_event * e , void * vt )
2008-06-07 21:26:41 +00:00
{
2008-12-22 00:52:44 +00:00
Torrent * t = vt ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
torrentLock ( t ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
assert ( peer ! = NULL ) ;
2011-02-25 01:48:46 +00:00
2012-12-05 17:29:46 +00:00
switch ( e - > eventType )
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
case TR_PEER_PEER_GOT_DATA :
{
2012-12-05 17:29:46 +00:00
const time_t now = tr_time ( ) ;
2008-06-07 21:26:41 +00:00
tr_torrent * tor = t - > tor ;
2008-11-17 04:00:57 +00:00
2012-12-05 17:29:46 +00:00
if ( e - > wasPieceData )
2010-08-03 01:25:23 +00:00
{
2008-11-17 04:00:57 +00:00
tor - > uploadedCur + = e - > length ;
2012-12-05 17:29:46 +00:00
tr_announcerAddBytes ( tor , TR_ANN_UP , e - > length ) ;
tr_torrentSetActivityDate ( tor , now ) ;
tr_torrentSetDirty ( tor ) ;
2009-08-07 05:29:37 +00:00
}
2008-11-17 04:00:57 +00:00
/* update the stats */
2012-12-05 17:29:46 +00:00
if ( e - > wasPieceData )
tr_statsAddUploaded ( tor - > session , e - > length ) ;
2008-11-17 04:00:57 +00:00
/* update our atom */
2012-12-05 17:29:46 +00:00
if ( peer - > atom & & e - > wasPieceData )
2009-05-09 06:08:21 +00:00
peer - > atom - > piece_data_time = now ;
2008-11-17 04:00:57 +00:00
2008-01-05 18:17:56 +00:00
break ;
}
2011-02-17 05:14:53 +00:00
case TR_PEER_CLIENT_GOT_HAVE :
2012-12-05 17:29:46 +00:00
if ( replicationExists ( t ) ) {
tr_incrReplicationOfPiece ( t , e - > pieceIndex ) ;
assertReplicationCountIsExact ( t ) ;
2011-02-17 05:14:53 +00:00
}
break ;
case TR_PEER_CLIENT_GOT_HAVE_ALL :
2012-12-05 17:29:46 +00:00
if ( replicationExists ( t ) ) {
tr_incrReplication ( t ) ;
assertReplicationCountIsExact ( t ) ;
2011-02-17 05:14:53 +00:00
}
break ;
case TR_PEER_CLIENT_GOT_HAVE_NONE :
/* noop */
break ;
case TR_PEER_CLIENT_GOT_BITFIELD :
2012-12-05 17:29:46 +00:00
assert ( e - > bitfield ! = NULL ) ;
if ( replicationExists ( t ) ) {
tr_incrReplicationFromBitfield ( t , e - > bitfield ) ;
assertReplicationCountIsExact ( t ) ;
2011-02-17 05:14:53 +00:00
}
break ;
2011-03-21 16:42:32 +00:00
case TR_PEER_CLIENT_GOT_REJ : {
2012-12-05 17:29:46 +00:00
tr_block_index_t b = _tr_block ( t - > tor , e - > pieceIndex , e - > offset ) ;
if ( b < t - > tor - > blockCount )
removeRequestFromTables ( t , b , peer ) ;
2011-03-21 16:42:32 +00:00
else
2012-12-05 17:29:46 +00:00
tordbg ( t , " Peer %s sent an out-of-range reject message " ,
tr_atomAddrStr ( peer - > atom ) ) ;
2009-11-08 23:20:00 +00:00
break ;
2011-03-21 16:42:32 +00:00
}
2009-11-08 23:20:00 +00:00
case TR_PEER_CLIENT_GOT_CHOKE :
2012-12-05 17:29:46 +00:00
peerDeclinedAllRequests ( t , peer ) ;
2009-11-08 23:20:00 +00:00
break ;
2009-10-29 16:10:03 +00:00
case TR_PEER_CLIENT_GOT_PORT :
2012-12-05 17:29:46 +00:00
if ( peer - > atom )
2011-03-03 17:28:04 +00:00
peer - > atom - > port = e - > port ;
2009-10-29 16:10:03 +00:00
break ;
2008-12-02 17:10:54 +00:00
case TR_PEER_CLIENT_GOT_SUGGEST :
2012-12-05 17:29:46 +00:00
peerSuggestedPiece ( t , peer , e - > pieceIndex , false ) ;
2008-12-02 17:10:54 +00:00
break ;
case TR_PEER_CLIENT_GOT_ALLOWED_FAST :
2012-12-05 17:29:46 +00:00
peerSuggestedPiece ( t , peer , e - > pieceIndex , true ) ;
2008-12-02 17:10:54 +00:00
break ;
2008-09-23 19:11:04 +00:00
case TR_PEER_CLIENT_GOT_DATA :
{
2012-12-05 17:29:46 +00:00
const time_t now = tr_time ( ) ;
2008-06-07 21:26:41 +00:00
tr_torrent * tor = t - > tor ;
2009-03-28 16:47:01 +00:00
2012-12-05 17:29:46 +00:00
if ( e - > wasPieceData )
2010-08-03 01:25:23 +00:00
{
2008-06-09 22:53:45 +00:00
tor - > downloadedCur + = e - > length ;
2012-12-05 17:29:46 +00:00
tr_torrentSetActivityDate ( tor , now ) ;
tr_torrentSetDirty ( tor ) ;
2009-08-07 05:29:37 +00:00
}
2008-11-17 04:00:57 +00:00
2009-08-10 20:04:08 +00:00
/* update the stats */
2012-12-05 17:29:46 +00:00
if ( e - > wasPieceData )
tr_statsAddDownloaded ( tor - > session , e - > length ) ;
2008-11-17 04:00:57 +00:00
/* update our atom */
2012-12-05 17:29:46 +00:00
if ( peer - > atom & & e - > wasPieceData )
2009-05-09 06:08:21 +00:00
peer - > atom - > piece_data_time = now ;
2008-11-17 04:00:57 +00:00
2007-09-20 16:32:01 +00:00
break ;
2008-06-07 21:26:41 +00:00
}
2007-09-20 16:32:01 +00:00
2008-06-07 21:26:41 +00:00
case TR_PEER_CLIENT_GOT_BLOCK :
{
2009-01-12 21:59:53 +00:00
tr_torrent * tor = t - > tor ;
2012-12-05 17:29:46 +00:00
tr_block_index_t block = _tr_block ( tor , e - > pieceIndex , e - > offset ) ;
2011-02-15 16:04:56 +00:00
int i , peerCount ;
tr_peer * * peers ;
tr_ptrArray peerArr = TR_PTR_ARRAY_INIT ;
2012-12-05 17:29:46 +00:00
removeRequestFromTables ( t , block , peer ) ;
getBlockRequestPeers ( t , block , & peerArr ) ;
peers = ( tr_peer * * ) tr_ptrArrayPeek ( & peerArr , & peerCount ) ;
2011-02-15 16:04:56 +00:00
/* remove additional block requests and send cancel to peers */
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < peerCount ; i + + ) {
2011-02-15 16:04:56 +00:00
tr_peer * p = peers [ i ] ;
2012-12-05 17:29:46 +00:00
assert ( p ! = peer ) ;
if ( p - > msgs ) {
tr_historyAdd ( & p - > cancelsSentToPeer , tr_time ( ) , 1 ) ;
tr_peerMsgsCancel ( p - > msgs , block ) ;
2011-02-15 16:04:56 +00:00
}
2012-12-05 17:29:46 +00:00
removeRequestFromTables ( t , block , p ) ;
2011-02-15 16:04:56 +00:00
}
2008-06-07 21:26:41 +00:00
2012-12-05 17:29:46 +00:00
tr_ptrArrayDestruct ( & peerArr , false ) ;
2008-06-07 21:26:41 +00:00
2012-12-05 17:29:46 +00:00
tr_historyAdd ( & peer - > blocksSentToClient , tr_time ( ) , 1 ) ;
2010-03-08 04:29:58 +00:00
2012-12-05 17:29:46 +00:00
if ( tr_cpBlockIsComplete ( & tor - > completion , block ) )
2008-06-07 21:26:41 +00:00
{
2010-02-20 15:36:25 +00:00
/* we already have this block... */
2012-12-05 17:29:46 +00:00
const uint32_t n = tr_torBlockCountBytes ( tor , block ) ;
tor - > downloadedCur - = MIN ( tor - > downloadedCur , n ) ;
tordbg ( t , " we have this block already... " ) ;
2009-11-08 23:20:00 +00:00
}
else
{
2012-12-05 17:29:46 +00:00
tr_cpBlockAdd ( & tor - > completion , block ) ;
pieceListResortPiece ( t , pieceListLookup ( t , e - > pieceIndex ) ) ;
tr_torrentSetDirty ( tor ) ;
2008-06-07 21:26:41 +00:00
2012-12-05 17:29:46 +00:00
if ( tr_cpPieceIsComplete ( & tor - > completion , e - > pieceIndex ) )
2008-09-23 19:11:04 +00:00
{
2009-11-08 23:20:00 +00:00
const tr_piece_index_t p = e - > pieceIndex ;
2012-12-05 17:29:46 +00:00
const bool ok = tr_torrentCheckPiece ( tor , p ) ;
2010-12-09 20:43:23 +00:00
2012-12-05 17:29:46 +00:00
tordbg ( t , " [LAZY] checked just-completed piece %zu " , ( size_t ) p ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
if ( ! ok )
2009-11-08 23:20:00 +00:00
{
2012-12-07 01:53:31 +00:00
tr_torerr ( tor , _ ( " Piece %lu, which was just downloaded, failed its checksum test " ) ,
2012-12-05 17:29:46 +00:00
( unsigned long ) p ) ;
2009-11-08 23:20:00 +00:00
}
2008-06-07 21:26:41 +00:00
2012-12-05 17:29:46 +00:00
tr_peerMgrSetBlame ( tor , p , ok ) ;
2008-06-07 21:26:41 +00:00
2012-12-05 17:29:46 +00:00
if ( ! ok )
2009-11-08 23:20:00 +00:00
{
2012-12-05 17:29:46 +00:00
gotBadPiece ( t , p ) ;
2009-11-08 23:20:00 +00:00
}
else
{
int i ;
int peerCount ;
tr_peer * * peers ;
tr_file_index_t fileIndex ;
2010-02-20 15:36:25 +00:00
/* only add this to downloadedCur if we got it from a peer --
2010-12-27 19:18:17 +00:00
* webseeds shouldn ' t count against our ratio . As one tracker
2010-02-20 15:36:25 +00:00
* admin put it , " Those pieces are downloaded directly from the
* content distributor , not the peers , it is the tracker ' s job
* to manage the swarms , not the web server and does not fit
* into the jurisdiction of the tracker . " */
2012-12-05 17:29:46 +00:00
if ( peer - > msgs ! = NULL ) {
const uint32_t n = tr_torPieceCountBytes ( tor , p ) ;
tr_announcerAddBytes ( tor , TR_ANN_DOWN , n ) ;
2010-02-20 15:36:25 +00:00
}
2012-12-05 17:29:46 +00:00
peerCount = tr_ptrArraySize ( & t - > peers ) ;
peers = ( tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
for ( i = 0 ; i < peerCount ; + + i )
tr_peerMsgsHave ( peers [ i ] - > msgs , p ) ;
2009-11-08 23:20:00 +00:00
2012-12-05 17:29:46 +00:00
for ( fileIndex = 0 ; fileIndex < tor - > info . fileCount ; + + fileIndex ) {
2009-11-08 23:20:00 +00:00
const tr_file * file = & tor - > info . files [ fileIndex ] ;
2012-12-05 17:29:46 +00:00
if ( ( file - > firstPiece < = p ) & & ( p < = file - > lastPiece ) ) {
if ( tr_cpFileIsComplete ( & tor - > completion , fileIndex ) ) {
tr_cacheFlushFile ( tor - > session - > cache , tor , fileIndex ) ;
tr_torrentFileCompleted ( tor , fileIndex ) ;
2010-06-19 14:25:11 +00:00
}
}
2009-11-08 23:20:00 +00:00
}
2012-12-05 17:29:46 +00:00
pieceListRemovePiece ( t , p ) ;
2009-01-12 21:59:53 +00:00
}
2008-06-21 01:03:31 +00:00
}
2009-11-09 06:36:47 +00:00
2011-03-22 15:19:54 +00:00
t - > needsCompletenessCheck = true ;
2008-06-07 21:26:41 +00:00
}
2007-09-20 16:32:01 +00:00
break ;
2008-06-07 21:26:41 +00:00
}
2007-09-20 16:32:01 +00:00
2008-06-07 21:26:41 +00:00
case TR_PEER_ERROR :
2012-12-05 17:29:46 +00:00
if ( ( e - > err = = ERANGE ) | | ( e - > err = = EMSGSIZE ) | | ( e - > err = = ENOTCONN ) )
2008-09-23 19:11:04 +00:00
{
2008-10-03 04:49:06 +00:00
/* some protocol error from the peer */
peer - > doPurge = 1 ;
2012-12-05 17:29:46 +00:00
tordbg ( t , " setting %s doPurge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error " ,
tr_atomAddrStr ( peer - > atom ) ) ;
2008-10-03 04:49:06 +00:00
}
2009-11-22 03:57:36 +00:00
else
2008-10-03 04:49:06 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " unhandled error: %s " , tr_strerror ( e - > err ) ) ;
2008-01-18 19:13:32 +00:00
}
2007-09-20 16:32:01 +00:00
break ;
default :
2012-12-05 17:29:46 +00:00
assert ( 0 ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
torrentUnlock ( t ) ;
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
2012-12-05 17:29:46 +00:00
ensureAtomExists ( Torrent * t ,
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
{
2010-04-20 21:54:03 +00:00
struct peer_atom * a ;
2012-12-05 17:29:46 +00:00
assert ( tr_address_is_valid ( addr ) ) ;
assert ( from < TR_PEER_FROM__MAX ) ;
2009-09-10 03:07:54 +00:00
2012-12-05 17:29:46 +00:00
a = getExistingAtom ( t , addr ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
if ( a = = NULL )
2007-10-01 05:32:34 +00:00
{
2012-12-05 17:29:46 +00:00
const int jitter = tr_cryptoWeakRandInt ( 60 * 10 ) ;
a = tr_new0 ( struct peer_atom , 1 ) ;
2007-10-01 05:32:34 +00:00
a - > addr = * addr ;
a - > port = port ;
a - > flags = flags ;
2010-12-23 02:35:21 +00:00
a - > fromFirst = from ;
a - > fromBest = from ;
2012-12-05 17:29:46 +00:00
a - > shelf_date = tr_time ( ) + getDefaultShelfLife ( from ) + jitter ;
2010-06-14 12:01:50 +00:00
a - > blocklisted = - 1 ;
2012-12-05 17:29:46 +00:00
atomSetSeedProbability ( a , seedProbability ) ;
tr_ptrArrayInsertSorted ( & t - > pool , a , compareAtomsByAddress ) ;
2009-11-26 05:13:58 +00:00
2012-12-05 17:29:46 +00:00
tordbg ( t , " got a new atom: %s " , tr_atomAddrStr ( a ) ) ;
2007-10-01 05:32:34 +00:00
}
2010-12-23 02:35:21 +00:00
else
2010-04-20 21:54:03 +00:00
{
2012-12-05 17:29:46 +00:00
if ( from < a - > fromBest )
2010-12-23 02:35:21 +00:00
a - > fromBest = from ;
2011-03-04 23:26:10 +00:00
2012-12-05 17:29:46 +00:00
if ( a - > seedProbability = = - 1 )
atomSetSeedProbability ( a , seedProbability ) ;
2011-01-16 15:51:48 +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
{
2008-01-28 21:05:50 +00:00
return tor - > maxConnectedPeers ;
2008-01-20 03:21:51 +00:00
}
2008-09-05 05:14:49 +00:00
static int
2012-12-05 17:29:46 +00:00
getPeerCount ( const Torrent * t )
2008-09-05 05:14:49 +00:00
{
2012-12-05 17:29:46 +00:00
return tr_ptrArraySize ( & t - > peers ) ; /* + tr_ptrArraySize (&t->outgoingHandshakes); */
2008-09-05 05:14:49 +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
{
2011-03-22 15:19:54 +00:00
bool ok = isConnected ;
bool success = false ;
2008-12-02 03:41:58 +00:00
tr_port port ;
const tr_address * addr ;
tr_peerMgr * manager = vmanager ;
Torrent * t ;
tr_handshake * ours ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
assert ( io ) ;
assert ( tr_isBool ( ok ) ) ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
t = tr_peerIoHasTorrentHash ( io )
? getExistingTorrent ( manager , tr_peerIoGetTorrentHash ( io ) )
2007-10-02 16:12:44 +00:00
: NULL ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
if ( tr_peerIoIsIncoming ( io ) )
ours = tr_ptrArrayRemoveSorted ( & manager - > incomingHandshakes ,
handshake , handshakeCompare ) ;
else if ( t )
ours = tr_ptrArrayRemoveSorted ( & t - > outgoingHandshakes ,
handshake , handshakeCompare ) ;
2007-10-02 16:12:44 +00:00
else
ours = handshake ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
assert ( ours ) ;
assert ( ours = = handshake ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
if ( t )
torrentLock ( t ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
addr = tr_peerIoGetAddress ( io , & port ) ;
2007-10-02 16:12:44 +00:00
2012-12-05 17:29:46 +00:00
if ( ! ok | | ! t | | ! t - > isRunning )
2007-09-20 16:32:01 +00:00
{
2012-12-05 17:29:46 +00:00
if ( t )
2008-09-23 19:11:04 +00:00
{
2012-12-05 17:29:46 +00:00
struct peer_atom * atom = getExistingAtom ( t , addr ) ;
if ( atom )
2010-04-20 21:54:03 +00:00
{
2008-08-08 22:44:32 +00:00
+ + atom - > numFails ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
if ( ! readAnythingFromPeer )
2010-04-20 21:54:03 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " marking peer %s as unreachable... numFails is %d " , tr_atomAddrStr ( atom ) , ( int ) atom - > numFails ) ;
2010-12-14 18:33:48 +00:00
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
}
2007-09-29 06:37:03 +00:00
else /* looking good */
{
2007-10-08 01:31:27 +00:00
struct peer_atom * atom ;
2009-11-26 05:13:58 +00:00
2012-12-05 17:29:46 +00:00
ensureAtomExists ( t , addr , port , 0 , - 1 , TR_PEER_FROM_INCOMING ) ;
atom = getExistingAtom ( t , addr ) ;
atom - > time = tr_time ( ) ;
2008-12-11 07:04:46 +00:00
atom - > piece_data_time = 0 ;
2012-12-05 17:29:46 +00:00
atom - > lastConnectionAt = tr_time ( ) ;
2007-10-11 00:09:58 +00:00
2012-12-05 17:29:46 +00:00
if ( ! tr_peerIoIsIncoming ( io ) )
2010-12-14 18:33:48 +00:00
{
atom - > flags | = ADDED_F_CONNECTABLE ;
atom - > flags2 & = ~ MYFLAG_UNREACHABLE ;
}
2011-02-18 00:24:48 +00:00
/* In principle, this flag specifies whether the peer groks uTP,
not whether it ' s currently connected over uTP . */
2012-12-05 17:29:46 +00:00
if ( io - > utp_socket )
2011-02-18 00:24:48 +00:00
atom - > flags | = ADDED_F_UTP_FLAGS ;
2012-12-05 17:29:46 +00:00
if ( atom - > flags2 & MYFLAG_BANNED )
2007-10-08 01:31:27 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " banned peer %s tried to reconnect " ,
tr_atomAddrStr ( atom ) ) ;
2007-10-08 01:31:27 +00:00
}
2012-12-05 17:29:46 +00:00
else if ( tr_peerIoIsIncoming ( io )
& & ( getPeerCount ( t ) > = getMaxPeerCount ( t - > tor ) ) )
2008-09-05 05:14:49 +00:00
2007-11-09 15:19:12 +00:00
{
}
2007-10-08 01:31:27 +00:00
else
{
2009-11-28 07:15:31 +00:00
tr_peer * peer = atom - > peer ;
2007-10-11 00:09:58 +00:00
2012-12-05 17:29:46 +00:00
if ( peer ) /* we already have this peer */
2007-10-11 00:09:58 +00:00
{
}
else
{
2012-12-05 17:29:46 +00:00
peer = getPeer ( t , atom ) ;
2008-04-29 16:57:16 +00:00
2012-12-05 17:29:46 +00:00
if ( ! peer_id )
2012-12-22 20:35:19 +00:00
peer - > client = TR_KEY_NONE ;
2008-11-25 21:35:17 +00:00
else {
2008-04-29 16:57:16 +00:00
char client [ 128 ] ;
2012-12-05 17:29:46 +00:00
tr_clientForId ( client , sizeof ( client ) , peer_id ) ;
2012-12-22 20:35:19 +00:00
peer - > client = tr_quark_new ( client , - 1 ) ;
2008-04-29 16:57:16 +00:00
}
2008-11-25 21:35:17 +00:00
2012-12-05 17:29:46 +00:00
peer - > io = tr_handshakeStealIO ( handshake ) ; /* this steals its refcount too, which is
balanced by our unref in peerDelete ( ) */
tr_peerIoSetParent ( peer - > io , & t - > tor - > bandwidth ) ;
tr_peerMsgsNew ( t - > tor , peer , peerCallbackFunc , t ) ;
2008-09-19 17:03:25 +00:00
2011-03-22 15:19:54 +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
2012-12-05 17:29:46 +00:00
if ( t )
torrentUnlock ( t ) ;
2008-09-19 17:03:25 +00:00
return success ;
2007-09-20 16:32:01 +00:00
}
void
2012-12-05 17:29:46 +00:00
tr_peerMgrAddIncoming ( tr_peerMgr * manager ,
2008-12-02 03:41:58 +00:00
tr_address * addr ,
tr_port port ,
2011-02-18 00:23:51 +00:00
int socket ,
2012-12-05 17:29:46 +00:00
struct UTPSocket * utp_socket )
2007-09-20 16:32:01 +00:00
{
2009-10-23 03:41:36 +00:00
tr_session * session ;
2012-12-05 17:29:46 +00:00
managerLock ( manager ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
assert ( tr_isSession ( manager - > session ) ) ;
2009-10-23 03:41:36 +00:00
session = manager - > session ;
2012-12-05 17:29:46 +00:00
if ( tr_sessionIsAddressBlocked ( session , addr ) )
2008-03-30 00:57:55 +00:00
{
2012-12-05 17:29:46 +00:00
tr_dbg ( " Banned IP address \" %s \" tried to connect to us " , tr_address_to_string ( addr ) ) ;
if ( socket > = 0 )
tr_netClose ( session , socket ) ;
2011-02-18 00:23:51 +00:00
else
2012-12-05 17:29:46 +00:00
UTP_Close ( utp_socket ) ;
2008-03-30 00:57:55 +00:00
}
2012-12-05 17:29:46 +00:00
else if ( getExistingHandshake ( & manager - > incomingHandshakes , addr ) )
2007-10-25 13:38:34 +00:00
{
2012-12-05 17:29:46 +00:00
if ( socket > = 0 )
tr_netClose ( session , socket ) ;
2011-02-18 00:23:51 +00:00
else
2012-12-05 17:29:46 +00:00
UTP_Close ( utp_socket ) ;
2007-10-25 13:38:34 +00:00
}
2009-11-29 18:35:02 +00:00
else /* we don't have a connection to them yet... */
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
tr_peerIo * io ;
2007-10-15 16:01:42 +00:00
tr_handshake * handshake ;
2007-10-02 16:12:44 +00:00
2012-12-05 17:29:46 +00:00
io = tr_peerIoNewIncoming ( session , & session - > bandwidth , addr , port , socket , utp_socket ) ;
2007-10-15 16:01:42 +00:00
2012-12-05 17:29:46 +00:00
handshake = tr_handshakeNew ( io ,
2009-10-23 03:41:36 +00:00
session - > encryptionMode ,
2007-10-15 16:01:42 +00:00
myHandshakeDoneCB ,
2012-12-05 17:29:46 +00:00
manager ) ;
2007-10-02 16:12:44 +00:00
2012-12-05 17:29:46 +00:00
tr_peerIoUnref ( io ) ; /* balanced by the implicit ref in tr_peerIoNewIncoming () */
2009-01-05 06:45:08 +00:00
2012-12-05 17:29:46 +00:00
tr_ptrArrayInsertSorted ( & manager - > incomingHandshakes , handshake ,
handshakeCompare ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +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
{
2012-12-05 17:29:46 +00:00
if ( tr_isPex ( pex ) ) /* safeguard against corrupt data */
2008-12-17 03:38:02 +00:00
{
2009-01-13 21:00:05 +00:00
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
if ( ! tr_sessionIsAddressBlocked ( t - > manager - > session , & pex - > addr ) )
if ( tr_address_is_valid_for_peers ( & pex - > addr , pex - > port ) )
ensureAtomExists ( t , & pex - > addr , pex - > port , pex - > flags , seedProbability , from ) ;
2008-12-22 00:52:44 +00:00
2012-12-05 17:29:46 +00:00
managerUnlock ( t - > 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
{
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
const int n = tr_ptrArraySize ( & t - > pool ) ;
struct peer_atom * * it = ( struct peer_atom * * ) tr_ptrArrayBase ( & t - > pool ) ;
2010-04-20 21:54:03 +00:00
struct peer_atom * * end = it + n ;
2012-12-05 17:29:46 +00:00
while ( it ! = end )
atomSetSeed ( t , * it + + ) ;
2010-04-20 21:54:03 +00:00
}
2008-04-19 15:07:59 +00:00
tr_pex *
2012-12-05 17:29:46 +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 ,
2012-12-05 17:29:46 +00:00
size_t * pexCount )
2008-09-23 19:11:04 +00:00
{
size_t i ;
size_t n = compactLen / 6 ;
2008-04-19 15:07:59 +00:00
const uint8_t * walk = compact ;
2012-12-05 17:29:46 +00:00
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
2008-08-09 16:17:59 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n ; + + i )
2008-09-23 19:11:04 +00:00
{
2008-12-02 03:41:58 +00:00
pex [ i ] . addr . type = TR_AF_INET ;
2012-12-05 17:29:46 +00:00
memcpy ( & pex [ i ] . addr . addr , walk , 4 ) ; walk + = 4 ;
memcpy ( & pex [ i ] . port , walk , 2 ) ; walk + = 2 ;
if ( added_f & & ( n = = added_f_len ) )
2008-04-19 15:07:59 +00:00
pex [ i ] . flags = added_f [ i ] ;
2007-09-20 16:32:01 +00:00
}
2008-08-10 14:58:11 +00:00
2008-04-19 15:07:59 +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
{
size_t i ;
size_t n = compactLen / 18 ;
const uint8_t * walk = compact ;
2012-12-05 17:29:46 +00:00
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
2009-08-10 20:04:08 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n ; + + i )
2008-12-15 00:17:08 +00:00
{
pex [ i ] . addr . type = TR_AF_INET6 ;
2012-12-05 17:29:46 +00:00
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 ) )
2008-12-15 00:17:08 +00:00
pex [ i ] . flags = added_f [ i ] ;
}
2009-08-10 20:04:08 +00:00
2008-12-15 00:17:08 +00:00
* pexCount = n ;
return pex ;
}
tr_pex *
2012-12-05 17:29:46 +00:00
tr_peerMgrArrayToPex ( const void * array ,
2008-12-15 00:17:08 +00:00
size_t arrayLen ,
2012-12-05 17:29:46 +00:00
size_t * pexCount )
2008-12-15 00:17:08 +00:00
{
size_t i ;
2012-12-05 17:29:46 +00:00
size_t n = arrayLen / ( sizeof ( tr_address ) + 2 ) ;
/*size_t n = arrayLen / sizeof (tr_peerArrayElement);*/
2008-12-15 00:17:08 +00:00
const uint8_t * walk = array ;
2012-12-05 17:29:46 +00:00
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
2009-08-10 20:04:08 +00:00
2012-12-05 17:29:46 +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 ) ;
2008-12-15 00:17:08 +00:00
pex [ i ] . flags = 0x00 ;
2012-12-05 17:29:46 +00:00
walk + = sizeof ( tr_address ) + 2 ;
2008-12-15 00:17:08 +00:00
}
2009-08-10 20:04:08 +00:00
2008-12-15 00:17:08 +00:00
* pexCount = n ;
return pex ;
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2011-03-07 14:33:45 +00:00
static void
2012-12-05 17:29:46 +00:00
tr_peerMgrSetBlame ( tr_torrent * tor ,
2008-08-20 13:45:52 +00:00
tr_piece_index_t pieceIndex ,
2012-12-05 17:29:46 +00:00
int success )
2007-09-20 16:32:01 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! success )
2007-10-08 01:31:27 +00:00
{
2008-09-23 19:11:04 +00:00
int peerCount , i ;
2009-01-13 21:00:05 +00:00
Torrent * t = tor - > torrentPeers ;
2007-10-08 01:31:27 +00:00
tr_peer * * peers ;
2012-12-05 17:29:46 +00:00
assert ( torrentIsLocked ( t ) ) ;
2007-10-08 01:31:27 +00:00
2012-12-05 17:29:46 +00:00
peers = ( tr_peer * * ) tr_ptrArrayPeek ( & t - > peers , & peerCount ) ;
for ( i = 0 ; i < peerCount ; + + i )
2007-10-08 01:31:27 +00:00
{
2007-11-13 05:36:43 +00:00
tr_peer * peer = peers [ i ] ;
2012-12-05 17:29:46 +00:00
if ( tr_bitfieldHas ( & peer - > blame , pieceIndex ) )
2007-11-13 05:36:43 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " peer %s contributed to corrupt piece (%d); now has %d strikes " ,
tr_atomAddrStr ( peer - > atom ) ,
pieceIndex , ( int ) peer - > strikes + 1 ) ;
addStrike ( t , peer ) ;
2007-11-13 05:36:43 +00:00
}
2007-10-08 01:31:27 +00:00
}
}
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
{
2008-08-01 16:43:22 +00:00
const tr_pex * a = va ;
const tr_pex * b = vb ;
2008-12-16 23:31:05 +00:00
int i ;
2012-12-05 17:29:46 +00:00
assert ( tr_isPex ( a ) ) ;
assert ( tr_isPex ( b ) ) ;
2008-12-16 23:31:05 +00:00
2012-12-05 17:29:46 +00:00
if ( ( i = tr_address_compare ( & a - > addr , & b - > addr ) ) )
2008-12-16 23:31:05 +00:00
return i ;
2012-12-05 17:29:46 +00:00
if ( a - > port ! = b - > port )
2008-12-16 23:31:05 +00:00
return a - > port < b - > port ? - 1 : 1 ;
2008-09-23 19:11:04 +00:00
2007-10-02 02:01:57 +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
{
const struct peer_atom * a = * ( const struct peer_atom * * ) va ;
const struct peer_atom * b = * ( const struct peer_atom * * ) vb ;
2012-12-05 17:29:46 +00:00
assert ( tr_isAtom ( a ) ) ;
assert ( tr_isAtom ( b ) ) ;
2009-09-10 02:20:35 +00:00
2012-12-05 17:29:46 +00:00
if ( a - > piece_data_time ! = b - > piece_data_time )
2009-09-10 02:20:35 +00:00
return a - > piece_data_time > b - > piece_data_time ? - 1 : 1 ;
2012-12-05 17:29:46 +00:00
if ( a - > fromBest ! = b - > fromBest )
2010-12-23 02:35:21 +00:00
return a - > fromBest < b - > fromBest ? - 1 : 1 ;
2012-12-05 17:29:46 +00:00
if ( a - > numFails ! = b - > numFails )
2009-09-10 02:20:35 +00:00
return a - > numFails < b - > numFails ? - 1 : 1 ;
return 0 ;
}
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
{
2012-12-05 17:29:46 +00:00
if ( tr_torrentIsSeed ( tor ) & & atomIsSeed ( atom ) )
2011-03-29 15:23:54 +00:00
return false ;
2012-12-05 17:29:46 +00:00
if ( peerIsInUse ( tor - > torrentPeers , atom ) )
2011-03-29 15:23:54 +00:00
return true ;
2012-12-05 17:29:46 +00:00
if ( isAtomBlocklisted ( tor - > session , atom ) )
2011-03-29 15:23:54 +00:00
return false ;
2012-12-05 17:29:46 +00:00
if ( atom - > flags2 & MYFLAG_BANNED )
2011-03-29 15:23:54 +00:00
return false ;
return true ;
}
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
{
2009-11-20 07:47:31 +00:00
int i ;
int n ;
2009-08-07 05:41:33 +00:00
int count = 0 ;
2009-11-20 07:47:31 +00:00
int atomCount = 0 ;
2009-01-13 21:00:05 +00:00
const Torrent * t = tor - > torrentPeers ;
2009-11-20 07:47:31 +00:00
struct peer_atom * * atoms = NULL ;
tr_pex * pex ;
tr_pex * walk ;
2012-12-05 17:29:46 +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
2012-12-05 17:29:46 +00:00
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2009-11-20 07:47:31 +00:00
/**
* * * build a list of atoms
* */
2012-12-05 17:29:46 +00:00
if ( list_mode = = TR_PEERS_CONNECTED ) /* connected peers only */
2008-10-05 22:51:18 +00:00
{
int i ;
2012-12-05 17:29:46 +00:00
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
atomCount = tr_ptrArraySize ( & t - > peers ) ;
atoms = tr_new ( struct peer_atom * , atomCount ) ;
for ( i = 0 ; i < atomCount ; + + i )
2009-11-20 07:47:31 +00:00
atoms [ i ] = peers [ i ] - > atom ;
}
2011-03-29 15:23:54 +00:00
else /* TR_PEERS_INTERESTING */
2009-11-20 07:47:31 +00:00
{
2011-03-29 15:23:54 +00:00
int i ;
2012-12-05 17:29:46 +00:00
struct peer_atom * * atomBase = ( struct peer_atom * * ) tr_ptrArrayBase ( & t - > pool ) ;
n = tr_ptrArraySize ( & t - > pool ) ;
atoms = tr_new ( struct peer_atom * , n ) ;
for ( i = 0 ; i < n ; + + i )
if ( isAtomInteresting ( tor , atomBase [ i ] ) )
2011-03-29 15:23:54 +00:00
atoms [ atomCount + + ] = atomBase [ i ] ;
2009-11-20 07:47:31 +00:00
}
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
qsort ( atoms , atomCount , sizeof ( struct peer_atom * ) , compareAtomsByUsefulness ) ;
2009-09-10 02:20:35 +00:00
2009-11-20 07:47:31 +00:00
/**
* * * add the first N of them into our return list
* */
2012-12-05 17:29:46 +00:00
n = MIN ( atomCount , maxCount ) ;
pex = walk = tr_new0 ( tr_pex , n ) ;
2009-11-20 07:47:31 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < atomCount & & count < n ; + + i )
2009-11-20 07:47:31 +00:00
{
const struct peer_atom * atom = atoms [ i ] ;
2012-12-05 17:29:46 +00:00
if ( atom - > addr . type = = af )
2008-10-05 22:51:18 +00:00
{
2012-12-05 17:29:46 +00:00
assert ( tr_address_is_valid ( & atom - > addr ) ) ;
2009-11-20 07:47:31 +00:00
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
2012-12-05 17:29:46 +00:00
qsort ( pex , count , sizeof ( tr_pex ) , tr_pexCompare ) ;
2009-09-10 02:20:35 +00:00
2012-12-05 17:29:46 +00:00
assert ( ( walk - pex ) = = count ) ;
2009-11-20 07:47:31 +00:00
* setme_pex = pex ;
2007-09-20 16:32:01 +00:00
2009-11-20 07:47:31 +00:00
/* cleanup */
2012-12-05 17:29:46 +00:00
tr_free ( atoms ) ;
managerUnlock ( t - > manager ) ;
2009-08-07 05:41:33 +00:00
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
{
2012-12-05 17:29:46 +00:00
struct event * timer = evtimer_new ( session - > event_base , callback , cbdata ) ;
tr_timerAddMsec ( timer , msec ) ;
2009-12-10 05:52:46 +00:00
return timer ;
}
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
{
2012-12-05 17:29:46 +00:00
if ( m - > atomTimer = = NULL )
m - > atomTimer = createTimer ( m - > session , ATOM_PERIOD_MSEC , atomPulse , m ) ;
2009-11-26 05:13:58 +00:00
2012-12-05 17:29:46 +00:00
if ( m - > bandwidthTimer = = NULL )
m - > bandwidthTimer = createTimer ( m - > session , BANDWIDTH_PERIOD_MSEC , bandwidthPulse , m ) ;
2009-05-13 20:54:35 +00:00
2012-12-05 17:29:46 +00:00
if ( m - > rechokeTimer = = NULL )
m - > rechokeTimer = createTimer ( m - > session , RECHOKE_PERIOD_MSEC , rechokePulse , m ) ;
2009-05-13 20:54:35 +00:00
2012-12-05 17:29:46 +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
{
2009-02-11 16:34:35 +00:00
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2011-01-18 23:44:36 +00:00
2012-12-05 17:29:46 +00:00
ensureMgrTimersExist ( t - > manager ) ;
2009-02-11 16:34:35 +00:00
2011-03-22 15:19:54 +00:00
t - > isRunning = true ;
2010-12-04 17:17:44 +00:00
t - > maxPeers = t - > tor - > maxConnectedPeers ;
2011-02-17 05:14:53 +00:00
t - > pieceSortState = PIECES_UNSORTED ;
2009-02-11 16:34:35 +00:00
2012-12-05 17:29:46 +00:00
rechokePulse ( 0 , 0 , t - > manager ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
static void
2012-12-05 17:29:46 +00:00
stopTorrent ( Torrent * t )
2007-09-20 16:32:01 +00:00
{
2011-03-28 16:31:05 +00:00
tr_peer * peer ;
2009-11-08 23:20:00 +00:00
2011-03-22 15:19:54 +00:00
t - > isRunning = false ;
2007-10-02 02:01:57 +00:00
2012-12-05 17:29:46 +00:00
replicationFree ( t ) ;
invalidatePieceSorting ( t ) ;
2011-02-17 05:14:53 +00:00
2007-10-02 16:12:44 +00:00
/* disconnect the peers. */
2012-12-05 17:29:46 +00:00
while ( ( peer = tr_ptrArrayPop ( & t - > peers ) ) )
peerDelete ( t , peer ) ;
2007-10-02 02:01:57 +00:00
2012-12-05 17:29:46 +00:00
/* disconnect the handshakes. handshakeAbort calls handshakeDoneCB (),
2007-10-02 16:12:44 +00:00
* which removes the handshake from t - > outgoingHandshakes . . . */
2012-12-05 17:29:46 +00:00
while ( ! tr_ptrArrayEmpty ( & t - > outgoingHandshakes ) )
tr_handshakeAbort ( tr_ptrArrayNth ( & t - > 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
{
2012-12-05 17:29:46 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2009-01-13 21:00:05 +00:00
2012-12-05 17:29:46 +00:00
stopTorrent ( tor - > torrentPeers ) ;
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
{
2012-12-05 17:29:46 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
assert ( tor - > torrentPeers = = NULL ) ;
2007-09-20 16:32:01 +00:00
2012-12-05 17:29:46 +00:00
tor - > torrentPeers = torrentNew ( 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
{
2012-12-05 17:29:46 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
stopTorrent ( tor - > torrentPeers ) ;
torrentFree ( tor - > torrentPeers ) ;
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
{
2011-03-28 16:31:05 +00:00
const tr_bitfield * have = & peer - > have ;
2011-02-24 14:35:45 +00:00
2012-12-05 17:29:46 +00:00
if ( tr_bitfieldHasAll ( have ) )
2011-02-24 14:35:45 +00:00
{
peer - > progress = 1.0 ;
}
2012-12-05 17:29:46 +00:00
else if ( tr_bitfieldHasNone ( have ) )
2011-02-24 14:35:45 +00:00
{
peer - > progress = 0.0 ;
}
else
{
2012-12-05 17:29:46 +00:00
const float true_count = tr_bitfieldCountTrueBits ( have ) ;
2011-02-24 14:35:45 +00:00
2012-12-05 17:29:46 +00:00
if ( tr_torrentHasMetadata ( tor ) )
2012-07-01 02:00:02 +00:00
{
2011-03-28 16:31:05 +00:00
peer - > progress = true_count / tor - > info . pieceCount ;
2012-07-01 02:00:02 +00:00
}
2011-02-24 14:35:45 +00:00
else /* without pieceCount, this result is only a best guess... */
2012-07-01 02:00:02 +00:00
{
2012-12-05 17:29:46 +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
}
2012-07-01 02:00:02 +00:00
/* clamp the progress range */
2012-12-05 17:29:46 +00:00
if ( peer - > progress < 0.0 )
2012-07-01 02:00:02 +00:00
peer - > progress = 0.0 ;
2012-12-05 17:29:46 +00:00
if ( peer - > progress > 1.0 )
2012-07-01 02:00:02 +00:00
peer - > progress = 1.0 ;
2012-12-05 17:29:46 +00:00
if ( peer - > atom & & ( peer - > progress > = 1.0 ) )
atomSetSeed ( tor - > torrentPeers , 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
{
2011-03-04 23:26:10 +00:00
int i ;
2012-10-05 22:04:08 +00:00
int peerCount ;
tr_peer * * peers ;
/* the webseed list may have changed... */
2012-12-05 17:29:46 +00:00
rebuildWebseedArray ( tor - > torrentPeers , tor ) ;
2011-03-04 23:26:10 +00:00
/* some peer_msgs' progress fields may not be accurate if we
2011-02-24 14:35:45 +00:00
didn ' t have the metadata before now . . . so refresh them all . . . */
2012-12-05 17:29:46 +00:00
peerCount = tr_ptrArraySize ( & tor - > torrentPeers - > peers ) ;
peers = ( tr_peer * * ) tr_ptrArrayBase ( & tor - > torrentPeers - > peers ) ;
for ( i = 0 ; i < peerCount ; + + i )
tr_peerUpdateProgress ( tor , peers [ i ] ) ;
2012-10-05 22:04:08 +00:00
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 ;
const int peerCount = tr_ptrArraySize ( & tor - > torrentPeers - > peers ) ;
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & tor - > torrentPeers - > peers ) ;
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
{
2012-12-05 17:29:46 +00:00
if ( peer - > progress > = 1.0 )
2011-03-28 16:31:05 +00:00
return true ;
2011-01-18 23:44:36 +00:00
2012-12-05 17:29:46 +00:00
if ( peer - > atom & & atomIsSeed ( peer - > atom ) )
2011-03-28 16:31:05 +00:00
return true ;
2007-09-29 06:37:03 +00:00
2011-03-28 16:31:05 +00:00
return false ;
}
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
{
size_t i ;
size_t n ;
uint64_t desiredAvailable ;
const Torrent * t = tor - > torrentPeers ;
/* common shortcuts... */
2012-12-05 17:29:46 +00:00
if ( tr_torrentIsSeed ( t - > tor ) )
2011-03-28 16:31:05 +00:00
return 0 ;
2007-09-27 03:03:38 +00:00
2012-12-05 17:29:46 +00:00
if ( ! tr_torrentHasMetadata ( tor ) )
2011-03-28 16:31:05 +00:00
return 0 ;
2012-12-05 17:29:46 +00:00
n = tr_ptrArraySize ( & t - > peers ) ;
if ( n = = 0 )
2011-03-28 16:31:05 +00:00
return 0 ;
else {
2012-12-05 17:29:46 +00:00
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > 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
}
2012-12-05 17:29:46 +00:00
if ( ! t - > pieceReplication | | ! t - > pieceReplicationSize )
2011-03-28 16:31:05 +00:00
return 0 ;
/* do it the hard way */
desiredAvailable = 0 ;
2012-12-05 17:29:46 +00:00
for ( i = 0 , n = MIN ( tor - > info . pieceCount , t - > pieceReplicationSize ) ; i < n ; + + i )
if ( ! tor - > info . pieces [ i ] . dnd & & ( t - > pieceReplication [ i ] > 0 ) )
desiredAvailable + = tr_cpMissingBytesInPiece ( & t - > tor - > completion , i ) ;
2011-03-28 16:31:05 +00:00
2012-12-05 17:29:46 +00:00
assert ( desiredAvailable < = tor - > info . totalSize ) ;
2011-03-28 16:31:05 +00:00
return desiredAvailable ;
2007-09-27 03:03:38 +00:00
}
2007-09-20 16:32:01 +00:00
void
2012-12-05 17:29:46 +00:00
tr_peerMgrTorrentStats ( tr_torrent * tor ,
2011-01-18 23:44:36 +00:00
int * setmePeersConnected ,
int * setmeWebseedsSendingToUs ,
int * setmePeersSendingToUs ,
int * setmePeersGettingFromUs ,
2012-12-05 17:29:46 +00:00
int * setmePeersFrom )
2008-12-05 22:56:19 +00:00
{
2012-12-14 20:04:37 +00:00
int i ;
int size ;
Torrent * t ;
const tr_peer * * peers ;
assert ( tr_isTorrent ( tor ) ) ;
2012-12-12 20:22:57 +00:00
* setmePeersConnected = 0 ;
* setmePeersGettingFromUs = 0 ;
* setmePeersSendingToUs = 0 ;
* setmeWebseedsSendingToUs = 0 ;
2007-09-20 16:32:01 +00:00
2012-12-14 20:04:37 +00:00
t = tor - > torrentPeers ;
size = tr_ptrArraySize ( & t - > peers ) ;
peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
2007-09-21 15:13:23 +00:00
2012-12-14 20:04:37 +00:00
for ( i = 0 ; i < TR_PEER_FROM__MAX ; + + i )
setmePeersFrom [ i ] = 0 ;
2007-09-20 16:32:01 +00:00
2012-12-14 20:04:37 +00:00
for ( i = 0 ; i < size ; + + i )
{
const tr_peer * peer = peers [ i ] ;
const struct peer_atom * atom = peer - > atom ;
2007-09-20 16:32:01 +00:00
2012-12-14 20:04:37 +00:00
if ( peer - > io = = NULL ) /* not connected */
continue ;
2007-09-20 16:32:01 +00:00
2012-12-14 20:04:37 +00:00
+ + * setmePeersConnected ;
2007-09-20 16:32:01 +00:00
2012-12-14 20:04:37 +00:00
+ + setmePeersFrom [ atom - > fromFirst ] ;
2008-01-16 17:52:47 +00:00
2012-12-14 20:04:37 +00:00
if ( clientIsDownloadingFrom ( tor , peer ) )
+ + * setmePeersSendingToUs ;
2007-09-29 06:37:03 +00:00
2012-12-14 20:04:37 +00:00
if ( clientIsUploadingTo ( peer ) )
+ + * setmePeersGettingFromUs ;
2012-12-12 20:22:57 +00:00
}
2012-12-14 20:04:37 +00:00
* setmeWebseedsSendingToUs = countActiveWebseeds ( t ) ;
2008-06-10 01:38:12 +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-14 20:04:37 +00:00
int i ;
int webseedCount ;
const Torrent * t ;
const tr_webseed * * webseeds ;
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
2012-12-14 20:04:37 +00:00
t = tor - > torrentPeers ;
webseedCount = tr_ptrArraySize ( & t - > webseeds ) ;
webseeds = ( const tr_webseed * * ) tr_ptrArrayBase ( & t - > webseeds ) ;
ret = tr_new0 ( double , webseedCount ) ;
2012-12-12 20:22:57 +00:00
2012-12-14 20:04:37 +00:00
assert ( t - > manager ! = NULL ) ;
assert ( webseedCount = = tor - > info . webseedCount ) ;
2012-12-12 20:22:57 +00:00
2012-12-14 20:04:37 +00:00
for ( i = 0 ; i < webseedCount ; + + i )
{
unsigned int Bps ;
if ( tr_webseedGetSpeed_Bps ( webseeds [ i ] , now , & Bps ) )
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
}
2012-07-01 02:17:35 +00:00
unsigned int
2012-12-05 17:29:46 +00:00
tr_peerGetPieceSpeed_Bps ( const tr_peer * peer , uint64_t now , tr_direction direction )
2008-11-06 02:56:51 +00:00
{
2012-12-14 20:04:37 +00:00
return peer - > io ? tr_peerIoGetPieceSpeed_Bps ( peer - > io , now , direction ) : 0.0 ;
2008-11-06 02:56:51 +00:00
}
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 ;
const Torrent * t ;
const tr_peer * * peers ;
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 ) ) ;
assert ( tor - > torrentPeers - > manager ! = NULL ) ;
2012-12-12 20:22:57 +00:00
2012-12-14 20:04:37 +00:00
t = tor - > torrentPeers ;
peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
size = tr_ptrArraySize ( & t - > peers ) ;
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 ;
const tr_peer * peer = peers [ i ] ;
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 ;
stat - > isUTP = peer - > io - > utp_socket ! = NULL ;
stat - > isEncrypted = tr_peerIoIsEncrypted ( peer - > io ) ? 1 : 0 ;
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 ) ) ;
stat - > peerIsChoked = peer - > peerIsChoked ;
stat - > peerIsInterested = peer - > peerIsInterested ;
stat - > clientIsChoked = peer - > clientIsChoked ;
stat - > clientIsInterested = peer - > clientIsInterested ;
stat - > isIncoming = tr_peerIoIsIncoming ( peer - > io ) ;
stat - > isDownloadingFrom = clientIsDownloadingFrom ( tor , peer ) ;
stat - > isUploadingTo = clientIsUploadingTo ( peer ) ;
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 ' ;
if ( t - > optimistic = = peer ) * pch + + = ' O ' ;
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
{
int i ;
2011-01-18 23:44:36 +00:00
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
const int peerCount = tr_ptrArraySize ( & t - > peers ) ;
2010-09-25 00:34:15 +00:00
2012-12-05 17:29:46 +00:00
assert ( tr_isTorrent ( tor ) ) ;
assert ( tr_torrentIsLocked ( tor ) ) ;
2010-09-25 00:34:15 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < peerCount ; + + i )
2010-09-25 00:34:15 +00:00
{
2012-12-05 17:29:46 +00:00
const tr_peer * peer = tr_ptrArrayNth ( & t - > peers , i ) ;
tr_peerMsgsSetInterested ( peer - > msgs , 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
{
RECHOKE_STATE_GOOD ,
RECHOKE_STATE_UNTESTED ,
RECHOKE_STATE_BAD
}
tr_rechoke_state ;
struct tr_rechoke_info
{
tr_peer * peer ;
int salt ;
int rechoke_state ;
} ;
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
{
const struct tr_rechoke_info * a = va ;
const struct tr_rechoke_info * b = vb ;
2012-12-05 17:29:46 +00:00
if ( a - > rechoke_state ! = b - > rechoke_state )
2011-04-29 23:25:12 +00:00
return a - > rechoke_state - b - > rechoke_state ;
return a - > salt - b - > salt ;
}
2010-03-08 04:29:58 +00:00
/* determines who we send "interested" messages to */
static void
2012-12-05 17:29:46 +00:00
rechokeDownloads ( Torrent * t )
2010-03-08 04:29:58 +00:00
{
int i ;
2011-04-29 23:25:12 +00:00
int maxPeers = 0 ;
int rechoke_count = 0 ;
struct tr_rechoke_info * rechoke = NULL ;
2010-03-08 04:29:58 +00:00
const int MIN_INTERESTING_PEERS = 5 ;
2012-12-05 17:29:46 +00:00
const int peerCount = tr_ptrArraySize ( & t - > peers ) ;
const time_t now = tr_time ( ) ;
2010-03-08 04:29:58 +00:00
2011-05-10 04:46:44 +00:00
/* some cases where this function isn't necessary */
2012-12-05 17:29:46 +00:00
if ( tr_torrentIsSeed ( t - > tor ) )
2011-05-10 04:46:44 +00:00
return ;
2012-12-05 17:29:46 +00:00
if ( ! tr_torrentIsPieceTransferAllowed ( t - > tor , TR_PEER_TO_CLIENT ) )
2011-05-10 04:46:44 +00:00
return ;
2011-04-29 23:25:12 +00:00
/* decide HOW MANY peers to be interested in */
2010-03-08 04:29:58 +00:00
{
2010-03-10 15:34:27 +00:00
int blocks = 0 ;
int cancels = 0 ;
2010-12-04 17:17:44 +00:00
time_t timeSinceCancel ;
2010-03-10 15:34:27 +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
2010-04-22 03:12:31 +00:00
* thinking it ' s hit its bandwidth cap .
2010-03-10 15:34:27 +00:00
*/
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < peerCount ; + + i )
2010-03-10 15:34:27 +00:00
{
2012-12-05 17:29:46 +00:00
const tr_peer * peer = tr_ptrArrayNth ( & t - > peers , i ) ;
const int b = tr_historyGet ( & peer - > blocksSentToClient , now , CANCEL_HISTORY_SEC ) ;
const int c = tr_historyGet ( & peer - > cancelsSentToPeer , now , CANCEL_HISTORY_SEC ) ;
2010-03-10 15:34:27 +00:00
2012-12-05 17:29:46 +00:00
if ( b = = 0 ) /* ignore unresponsive peers, as described above */
2010-03-10 15:34:27 +00:00
continue ;
blocks + = b ;
cancels + = c ;
}
2010-03-08 04:29:58 +00:00
2012-12-05 17:29:46 +00:00
if ( cancels > 0 )
2010-03-08 04:29:58 +00:00
{
2010-12-04 17:17:44 +00:00
/* 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 ) ;
2012-12-05 17:29:46 +00:00
const double mult = 1 - MIN ( cancelRate , 0.5 ) ;
2010-12-04 17:17:44 +00:00
maxPeers = t - > interestedCount * mult ;
2012-12-05 17:29:46 +00:00
tordbg ( t , " cancel rate is %.3f -- reducing the "
2010-12-04 17:17:44 +00:00
" number of peers we're interested in by %.0f percent " ,
2012-12-05 17:29:46 +00:00
cancelRate , mult * 100 ) ;
2010-12-04 17:17:44 +00:00
t - > lastCancel = now ;
2010-03-08 04:29:58 +00:00
}
2010-04-22 03:12:31 +00:00
2010-12-04 17:17:44 +00:00
timeSinceCancel = now - t - > lastCancel ;
2012-12-05 17:29:46 +00:00
if ( timeSinceCancel )
2010-10-01 18:16:01 +00:00
{
2010-12-04 17:17:44 +00:00
const int maxIncrease = 15 ;
const time_t maxHistory = 2 * CANCEL_HISTORY_SEC ;
2012-12-05 17:29:46 +00:00
const double mult = MIN ( timeSinceCancel , maxHistory ) / ( double ) maxHistory ;
2010-12-04 17:17:44 +00:00
const int inc = maxIncrease * mult ;
maxPeers = t - > maxPeers + inc ;
2012-12-05 17:29:46 +00:00
tordbg ( t , " time since last cancel is %li -- increasing the "
2010-12-04 17:17:44 +00:00
" number of peers we're interested in by %d " ,
2012-12-05 17:29:46 +00:00
timeSinceCancel , inc ) ;
2010-03-08 04:29:58 +00:00
}
}
2010-12-04 17:17:44 +00:00
/* don't let the previous section's number tweaking go too far... */
2012-12-05 17:29:46 +00:00
if ( maxPeers < MIN_INTERESTING_PEERS )
2010-04-22 03:12:31 +00:00
maxPeers = MIN_INTERESTING_PEERS ;
2012-12-05 17:29:46 +00:00
if ( maxPeers > t - > tor - > maxConnectedPeers )
2010-04-22 03:12:31 +00:00
maxPeers = t - > tor - > maxConnectedPeers ;
2010-03-08 04:29:58 +00:00
2010-10-01 18:16:01 +00:00
t - > maxPeers = maxPeers ;
2012-12-05 17:29:46 +00:00
if ( peerCount > 0 )
2010-03-08 04:29:58 +00:00
{
2011-09-21 23:04:39 +00:00
bool * piece_is_interesting ;
2011-05-10 03:50:54 +00:00
const tr_torrent * const tor = t - > tor ;
const int n = tor - > info . pieceCount ;
2010-03-08 04:29:58 +00:00
2011-05-10 03:50:54 +00:00
/* build a bitfield of interesting pieces... */
2012-12-05 17:29:46 +00:00
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 ) ;
2011-05-10 03:50:54 +00:00
/* decide WHICH peers to be interested in (based on their cancel-to-block ratio) */
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < peerCount ; + + i )
2011-04-29 23:25:12 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peer * peer = tr_ptrArrayNth ( & t - > peers , i ) ;
2011-05-10 03:50:54 +00:00
2012-12-05 17:29:46 +00:00
if ( ! isPeerInteresting ( t - > tor , piece_is_interesting , peer ) )
2011-05-10 03:50:54 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peerMsgsSetInterested ( peer - > msgs , false ) ;
2011-05-10 03:50:54 +00:00
}
2011-04-29 23:25:12 +00:00
else
2011-05-10 03:50:54 +00:00
{
tr_rechoke_state rechoke_state ;
2012-12-05 17:29:46 +00:00
const int blocks = tr_historyGet ( & peer - > blocksSentToClient , now , CANCEL_HISTORY_SEC ) ;
const int cancels = tr_historyGet ( & peer - > cancelsSentToPeer , now , CANCEL_HISTORY_SEC ) ;
2011-05-10 03:50:54 +00:00
2012-12-05 17:29:46 +00:00
if ( ! blocks & & ! cancels )
2011-05-10 03:50:54 +00:00
rechoke_state = RECHOKE_STATE_UNTESTED ;
2012-12-05 17:29:46 +00:00
else if ( ! cancels )
2011-05-10 03:50:54 +00:00
rechoke_state = RECHOKE_STATE_GOOD ;
2012-12-05 17:29:46 +00:00
else if ( ! blocks )
2011-05-10 03:50:54 +00:00
rechoke_state = RECHOKE_STATE_BAD ;
2012-12-05 17:29:46 +00:00
else if ( ( cancels * 10 ) < blocks )
2011-05-10 03:50:54 +00:00
rechoke_state = RECHOKE_STATE_GOOD ;
else
rechoke_state = RECHOKE_STATE_BAD ;
2010-06-22 16:31:38 +00:00
2012-12-05 17:29:46 +00:00
if ( rechoke = = NULL )
rechoke = tr_new ( struct tr_rechoke_info , peerCount ) ;
2011-05-10 03:50:54 +00:00
rechoke [ rechoke_count ] . peer = peer ;
rechoke [ rechoke_count ] . rechoke_state = rechoke_state ;
2012-12-05 17:29:46 +00:00
rechoke [ rechoke_count ] . salt = tr_cryptoWeakRandInt ( INT_MAX ) ;
2011-05-10 03:50:54 +00:00
rechoke_count + + ;
}
2010-03-17 17:07:40 +00:00
2011-04-29 23:25:12 +00:00
}
2010-03-08 04:29:58 +00:00
2012-12-05 17:29:46 +00:00
tr_free ( piece_is_interesting ) ;
2010-03-08 04:29:58 +00:00
}
2011-04-29 23:25:12 +00:00
/* now that we know which & how many peers to be interested in... update the peer interest */
2012-12-05 17:29:46 +00:00
qsort ( rechoke , rechoke_count , sizeof ( struct tr_rechoke_info ) , compare_rechoke_info ) ;
t - > interestedCount = MIN ( maxPeers , rechoke_count ) ;
for ( i = 0 ; i < rechoke_count ; + + i )
tr_peerMsgsSetInterested ( rechoke [ i ] . peer - > msgs , i < t - > interestedCount ) ;
2010-03-17 17:07:40 +00:00
2010-03-08 04:29:58 +00:00
/* cleanup */
2012-12-05 17:29:46 +00:00
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
{
2011-03-22 15:19:54 +00:00
bool isInterested ;
bool wasChoked ;
bool isChoked ;
2008-11-15 01:07:08 +00:00
int rate ;
2010-06-27 01:24:48 +00:00
int salt ;
2008-09-23 19:11:04 +00:00
tr_peer * peer ;
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
{
2007-10-03 16:42:43 +00:00
const struct ChokeData * a = va ;
const struct ChokeData * b = vb ;
2008-06-27 02:42:44 +00:00
2012-12-05 17:29:46 +00:00
if ( a - > rate ! = b - > rate ) /* prefer higher overall speeds */
2008-11-15 01:07:08 +00:00
return a - > rate > b - > rate ? - 1 : 1 ;
2008-11-15 00:46:51 +00:00
2012-12-05 17:29:46 +00:00
if ( a - > wasChoked ! = b - > wasChoked ) /* prefer unchoked */
2010-09-19 01:04:49 +00:00
return a - > wasChoked ? 1 : - 1 ;
2008-06-27 02:42:44 +00:00
2012-12-05 17:29:46 +00:00
if ( a - > salt ! = b - > salt ) /* random order */
2010-06-27 01:24:48 +00:00
return a - > salt - b - > salt ;
2008-11-15 01:07:08 +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? */
2008-01-11 02:09:20 +00:00
static int
2012-12-05 17:29:46 +00:00
isNew ( const tr_peer * peer )
2008-01-11 02:09:20 +00:00
{
2012-12-05 17:29:46 +00:00
return peer & & peer - > io & & tr_peerIoGetAge ( peer - > io ) < 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
{
2012-07-01 02:17:35 +00:00
unsigned int Bps ;
2010-06-23 04:36:16 +00:00
2012-12-05 17:29:46 +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
/* downloading a private torrent... take upload speed into account
* because there may only be a small window of opportunity to share */
2012-12-05 17:29:46 +00:00
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
/* downloading a public torrent */
else
2012-12-05 17:29:46 +00:00
Bps = tr_peerGetPieceSpeed_Bps ( atom - > peer , now , TR_PEER_TO_CLIENT ) ;
2010-06-23 04:36:16 +00:00
/* convert it to bytes per second */
2010-07-03 00:25:22 +00:00
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
{
2012-12-05 17:29:46 +00:00
if ( ! tr_bandwidthIsLimited ( b , dir ) )
2011-03-22 15:19:54 +00:00
return false ;
2010-09-19 01:04:49 +00:00
else {
2012-12-05 17:29:46 +00:00
const unsigned int got = tr_bandwidthGetPieceSpeed_Bps ( b , now_msec , dir ) ;
const unsigned int want = tr_bandwidthGetDesiredSpeed_Bps ( b , dir ) ;
2010-09-19 01:04:49 +00:00
return got > = want ;
}
}
2007-09-20 16:32:01 +00:00
static void
2012-12-05 17:29:46 +00:00
rechokeUploads ( Torrent * t , const uint64_t now )
2007-09-20 16:32:01 +00:00
{
2008-12-30 08:20:16 +00:00
int i , size , unchokedInterested ;
2012-12-05 17:29:46 +00:00
const int peerCount = tr_ptrArraySize ( & t - > peers ) ;
tr_peer * * peers = ( tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
struct ChokeData * choke = tr_new0 ( struct ChokeData , peerCount ) ;
2009-01-09 15:45:44 +00:00
const tr_session * session = t - > manager - > session ;
2012-12-05 17:29:46 +00:00
const int chokeAll = ! tr_torrentIsPieceTransferAllowed ( t - > tor , TR_CLIENT_TO_PEER ) ;
const bool isMaxedOut = isBandwidthMaxedOut ( & t - > tor - > bandwidth , now , TR_UP ) ;
2007-09-29 06:37:03 +00:00
2012-12-05 17:29:46 +00:00
assert ( torrentIsLocked ( t ) ) ;
2008-09-23 19:11:04 +00:00
2010-10-13 03:56:25 +00:00
/* an optimistic unchoke peer's "optimistic"
2012-12-05 17:29:46 +00:00
* state lasts for N calls to rechokeUploads ( ) . */
if ( t - > optimisticUnchokeTimeScaler > 0 )
2010-10-13 03:56:25 +00:00
t - > optimisticUnchokeTimeScaler - - ;
else
t - > optimistic = NULL ;
2007-09-20 16:32:01 +00:00
/* sort the peers by preference and rate */
2012-12-05 17:29:46 +00:00
for ( i = 0 , size = 0 ; i < peerCount ; + + i )
2007-09-22 00:22:10 +00:00
{
2007-09-20 16:32:01 +00:00
tr_peer * peer = peers [ i ] ;
2009-05-09 06:08:21 +00:00
struct peer_atom * atom = peer - > atom ;
2008-12-02 19:46:51 +00:00
2012-12-05 17:29:46 +00:00
if ( peerIsSeed ( peer ) ) /* choke seeds and partial seeds */
2008-12-02 19:46:51 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peerMsgsSetChoke ( peer - > msgs , true ) ;
2008-12-02 19:46:51 +00:00
}
2012-12-05 17:29:46 +00:00
else if ( chokeAll ) /* choke everyone if we're not uploading */
2008-12-02 19:46:51 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peerMsgsSetChoke ( peer - > msgs , true ) ;
2008-12-02 19:46:51 +00:00
}
2012-12-05 17:29:46 +00:00
else if ( peer ! = t - > optimistic )
2008-12-02 19:46:51 +00:00
{
2008-11-06 02:56:51 +00:00
struct ChokeData * n = & choke [ size + + ] ;
n - > peer = peer ;
n - > isInterested = peer - > peerIsInterested ;
2010-09-19 01:04:49 +00:00
n - > wasChoked = peer - > peerIsChoked ;
2012-12-05 17:29:46 +00:00
n - > rate = getRate ( t - > tor , atom , now ) ;
n - > salt = tr_cryptoWeakRandInt ( INT_MAX ) ;
2011-03-22 15:19:54 +00:00
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
2012-12-05 17:29:46 +00:00
qsort ( choke , size , sizeof ( struct ChokeData ) , compareChoke ) ;
2007-09-20 16:32:01 +00:00
2008-01-09 17:33:43 +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
2008-09-23 19:11:04 +00:00
* rate to decide which peers to unchoke .
2010-09-19 01:04:49 +00:00
*
* If our bandwidth is maxed out , don ' t unchoke any more peers .
2008-01-09 17:33:43 +00:00
*/
unchokedInterested = 0 ;
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < size & & unchokedInterested < session - > uploadSlotsPerTorrent ; + + i ) {
2011-03-22 15:19:54 +00:00
choke [ i ] . isChoked = isMaxedOut ? choke [ i ] . wasChoked : false ;
2012-12-05 17:29:46 +00:00
if ( choke [ i ] . isInterested )
2008-01-09 17:33:43 +00:00
+ + unchokedInterested ;
2007-11-18 06:15:13 +00:00
}
2007-09-20 16:32:01 +00:00
2008-01-09 17:33:43 +00:00
/* optimistic unchoke */
2012-12-05 17:29:46 +00:00
if ( ! t - > optimistic & & ! isMaxedOut & & ( i < size ) )
2008-01-11 02:09:20 +00:00
{
2008-12-05 22:56:19 +00:00
int n ;
2008-01-11 02:09:20 +00:00
struct ChokeData * c ;
2008-12-29 08:54:36 +00:00
tr_ptrArray randPool = TR_PTR_ARRAY_INIT ;
2008-06-03 04:29:56 +00:00
2012-12-05 17:29:46 +00:00
for ( ; i < size ; + + i )
2008-01-11 02:09:20 +00:00
{
2012-12-05 17:29:46 +00:00
if ( choke [ i ] . isInterested )
2008-06-03 04:29:56 +00:00
{
const tr_peer * peer = choke [ i ] . peer ;
2008-12-05 22:56:19 +00:00
int x = 1 , y ;
2012-12-05 17:29:46 +00:00
if ( isNew ( peer ) ) x * = 3 ;
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
2012-12-05 17:29:46 +00:00
if ( ( n = tr_ptrArraySize ( & randPool ) ) )
2008-06-03 04:29:56 +00:00
{
2012-12-05 17:29:46 +00:00
c = tr_ptrArrayNth ( & randPool , tr_cryptoWeakRandInt ( n ) ) ;
2011-03-22 15:19:54 +00:00
c - > isChoked = false ;
2008-06-03 04:29:56 +00:00
t - > optimistic = c - > peer ;
2010-10-13 03:56:25 +00:00
t - > optimisticUnchokeTimeScaler = OPTIMISTIC_UNCHOKE_MULTIPLIER ;
2008-06-03 04:29:56 +00:00
}
2012-12-05 17:29:46 +00:00
tr_ptrArrayDestruct ( & randPool , NULL ) ;
2007-09-20 16:32:01 +00:00
}
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < size ; + + i )
tr_peerMsgsSetChoke ( choke [ i ] . peer - > msgs , choke [ i ] . isChoked ) ;
2007-09-20 16:32:01 +00:00
/* cleanup */
2012-12-05 17:29:46 +00:00
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
{
2009-02-04 16:58:52 +00:00
tr_torrent * tor = NULL ;
tr_peerMgr * mgr = vmgr ;
2012-12-05 17:29:46 +00:00
const uint64_t now = tr_time_msec ( ) ;
2011-01-29 18:59:23 +00:00
2012-12-05 17:29:46 +00:00
managerLock ( mgr ) ;
2008-09-23 19:11:04 +00:00
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) ) {
if ( tor - > isRunning ) {
2011-04-02 08:35:47 +00:00
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
if ( ! tr_ptrArrayEmpty ( & t - > peers ) ) {
rechokeUploads ( t , now ) ;
rechokeDownloads ( t ) ;
2011-05-10 04:46:44 +00:00
}
2010-03-06 14:56:15 +00:00
}
}
2009-02-04 16:58:52 +00:00
2012-12-05 17:29:46 +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
2012-12-05 17:29:46 +00:00
shouldPeerBeClosed ( const Torrent * t ,
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
{
2008-09-23 19:11:04 +00:00
const tr_torrent * tor = t - > tor ;
2009-05-09 06:08:21 +00:00
const struct peer_atom * atom = peer - > atom ;
2007-09-22 14:18:52 +00:00
2007-10-13 13:54:05 +00:00
/* if it's marked for purging, close it */
2012-12-05 17:29:46 +00:00
if ( peer - > doPurge )
2008-09-23 19:11:04 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " purging peer %s because its doPurge flag is set " ,
tr_atomAddrStr ( atom ) ) ;
2011-03-22 15:19:54 +00:00
return true ;
2007-10-13 13:54:05 +00:00
}
2007-09-29 06:37:03 +00:00
2011-03-07 03:46:26 +00:00
/* disconnect if we're both seeds and enough time has passed for PEX */
2012-12-05 17:29:46 +00:00
if ( tr_torrentIsSeed ( tor ) & & peerIsSeed ( peer ) )
return ! tr_torrentAllowsPex ( tor ) | | ( now - atom - > time > = 30 ) ;
2007-10-01 03:24:52 +00:00
2007-10-13 13:54:05 +00:00
/* 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 . . . */
2008-05-06 20:31:05 +00:00
{
2012-12-05 17:29:46 +00:00
const int relaxStrictnessIfFewerThanN = ( int ) ( ( getMaxPeerCount ( tor ) * 0.9 ) + 0.5 ) ;
2007-10-13 13:54:05 +00:00
/* if we have >= relaxIfFewerThan, strictness is 100%.
* if we have zero connections , strictness is 0 % */
2008-12-05 22:56:19 +00:00
const float strictness = peerCount > = relaxStrictnessIfFewerThanN
2009-01-20 03:32:54 +00:00
? 1.0
: peerCount / ( float ) relaxStrictnessIfFewerThanN ;
2008-12-05 22:56:19 +00:00
const int lo = MIN_UPLOAD_IDLE_SECS ;
const int hi = MAX_UPLOAD_IDLE_SECS ;
2012-12-05 17:29:46 +00:00
const int limit = hi - ( ( hi - lo ) * strictness ) ;
const int idleTime = now - MAX ( atom - > time , atom - > piece_data_time ) ;
/*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);*/
if ( idleTime > limit ) {
tordbg ( t , " purging peer %s because it's been %d secs since we shared anything " ,
tr_atomAddrStr ( atom ) , idleTime ) ;
2011-03-22 15:19:54 +00:00
return true ;
2007-10-13 13:54:05 +00:00
}
2007-09-22 14:18:52 +00:00
}
2011-03-22 15:19:54 +00:00
return false ;
2007-10-13 13:54:05 +00:00
}
static tr_peer * *
2012-12-05 17:29:46 +00:00
getPeersToClose ( Torrent * t , const time_t now_sec , int * setmeSize )
2007-10-13 13:54:05 +00:00
{
2008-12-05 22:56:19 +00:00
int i , peerCount , outsize ;
2011-04-27 19:06:06 +00:00
struct tr_peer * * ret = NULL ;
2012-12-05 17:29:46 +00:00
tr_peer * * peers = ( tr_peer * * ) tr_ptrArrayPeek ( & t - > peers , & peerCount ) ;
2007-10-13 13:54:05 +00:00
2012-12-05 17:29:46 +00:00
assert ( torrentIsLocked ( t ) ) ;
2007-10-13 13:54:05 +00:00
2012-12-05 17:29:46 +00:00
for ( i = outsize = 0 ; i < peerCount ; + + i ) {
if ( shouldPeerBeClosed ( t , peers [ i ] , peerCount , now_sec ) ) {
if ( ret = = NULL )
ret = tr_new ( tr_peer * , peerCount ) ;
2007-10-13 13:54:05 +00:00
ret [ outsize + + ] = peers [ i ] ;
2011-04-27 19:06:06 +00:00
}
}
2007-10-13 13:54:05 +00:00
2007-09-30 23:55:49 +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
{
2009-11-19 03:00:20 +00:00
int sec ;
2008-08-16 05:12:55 +00:00
2008-09-05 05:14:49 +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 . */
2012-12-05 17:29:46 +00:00
if ( ( now - atom - > piece_data_time ) < = ( MINIMUM_RECONNECT_INTERVAL_SECS * 2 ) )
2008-09-05 05:14:49 +00:00
sec = MINIMUM_RECONNECT_INTERVAL_SECS ;
/* don't allow reconnects more often than our minimum */
2012-12-05 17:29:46 +00:00
else if ( ( now - atom - > time ) < MINIMUM_RECONNECT_INTERVAL_SECS )
2008-09-05 05:14:49 +00:00
sec = MINIMUM_RECONNECT_INTERVAL_SECS ;
/* otherwise, the interval depends on how many times we've tried
* and failed to connect to the peer */
2012-12-05 17:29:46 +00:00
else switch ( atom - > numFails ) {
2008-12-05 22:56:19 +00:00
case 0 : sec = 0 ; break ;
case 1 : sec = 5 ; break ;
case 2 : sec = 2 * 60 ; break ;
case 3 : sec = 15 * 60 ; break ;
case 4 : sec = 30 * 60 ; break ;
case 5 : sec = 60 * 60 ; break ;
default : sec = 120 * 60 ; break ;
}
2008-08-16 05:12:55 +00:00
2010-04-20 21:54:03 +00:00
/* penalize peers that were unreachable the last time we tried */
2012-12-05 17:29:46 +00:00
if ( atom - > flags2 & MYFLAG_UNREACHABLE )
2010-04-20 21:54:03 +00:00
sec + = sec ;
2007-09-26 04:44:54 +00:00
2012-12-05 17:29:46 +00:00
dbgmsg ( " reconnect interval for %s is %d seconds " , tr_atomAddrStr ( atom ) , sec ) ;
2010-04-20 21:54:03 +00:00
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
2012-12-05 17:29:46 +00:00
removePeer ( Torrent * t , tr_peer * peer )
2011-02-17 05:14:53 +00:00
{
tr_peer * removed ;
struct peer_atom * atom = peer - > atom ;
2012-12-05 17:29:46 +00:00
assert ( torrentIsLocked ( t ) ) ;
assert ( atom ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
atom - > time = tr_time ( ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
removed = tr_ptrArrayRemoveSorted ( & t - > peers , peer , peerCompare ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
if ( replicationExists ( t ) )
tr_decrReplicationFromBitfield ( t , & peer - > have ) ;
2011-02-17 05:14:53 +00:00
2012-12-05 17:29:46 +00:00
assert ( removed = = peer ) ;
peerDelete ( t , removed ) ;
2011-02-17 05:14:53 +00:00
}
2009-01-20 15:47:25 +00:00
static void
2012-12-05 17:29:46 +00:00
closePeer ( Torrent * t , tr_peer * peer )
2009-01-20 15:47:25 +00:00
{
struct peer_atom * atom ;
2012-12-05 17:29:46 +00:00
assert ( t ! = NULL ) ;
assert ( peer ! = NULL ) ;
2009-01-20 15:47:25 +00:00
2009-05-09 06:08:21 +00:00
atom = peer - > atom ;
2009-01-20 15:47:25 +00:00
/* if we transferred piece data, then they might be good peers,
2010-12-27 19:18:17 +00:00
so reset their ` numFails ' weight to zero . otherwise we connected
2009-01-20 15:47:25 +00:00
to them fruitlessly , so mark it as another fail */
2012-12-05 17:29:46 +00:00
if ( atom - > piece_data_time ) {
tordbg ( t , " resetting atom %s numFails to 0 " , tr_atomAddrStr ( atom ) ) ;
2009-01-20 15:47:25 +00:00
atom - > numFails = 0 ;
2010-04-20 21:54:03 +00:00
} else {
2009-01-20 15:47:25 +00:00
+ + atom - > numFails ;
2012-12-05 17:29:46 +00:00
tordbg ( t , " 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
2012-12-05 17:29:46 +00:00
tordbg ( t , " removing bad peer %s " , tr_peerIoGetAddrStr ( peer - > io ) ) ;
removePeer ( t , peer ) ;
2009-01-20 15:47:25 +00:00
}
2011-02-17 05:14:53 +00:00
static void
2012-12-05 17:29:46 +00:00
removeAllPeers ( Torrent * t )
2011-02-17 05:14:53 +00:00
{
2012-12-05 17:29:46 +00:00
while ( ! tr_ptrArrayEmpty ( & t - > peers ) )
removePeer ( t , tr_ptrArrayNth ( & t - > peers , 0 ) ) ;
2011-02-17 05:14:53 +00:00
}
2009-02-04 16:58:52 +00:00
static void
2012-12-05 17:29:46 +00:00
closeBadPeers ( Torrent * t , const time_t now_sec )
2007-09-30 23:55:49 +00:00
{
2012-12-05 17:29:46 +00:00
if ( ! tr_ptrArrayEmpty ( & t - > peers ) )
2011-04-07 20:15:49 +00:00
{
int i ;
int peerCount ;
2012-12-05 17:29:46 +00:00
struct tr_peer * * peers = getPeersToClose ( t , now_sec , & peerCount ) ;
for ( i = 0 ; i < peerCount ; + + i )
closePeer ( t , 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
{
tr_peer * peer ;
2009-07-06 12:27:24 +00:00
void * clientData ;
2009-07-05 18:28:36 +00:00
time_t pieceDataTime ;
time_t time ;
2009-07-06 12:27:24 +00:00
int speed ;
2011-03-22 15:19:54 +00:00
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
{
const struct peer_liveliness * a = va ;
const struct peer_liveliness * b = vb ;
2012-12-05 17:29:46 +00:00
if ( a - > doPurge ! = b - > doPurge )
2009-07-06 12:27:24 +00:00
return a - > doPurge ? 1 : - 1 ;
2012-12-05 17:29:46 +00:00
if ( a - > speed ! = b - > speed ) /* faster goes first */
2009-07-05 18:28:36 +00:00
return a - > speed > b - > speed ? - 1 : 1 ;
2009-07-06 12:27:24 +00:00
/* the one to give us data more recently goes first */
2012-12-05 17:29:46 +00:00
if ( a - > pieceDataTime ! = b - > pieceDataTime )
2009-07-05 18:28:36 +00:00
return a - > pieceDataTime > b - > pieceDataTime ? - 1 : 1 ;
2009-07-06 12:27:24 +00:00
/* the one we connected to most recently goes first */
2012-12-05 17:29:46 +00:00
if ( a - > time ! = b - > time )
2009-07-05 18:28:36 +00:00
return a - > time > b - > time ? - 1 : 1 ;
return 0 ;
}
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
{
int i ;
2009-07-06 12:27:24 +00:00
struct peer_liveliness * lives , * l ;
2009-07-05 18:28:36 +00:00
/* build a sortable array of peer + extra info */
2012-12-05 17:29:46 +00:00
lives = l = tr_new0 ( struct peer_liveliness , n ) ;
for ( i = 0 ; i < n ; + + i , + + l )
2009-10-27 20:06:55 +00:00
{
2009-07-05 18:28:36 +00:00
tr_peer * p = peers [ i ] ;
2009-07-06 12:27:24 +00:00
l - > peer = p ;
l - > doPurge = p - > doPurge ;
l - > pieceDataTime = p - > atom - > piece_data_time ;
l - > time = p - > atom - > time ;
2012-12-05 17:29:46 +00:00
l - > speed = tr_peerGetPieceSpeed_Bps ( p , now , TR_UP )
+ tr_peerGetPieceSpeed_Bps ( p , now , TR_DOWN ) ;
if ( clientData )
2009-07-06 12:27:24 +00:00
l - > clientData = clientData [ i ] ;
2009-07-05 18:28:36 +00:00
}
/* sort 'em */
2012-12-05 17:29:46 +00:00
assert ( n = = ( l - lives ) ) ;
qsort ( lives , n , sizeof ( struct peer_liveliness ) , compare ) ;
2009-07-05 18:28:36 +00:00
/* build the peer array */
2012-12-05 17:29:46 +00:00
for ( i = 0 , l = lives ; i < n ; + + i , + + l ) {
2009-07-06 12:27:24 +00:00
peers [ i ] = l - > peer ;
2012-12-05 17:29:46 +00:00
if ( clientData )
2009-07-06 12:27:24 +00:00
clientData [ i ] = l - > clientData ;
2009-07-05 18:28:36 +00:00
}
2012-12-05 17:29:46 +00:00
assert ( n = = ( l - lives ) ) ;
2009-07-05 18:28:36 +00:00
/* cleanup */
2012-12-05 17:29:46 +00:00
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
{
2012-12-05 17:29:46 +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
2012-12-05 17:29:46 +00:00
enforceTorrentPeerLimit ( Torrent * t , uint64_t now )
2009-07-05 18:28:36 +00:00
{
2012-12-05 17:29:46 +00:00
int n = tr_ptrArraySize ( & t - > peers ) ;
const int max = tr_torrentGetPeerLimit ( t - > tor ) ;
if ( n > max )
2009-07-05 18:28:36 +00:00
{
2012-12-05 17:29:46 +00:00
void * base = tr_ptrArrayBase ( & t - > peers ) ;
tr_peer * * peers = tr_memdup ( base , n * sizeof ( tr_peer * ) ) ;
sortPeersByLiveliness ( peers , NULL , n , now ) ;
while ( n > max )
closePeer ( t , 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
{
2009-07-06 12:27:24 +00:00
int n = 0 ;
tr_torrent * tor = NULL ;
2012-12-05 17:29:46 +00:00
const int max = tr_sessionGetPeerLimit ( session ) ;
2009-07-05 18:28:36 +00:00
/* count the total number of peers */
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
n + = tr_ptrArraySize ( & tor - > torrentPeers - > peers ) ;
2009-07-05 18:28:36 +00:00
2009-08-10 20:04:08 +00:00
/* if there are too many, prune out the worst */
2012-12-05 17:29:46 +00:00
if ( n > max )
2009-07-05 18:28:36 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peer * * peers = tr_new ( tr_peer * , n ) ;
Torrent * * torrents = tr_new ( Torrent * , n ) ;
2009-07-05 18:28:36 +00:00
/* populate the peer array */
2009-07-06 12:27:24 +00:00
n = 0 ;
2009-07-05 18:28:36 +00:00
tor = NULL ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) ) {
2009-07-05 18:28:36 +00:00
int i ;
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
const int tn = tr_ptrArraySize ( & t - > peers ) ;
for ( i = 0 ; i < tn ; + + i , + + n ) {
peers [ n ] = tr_ptrArrayNth ( & t - > peers , i ) ;
2009-07-05 18:28:36 +00:00
torrents [ n ] = t ;
}
}
2009-08-10 20:04:08 +00:00
2009-07-05 18:28:36 +00:00
/* sort 'em */
2012-12-05 17:29:46 +00:00
sortPeersByLiveliness ( peers , ( void * * ) torrents , n , now ) ;
2009-07-05 18:28:36 +00:00
/* cull out the crappiest */
2012-12-05 17:29:46 +00:00
while ( n - - > max )
closePeer ( torrents [ n ] , peers [ n ] ) ;
2009-07-05 18:28:36 +00:00
/* cleanup */
2012-12-05 17:29:46 +00:00
tr_free ( torrents ) ;
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
{
2009-07-05 18:28:36 +00:00
tr_torrent * tor ;
2009-02-04 16:58:52 +00:00
tr_peerMgr * mgr = vmgr ;
2012-12-05 17:29:46 +00:00
const time_t now_sec = tr_time ( ) ;
const uint64_t now_msec = tr_time_msec ( ) ;
2009-07-05 18:28:36 +00:00
2009-12-12 17:05:31 +00:00
/**
* * * enforce the per - session and per - torrent peer limits
* */
2009-07-05 18:28:36 +00:00
/* if we're over the per-torrent peer limits, cull some peers */
tor = NULL ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
if ( tor - > isRunning )
enforceTorrentPeerLimit ( tor - > torrentPeers , now_msec ) ;
2009-07-05 18:28:36 +00:00
/* if we're over the per-session peer limits, cull some peers */
2012-12-05 17:29:46 +00:00
enforceSessionPeerLimit ( mgr - > session , now_msec ) ;
2009-07-05 18:28:36 +00:00
2010-04-20 21:54:03 +00:00
/* remove crappy peers */
tor = NULL ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
if ( ! tor - > torrentPeers - > isRunning )
removeAllPeers ( tor - > torrentPeers ) ;
2011-02-19 12:30:18 +00:00
else
2012-12-05 17:29:46 +00:00
closeBadPeers ( tor - > torrentPeers , now_sec ) ;
2009-12-12 17:05:31 +00:00
2010-04-20 21:54:03 +00:00
/* try to make new peer connections */
2012-12-05 17:29:46 +00:00
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
{
2009-01-13 21:00:05 +00:00
tr_torrent * tor = NULL ;
2008-11-24 04:21:23 +00:00
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
2008-11-24 04:21:23 +00:00
{
2009-01-13 21:00:05 +00:00
int j ;
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
for ( j = 0 ; j < tr_ptrArraySize ( & t - > peers ) ; + + j )
2008-11-24 04:21:23 +00:00
{
2012-12-05 17:29:46 +00:00
tr_peer * peer = tr_ptrArrayNth ( & t - > peers , j ) ;
tr_peerMsgsPulse ( peer - > msgs ) ;
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
{
2010-03-06 14:56:15 +00:00
tr_torrent * tor ;
2008-09-17 19:44:24 +00:00
tr_peerMgr * mgr = vmgr ;
2011-08-01 22:24:24 +00:00
tr_session * session = mgr - > session ;
2012-12-05 17:29:46 +00:00
managerLock ( mgr ) ;
2008-09-17 19:44:24 +00:00
2008-12-20 22:19:34 +00:00
/* FIXME: this next line probably isn't necessary... */
2012-12-05 17:29:46 +00:00
pumpAllPeers ( mgr ) ;
2008-12-20 22:19:34 +00:00
/* allocate bandwidth to the peers */
2012-12-05 17:29:46 +00:00
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
2011-05-10 14:41:59 +00:00
/* torrent upkeep */
2010-03-06 14:56:15 +00:00
tor = NULL ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2011-05-10 14:41:59 +00:00
{
/* possibly stop torrents that have seeded enough */
2012-12-05 17:29:46 +00:00
tr_torrentCheckSeedLimit ( tor ) ;
2009-04-09 14:10:31 +00:00
2011-05-10 14:41:59 +00:00
/* run the completeness check for any torrents that need it */
2012-12-05 17:29:46 +00:00
if ( tor - > torrentPeers - > needsCompletenessCheck ) {
2011-03-22 15:19:54 +00:00
tor - > torrentPeers - > needsCompletenessCheck = false ;
2012-12-05 17:29:46 +00:00
tr_torrentRecheckCompleteness ( tor ) ;
2009-11-09 06:36:47 +00:00
}
2011-05-10 14:41:59 +00:00
/* stop torrents that are ready to stop, but couldn't be stopped
earlier during the peer - io callback call chain */
2012-12-05 17:29:46 +00:00
if ( tor - > isStopping )
tr_torrentStop ( tor ) ;
2011-05-10 14:41:59 +00:00
}
2009-08-13 17:25:26 +00:00
2011-08-01 22:24:24 +00:00
/* pump the queues */
2012-12-05 17:29:46 +00:00
queuePulse ( session , TR_UP ) ;
queuePulse ( session , TR_DOWN ) ;
2011-08-01 22:24:24 +00:00
2012-12-05 17:29:46 +00:00
reconnectPulse ( 0 , 0 , mgr ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +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
{
const struct peer_atom * a = * ( const struct peer_atom * * ) va ;
const struct peer_atom * b = * ( const struct peer_atom * * ) vb ;
2012-12-05 17:29:46 +00:00
assert ( tr_isAtom ( a ) ) ;
assert ( tr_isAtom ( b ) ) ;
2009-11-26 05:13:58 +00:00
2012-12-05 17:29:46 +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
{
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 ;
2012-12-05 17:29:46 +00:00
const time_t tr_now = tr_time ( ) ;
2009-11-26 05:13:58 +00:00
2012-12-05 17:29:46 +00:00
assert ( tr_isAtom ( a ) ) ;
assert ( tr_isAtom ( b ) ) ;
2009-11-26 05:13:58 +00:00
/* primary key: the last piece data time *if* it was within the last hour */
2012-12-05 17:29:46 +00:00
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 )
2009-11-26 05:13:58 +00:00
return atime > btime ? - 1 : 1 ;
/* secondary key: shelf date. */
2012-12-05 17:29:46 +00:00
if ( a - > shelf_date ! = b - > shelf_date )
2009-11-26 05:13:58 +00:00
return a - > shelf_date > b - > shelf_date ? - 1 : 1 ;
return 0 ;
}
static int
2012-12-05 17:29:46 +00:00
getMaxAtomCount ( const tr_torrent * tor )
2009-11-26 05:13:58 +00:00
{
const int n = tor - > maxConnectedPeers ;
2010-09-25 00:38:49 +00:00
/* approximate fit of the old jump discontinuous function */
2012-12-05 17:29:46 +00:00
if ( n > = 55 ) return n + 150 ;
if ( n > = 20 ) return 2 * n + 95 ;
2010-09-25 00:38:49 +00:00
return 4 * n + 55 ;
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
{
tr_torrent * tor = NULL ;
tr_peerMgr * mgr = vmgr ;
2012-12-05 17:29:46 +00:00
managerLock ( mgr ) ;
2009-11-26 05:13:58 +00:00
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
2009-11-26 05:13:58 +00:00
{
int atomCount ;
Torrent * t = tor - > torrentPeers ;
2012-12-05 17:29:46 +00:00
const int maxAtomCount = getMaxAtomCount ( tor ) ;
struct peer_atom * * atoms = ( struct peer_atom * * ) tr_ptrArrayPeek ( & t - > pool , & atomCount ) ;
2009-11-26 05:13:58 +00:00
2012-12-05 17:29:46 +00:00
if ( atomCount > maxAtomCount ) /* we've got too many atoms... time to prune */
2009-11-26 05:13:58 +00:00
{
int i ;
int keepCount = 0 ;
int testCount = 0 ;
2012-12-05 17:29:46 +00:00
struct peer_atom * * keep = tr_new ( struct peer_atom * , atomCount ) ;
struct peer_atom * * test = tr_new ( struct peer_atom * , atomCount ) ;
2009-11-26 05:13:58 +00:00
/* keep the ones that are in use */
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < atomCount ; + + i ) {
2009-11-26 05:13:58 +00:00
struct peer_atom * atom = atoms [ i ] ;
2012-12-05 17:29:46 +00:00
if ( peerIsInUse ( t , atom ) )
2009-11-26 05:13:58 +00:00
keep [ keepCount + + ] = atom ;
else
test [ testCount + + ] = atom ;
}
/* if there's room, keep the best of what's left */
i = 0 ;
2012-12-05 17:29:46 +00:00
if ( keepCount < maxAtomCount ) {
qsort ( test , testCount , sizeof ( struct peer_atom * ) , compareAtomPtrsByShelfDate ) ;
while ( i < testCount & & keepCount < maxAtomCount )
2009-11-26 05:13:58 +00:00
keep [ keepCount + + ] = test [ i + + ] ;
}
/* free the culled atoms */
2012-12-05 17:29:46 +00:00
while ( i < testCount )
tr_free ( test [ i + + ] ) ;
2009-11-26 05:13:58 +00:00
/* rebuild Torrent.pool with what's left */
2012-12-05 17:29:46 +00:00
tr_ptrArrayDestruct ( & t - > pool , NULL ) ;
2009-11-26 05:13:58 +00:00
t - > pool = TR_PTR_ARRAY_INIT ;
2012-12-05 17:29:46 +00:00
qsort ( keep , keepCount , sizeof ( struct peer_atom * ) , compareAtomPtrsByAddress ) ;
for ( i = 0 ; i < keepCount ; + + i )
tr_ptrArrayAppend ( & t - > pool , keep [ i ] ) ;
2009-11-27 14:27:44 +00:00
2012-12-05 17:29:46 +00:00
tordbg ( t , " max atom count is %d... pruned from %d to %d \n " , maxAtomCount , atomCount , keepCount ) ;
2009-11-26 05:13:58 +00:00
/* cleanup */
2012-12-05 17:29:46 +00:00
tr_free ( test ) ;
tr_free ( keep ) ;
2009-11-26 05:13:58 +00:00
}
}
2012-12-05 17:29:46 +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
{
/* not if we're both seeds */
2012-12-05 17:29:46 +00:00
if ( tr_torrentIsSeed ( tor ) & & atomIsSeed ( atom ) )
2011-03-22 15:19:54 +00:00
return false ;
2010-07-04 20:40:34 +00:00
2010-12-27 19:18:17 +00:00
/* not if we've already got a connection to them... */
2012-12-05 17:29:46 +00:00
if ( peerIsInUse ( tor - > torrentPeers , atom ) )
2011-03-22 15:19:54 +00:00
return false ;
2010-07-04 20:40:34 +00:00
2010-06-14 12:48:28 +00:00
/* not if we just tried them already */
2012-12-05 17:29:46 +00:00
if ( ( now - atom - > time ) < getReconnectIntervalSecs ( atom , now ) )
2011-03-22 15:19:54 +00:00
return false ;
2010-06-14 12:48:28 +00:00
2010-04-20 21:54:03 +00:00
/* not if they're blocklisted */
2012-12-05 17:29:46 +00:00
if ( isAtomBlocklisted ( tor - > session , atom ) )
2011-03-22 15:19:54 +00:00
return false ;
2010-04-20 21:54:03 +00:00
2010-07-04 20:40:34 +00:00
/* not if they're banned... */
2012-12-05 17:29:46 +00:00
if ( atom - > flags2 & MYFLAG_BANNED )
2011-03-22 15:19:54 +00:00
return false ;
2010-06-14 11:57:46 +00:00
2011-03-22 15:19:54 +00:00
return true ;
2010-04-20 21:54:03 +00:00
}
struct peer_candidate
{
2010-06-14 01:56:03 +00:00
uint64_t score ;
2010-04-20 21:54:03 +00:00
tr_torrent * tor ;
struct peer_atom * atom ;
} ;
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
{
2012-12-05 17:29:46 +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
{
value = ( value < < ( uint64_t ) width ) ;
value | = addme ;
return value ;
}
/* 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
{
uint64_t i ;
uint64_t score = 0 ;
2011-03-22 15:19:54 +00:00
const bool failed = atom - > lastConnectionAt < atom - > lastConnectionAttemptAt ;
2010-06-14 01:56:03 +00:00
/* prefer peers we've connected to, or never tried, over peers we failed to connect to. */
i = failed ? 1 : 0 ;
2012-12-05 17:29:46 +00:00
score = addValToKey ( score , 1 , i ) ;
2010-06-14 01:56:03 +00:00
/* prefer the one we attempted least recently (to cycle through all peers) */
i = atom - > lastConnectionAttemptAt ;
2012-12-05 17:29:46 +00:00
score = addValToKey ( score , 32 , i ) ;
2010-06-14 01:56:03 +00:00
/* prefer peers belonging to a torrent of a higher priority */
2012-12-05 17:29:46 +00:00
switch ( tr_torrentGetPriority ( tor ) ) {
2010-06-14 01:56:03 +00:00
case TR_PRI_HIGH : i = 0 ; break ;
case TR_PRI_NORMAL : i = 1 ; break ;
case TR_PRI_LOW : i = 2 ; break ;
}
2012-12-05 17:29:46 +00:00
score = addValToKey ( score , 4 , i ) ;
2010-06-14 01:56:03 +00:00
/* prefer recently-started torrents */
2012-12-05 17:29:46 +00:00
i = torrentWasRecentlyStarted ( tor ) ? 0 : 1 ;
score = addValToKey ( score , 1 , i ) ;
2010-06-14 01:56:03 +00:00
2010-06-26 18:49:31 +00:00
/* prefer torrents we're downloading with */
2012-12-05 17:29:46 +00:00
i = tr_torrentIsSeed ( tor ) ? 1 : 0 ;
score = addValToKey ( score , 1 , i ) ;
2010-06-26 18:49:31 +00:00
2010-12-14 18:33:48 +00:00
/* prefer peers that are known to be connectible */
2012-12-05 17:29:46 +00:00
i = ( atom - > flags & ADDED_F_CONNECTABLE ) ? 0 : 1 ;
score = addValToKey ( score , 1 , i ) ;
2010-12-14 18:33:48 +00:00
2010-06-14 01:56:03 +00:00
/* prefer peers that we might have a chance of uploading to...
so lower seed probability is better */
2012-12-05 17:29:46 +00:00
if ( atom - > seedProbability = = 100 ) i = 101 ;
else if ( atom - > seedProbability = = - 1 ) i = 100 ;
2010-06-14 01:56:03 +00:00
else i = atom - > seedProbability ;
2012-12-05 17:29:46 +00:00
score = addValToKey ( score , 8 , i ) ;
2010-06-14 01:56:03 +00:00
/* Prefer peers that we got from more trusted sources.
2010-12-23 02:35:21 +00:00
* lower ` fromBest ' values indicate more trusted sources */
2012-12-05 17:29:46 +00:00
score = addValToKey ( score , 4 , atom - > fromBest ) ;
2010-06-14 01:56:03 +00:00
/* salt */
2012-12-05 17:29:46 +00:00
score = addValToKey ( score , 8 , salt ) ;
2010-06-14 01:56:03 +00:00
return score ;
}
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
{
int i ;
uint64_t worstFirstScore = 0 ;
2012-12-05 17:29:46 +00:00
const int x = MIN ( n , k ) - 1 ;
2011-12-31 21:28:53 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < x ; i + + )
if ( worstFirstScore < candidates [ i ] . score )
2011-12-31 21:28:53 +00:00
worstFirstScore = candidates [ i ] . score ;
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < x ; i + + )
assert ( candidates [ i ] . score < = worstFirstScore ) ;
2011-12-31 21:28:53 +00:00
2012-12-05 17:29:46 +00:00
for ( i = x + 1 ; i < n ; i + + )
assert ( candidates [ i ] . score > = worstFirstScore ) ;
2011-12-31 21:28:53 +00:00
return true ;
}
# 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
{
2011-05-10 01:51:12 +00:00
int atomCount ;
int peerCount ;
2010-04-20 21:54:03 +00:00
tr_torrent * tor ;
struct peer_candidate * candidates ;
struct peer_candidate * walk ;
2012-12-05 17:29:46 +00:00
const time_t now = tr_time ( ) ;
const uint64_t now_msec = tr_time_msec ( ) ;
2010-04-29 03:21:54 +00:00
/* leave 5% of connection slots for incoming connections -- ticket #2609 */
2012-12-05 17:29:46 +00:00
const int maxCandidates = tr_sessionGetPeerLimit ( session ) * 0.95 ;
2010-04-20 21:54:03 +00:00
2011-05-10 01:51:12 +00:00
/* count how many peers and atoms we've got */
2010-04-20 21:54:03 +00:00
tor = NULL ;
2011-05-10 01:51:12 +00:00
atomCount = 0 ;
peerCount = 0 ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) ) {
atomCount + = tr_ptrArraySize ( & tor - > torrentPeers - > pool ) ;
peerCount + = tr_ptrArraySize ( & tor - > torrentPeers - > peers ) ;
2011-05-10 01:51:12 +00:00
}
/* don't start any new handshakes if we're full up */
2012-12-05 17:29:46 +00:00
if ( maxCandidates < = peerCount ) {
2010-04-20 21:54:03 +00:00
* candidateCount = 0 ;
return NULL ;
}
/* allocate an array of candidates */
2012-12-05 17:29:46 +00:00
walk = candidates = tr_new ( struct peer_candidate , atomCount ) ;
2010-04-20 21:54:03 +00:00
/* populate the candidate array */
tor = NULL ;
2012-12-05 17:29:46 +00:00
while ( ( tor = tr_torrentNext ( session , tor ) ) )
2010-04-20 21:54:03 +00:00
{
int i , nAtoms ;
struct peer_atom * * atoms ;
2012-12-05 17:29:46 +00:00
if ( ! tor - > torrentPeers - > isRunning )
2010-04-20 21:54:03 +00:00
continue ;
/* if we've already got enough peers in this torrent... */
2012-12-05 17:29:46 +00:00
if ( tr_torrentGetPeerLimit ( tor ) < = tr_ptrArraySize ( & tor - > torrentPeers - > peers ) )
2010-04-20 21:54:03 +00:00
continue ;
/* if we've already got enough speed in this torrent... */
2012-12-05 17:29:46 +00:00
if ( tr_torrentIsSeed ( tor ) & & isBandwidthMaxedOut ( & tor - > bandwidth , now_msec , TR_UP ) )
2010-04-20 21:54:03 +00:00
continue ;
2012-12-05 17:29:46 +00:00
atoms = ( struct peer_atom * * ) tr_ptrArrayPeek ( & tor - > torrentPeers - > pool , & nAtoms ) ;
for ( i = 0 ; i < nAtoms ; + + i )
2010-04-20 21:54:03 +00:00
{
struct peer_atom * atom = atoms [ i ] ;
2012-12-05 17:29:46 +00:00
if ( isPeerCandidate ( tor , atom , now ) )
2010-04-20 21:54:03 +00:00
{
2012-12-05 17:29:46 +00:00
const uint8_t salt = tr_cryptoWeakRandInt ( 1024 ) ;
2010-04-20 21:54:03 +00:00
walk - > tor = tor ;
walk - > atom = atom ;
2012-12-05 17:29:46 +00:00
walk - > score = getPeerCandidateScore ( tor , atom , salt ) ;
2010-04-20 21:54:03 +00:00
+ + walk ;
}
}
}
* candidateCount = walk - candidates ;
2012-12-05 17:29:46 +00:00
if ( walk ! = candidates )
2012-12-28 20:10:03 +00:00
selectPeerCandidates ( candidates , walk - candidates , max ) ;
2011-12-31 21:28:53 +00:00
2012-12-05 17:29:46 +00:00
assert ( checkBestScoresComeFirst ( candidates , * candidateCount , max ) ) ;
2011-12-31 21:28:53 +00:00
2010-04-20 21:54:03 +00:00
return candidates ;
}
static void
2012-12-05 17:29:46 +00:00
initiateConnection ( tr_peerMgr * mgr , Torrent * t , struct peer_atom * atom )
2010-04-20 21:54:03 +00:00
{
tr_peerIo * io ;
2012-12-05 17:29:46 +00:00
const time_t now = tr_time ( ) ;
bool utp = tr_sessionIsUTPEnabled ( mgr - > session ) & & ! atom - > utp_failed ;
2011-02-18 00:43:24 +00:00
2012-12-05 17:29:46 +00:00
if ( atom - > fromFirst = = TR_PEER_FROM_PEX )
2011-02-18 00:43:49 +00:00
/* 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 ) ;
2012-12-05 17:29:46 +00:00
tordbg ( t , " Starting an OUTGOING%s connection with %s " ,
2011-02-18 00:43:24 +00:00
utp ? " µTP " : " " ,
2012-12-05 17:29:46 +00:00
tr_atomAddrStr ( atom ) ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
io = tr_peerIoNewOutgoing ( mgr - > session ,
2011-03-31 14:53:22 +00:00
& mgr - > session - > bandwidth ,
2010-04-20 21:54:03 +00:00
& atom - > addr ,
atom - > port ,
t - > tor - > info . hash ,
2011-02-18 00:36:19 +00:00
t - > tor - > completeness = = TR_SEED ,
2012-12-05 17:29:46 +00:00
utp ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
if ( io = = NULL )
2010-04-20 21:54:03 +00:00
{
2012-12-05 17:29:46 +00:00
tordbg ( t , " peerIo not created; marking peer %s as unreachable " ,
tr_atomAddrStr ( atom ) ) ;
2010-12-14 18:33:48 +00:00
atom - > flags2 | = MYFLAG_UNREACHABLE ;
2010-04-20 21:54:03 +00:00
atom - > numFails + + ;
}
else
{
2012-12-05 17:29:46 +00:00
tr_handshake * handshake = tr_handshakeNew ( io ,
2010-04-20 21:54:03 +00:00
mgr - > session - > encryptionMode ,
myHandshakeDoneCB ,
2012-12-05 17:29:46 +00:00
mgr ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
assert ( tr_peerIoGetTorrentHash ( io ) ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
tr_peerIoUnref ( io ) ; /* balanced by the initial ref
in tr_peerIoNewOutgoing ( ) */
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
tr_ptrArrayInsertSorted ( & t - > outgoingHandshakes , handshake ,
handshakeCompare ) ;
2010-04-20 21:54:03 +00:00
}
atom - > lastConnectionAttemptAt = now ;
atom - > time = now ;
}
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
2012-12-05 17:29:46 +00:00
fprintf ( stderr , " Starting an OUTGOING connection with %s - [%s] seedProbability==%d; %s, %s \n " ,
tr_atomAddrStr ( c - > atom ) ,
tr_torrentName ( c - > tor ) ,
( int ) c - > atom - > seedProbability ,
tr_torrentIsPrivate ( c - > tor ) ? " private " : " public " ,
tr_torrentIsSeed ( c - > tor ) ? " seed " : " downloader " ) ;
2010-04-20 21:54:03 +00:00
# endif
2012-12-05 17:29:46 +00:00
initiateConnection ( mgr , c - > tor - > torrentPeers , 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
{
int i , n ;
struct peer_candidate * candidates ;
2012-12-05 17:29:46 +00:00
candidates = getPeerCandidates ( mgr - > session , & n , max ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
for ( i = 0 ; i < n & & i < max ; + + i )
initiateCandidateConnection ( mgr , & candidates [ i ] ) ;
2010-04-20 21:54:03 +00:00
2012-12-05 17:29:46 +00:00
tr_free ( candidates ) ;
2010-04-20 21:54:03 +00:00
}