2009-02-11 16:34:35 +00:00
2007-09-20 16:32:01 +00:00
/*
2009-01-10 23:09:07 +00:00
* This file Copyright ( C ) 2007 - 2009 Charles Kerr < charles @ transmissionbt . com >
2007-09-20 16:32:01 +00:00
*
* This file is licensed by the GPL version 2. Works owned by the
* Transmission project are granted a special exemption to clause 2 ( b )
2008-09-23 19:11:04 +00:00
* so that the bulk of its code can remain under the MIT license .
2007-09-20 16:32:01 +00:00
* This exemption does not extend to derived works not owned by
* the Transmission project .
*
* $ Id $
*/
2007-11-09 20:07:52 +00:00
# include <assert.h>
2008-10-10 02:14:51 +00:00
# include <errno.h>
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 */
# include <limits.h> /* INT_MAX */
2007-10-02 14:35:02 +00:00
# include <event.h>
2007-09-20 16:32:01 +00:00
# include "transmission.h"
2008-12-23 17:27:15 +00:00
# include "session.h"
2008-11-24 04:21:23 +00:00
# include "bandwidth.h"
# include "bencode.h"
2008-03-29 21:05:51 +00:00
# include "blocklist.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"
2009-01-12 21:59:53 +00:00
# include "fdlimit.h"
2007-09-20 16:32:01 +00:00
# include "handshake.h"
2008-06-07 21:26:41 +00:00
# include "inout.h" /* tr_ioTestPiece */
2007-09-20 16:32:01 +00:00
# include "net.h"
# include "peer-io.h"
# include "peer-mgr.h"
# include "peer-msgs.h"
# include "ptrarray.h"
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"
2007-09-20 16:32:01 +00:00
# include "trevent.h"
# 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
{
/* how frequently to change which peers are choked */
2008-09-23 19:11:04 +00:00
RECHOKE_PERIOD_MSEC = ( 10 * 1000 ) ,
2007-09-22 14:18:52 +00:00
2008-07-27 14:10:32 +00:00
/* minimum interval for refilling peers' request lists */
2009-02-04 16:58:52 +00:00
REFILL_PERIOD_MSEC = 400 ,
/* 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 */
2009-05-13 20:54:35 +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 */
2008-12-11 07:04:46 +00:00
MIN_UPLOAD_IDLE_SECS = ( 30 ) ,
2007-10-13 13:54:05 +00:00
/* when few peers are available, keep idle ones this long */
2008-12-11 07:04: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 # of peers to ask fer per torrent per reconnect pulse */
2009-01-03 07:23:26 +00:00
MAX_RECONNECTIONS_PER_PULSE = 16 ,
2007-10-02 00:05:40 +00:00
2008-01-11 18:13:09 +00:00
/* max number of peers to ask for per second overall.
2008-09-23 19:11:04 +00:00
* this throttle is to avoid overloading the router */
2009-01-03 07:23:26 +00:00
MAX_CONNECTIONS_PER_SECOND = 32 ,
2008-01-11 18:13:09 +00:00
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 ,
2007-10-08 01:31:27 +00:00
/* use for bitwise operations w/peer_atom.myflags */
2007-12-15 04:26:31 +00:00
MYFLAG_BANNED = 1 ,
2009-02-04 16:58:52 +00:00
/* use for bitwise operations w/peer_atom.myflags */
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 */
2008-09-05 05:14:49 +00:00
MINIMUM_RECONNECT_INTERVAL_SECS = 5
2007-09-22 14:18:52 +00:00
} ;
2007-09-22 00:22:10 +00:00
2007-10-01 16:31:17 +00:00
2007-09-20 16:32:01 +00:00
/**
* * *
* */
2008-12-02 19:46:51 +00:00
enum
{
UPLOAD_ONLY_UKNOWN ,
UPLOAD_ONLY_YES ,
UPLOAD_ONLY_NO
} ;
2008-12-11 17:02:34 +00:00
/**
* Peer information that should be kept even before we ' ve connected and
* after we ' ve disconnected . These are kept in a pool of peer_atoms to decide
* 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
{
2008-12-02 03:41:58 +00:00
uint8_t from ;
2008-12-02 19:46:51 +00:00
uint8_t flags ; /* these match the added_f flags */
uint8_t myflags ; /* flags that aren't defined in added_f */
uint8_t uploadOnly ; /* UPLOAD_ONLY_ */
2008-12-02 03:41:58 +00:00
tr_port port ;
uint16_t numFails ;
tr_address addr ;
2008-12-02 19:46:51 +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 ;
2007-09-30 23:55:49 +00:00
} ;
2009-02-18 17:19:36 +00:00
struct tr_blockIterator
{
time_t expirationDate ;
struct tr_torrent_peers * t ;
tr_block_index_t blockIndex , blockCount , * blocks ;
tr_piece_index_t pieceIndex , pieceCount , * pieces ;
} ;
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_bool isRunning ;
2008-10-25 02:20:16 +00:00
2009-02-18 17:19:36 +00:00
uint8_t hash [ SHA_DIGEST_LENGTH ] ;
int * pendingRequestCount ;
tr_ptrArray outgoingHandshakes ; /* tr_handshake */
tr_ptrArray pool ; /* struct peer_atom */
tr_ptrArray peers ; /* tr_peer */
tr_ptrArray webseeds ; /* tr_webseed */
tr_timer * refillTimer ;
tr_torrent * tor ;
tr_peer * optimistic ; /* the optimistic peer, or NULL if none */
struct tr_blockIterator * refillQueue ; /* used in refillPulse() */
2007-09-20 16:32:01 +00:00
2009-02-18 17:19:36 +00:00
struct tr_peerMgr * manager ;
2007-09-20 16:32:01 +00:00
}
Torrent ;
struct tr_peerMgr
{
2008-11-08 02:49:04 +00:00
tr_session * session ;
2008-12-29 08:54:36 +00:00
tr_ptrArray incomingHandshakes ; /* tr_handshake */
2008-11-08 02:49:04 +00:00
tr_timer * bandwidthTimer ;
2009-02-04 16:58:52 +00:00
tr_timer * rechokeTimer ;
tr_timer * reconnectTimer ;
2009-02-18 17:19:36 +00:00
tr_timer * refillUpkeepTimer ;
2007-09-20 16:32:01 +00:00
} ;
2008-10-14 01:29:33 +00:00
# define tordbg( t, ... ) \
2008-10-26 15:39:04 +00:00
do { \
if ( tr_deepLoggingIsActive ( ) ) \
tr_deepLog ( __FILE__ , __LINE__ , t - > tor - > info . name , __VA_ARGS__ ) ; \
} while ( 0 )
2008-09-17 19:44:24 +00:00
2008-10-14 01:29:33 +00:00
# define dbgmsg( ... ) \
2008-10-26 15:39:04 +00:00
do { \
if ( tr_deepLoggingIsActive ( ) ) \
tr_deepLog ( __FILE__ , __LINE__ , NULL , __VA_ARGS__ ) ; \
} while ( 0 )
2007-10-02 14:35:02 +00:00
/**
* * *
* */
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2008-02-28 19:33:11 +00:00
managerLock ( const struct tr_peerMgr * manager )
2007-09-29 06:37:03 +00:00
{
2008-09-17 19:44:24 +00:00
tr_globalLock ( manager - > session ) ;
2007-09-29 06:37:03 +00:00
}
2008-09-23 19:11:04 +00:00
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2008-02-28 19:33:11 +00:00
managerUnlock ( const struct tr_peerMgr * manager )
2007-09-29 06:37:03 +00:00
{
2008-09-17 19:44:24 +00:00
tr_globalUnlock ( manager - > session ) ;
2007-09-29 06:37:03 +00:00
}
2008-09-23 19:11:04 +00:00
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2007-09-29 06:37:03 +00:00
torrentLock ( Torrent * torrent )
{
managerLock ( torrent - > manager ) ;
}
2008-09-23 19:11:04 +00:00
2009-01-11 17:02:04 +00:00
static TR_INLINE void
2007-09-29 06:37:03 +00:00
torrentUnlock ( Torrent * torrent )
{
managerUnlock ( torrent - > manager ) ;
}
2008-09-23 19:11:04 +00:00
2009-01-11 17:02:04 +00:00
static TR_INLINE int
2007-09-30 23:55:49 +00:00
torrentIsLocked ( const Torrent * t )
2007-09-29 06:37:03 +00:00
{
2008-09-17 19:44:24 +00:00
return tr_globalIsLocked ( t - > manager - > session ) ;
2007-09-29 06:37:03 +00:00
}
/**
* * *
* */
2007-09-20 16:32:01 +00:00
static int
2008-12-22 00:52:44 +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
2008-12-02 03:41:58 +00:00
return tr_compareAddresses ( tr_handshakeGetAddr ( a , NULL ) , vb ) ;
2007-09-20 16:32:01 +00:00
}
static int
2008-12-22 00:52:44 +00:00
handshakeCompare ( const void * a , const void * b )
2007-09-20 16:32:01 +00:00
{
2007-09-21 15:31:46 +00:00
return handshakeCompareToAddr ( a , tr_handshakeGetAddr ( b , NULL ) ) ;
2007-09-20 16:32:01 +00:00
}
static tr_handshake *
2008-12-02 03:41:58 +00:00
getExistingHandshake ( tr_ptrArray * handshakes ,
const tr_address * addr )
2007-09-20 16:32:01 +00:00
{
2008-12-02 03:41:58 +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
2008-12-02 03:41:58 +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
2008-12-02 03:41:58 +00:00
return tr_compareAddresses ( & a - > addr , vb ) ;
2007-09-30 23:55:49 +00:00
}
static int
2008-12-02 03:41:58 +00:00
comparePeerAtoms ( 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
2007-09-30 23:55:49 +00:00
return comparePeerAtomToAddress ( va , & b - > addr ) ;
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
static Torrent *
2008-09-23 19:11:04 +00:00
getExistingTorrent ( tr_peerMgr * manager ,
const uint8_t * hash )
2007-09-20 16:32:01 +00:00
{
2009-01-13 21:00:05 +00:00
tr_torrent * tor = tr_torrentFindFromHash ( manager - > session , hash ) ;
return tor = = NULL ? NULL : tor - > torrentPeers ;
2007-09-20 16:32:01 +00:00
}
static int
2008-12-02 03:41:58 +00:00
peerCompare ( const void * va , const void * vb )
2007-09-20 16:32:01 +00:00
{
2007-10-03 16:42:43 +00:00
const tr_peer * a = va ;
const tr_peer * b = vb ;
2008-09-23 19:11:04 +00:00
2008-12-02 03:41:58 +00:00
return tr_compareAddresses ( & a - > addr , & b - > addr ) ;
2007-09-20 16:32:01 +00:00
}
static int
2008-12-02 03:41:58 +00:00
peerCompareToAddr ( const void * va , const void * vb )
2007-09-20 16:32:01 +00:00
{
2007-10-03 16:42:43 +00:00
const tr_peer * a = va ;
2008-09-23 19:11:04 +00:00
2008-12-02 03:41:58 +00:00
return tr_compareAddresses ( & a - > addr , vb ) ;
2007-09-20 16:32:01 +00:00
}
static tr_peer *
2008-12-02 03:41:58 +00:00
getExistingPeer ( Torrent * torrent ,
const tr_address * addr )
2007-09-20 16:32:01 +00:00
{
2007-09-29 06:37:03 +00:00
assert ( torrentIsLocked ( torrent ) ) ;
2008-12-02 03:41:58 +00:00
assert ( addr ) ;
2007-09-20 16:32:01 +00:00
2008-12-29 08:54:36 +00:00
return tr_ptrArrayFindSorted ( & torrent - > peers , addr , peerCompareToAddr ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-30 23:55:49 +00:00
static struct peer_atom *
2008-12-02 03:41:58 +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 ;
2007-09-30 23:55:49 +00:00
assert ( torrentIsLocked ( t ) ) ;
2008-12-29 08:54:36 +00:00
return tr_ptrArrayFindSorted ( & tt - > pool , addr , comparePeerAtomToAddress ) ;
2007-09-30 23:55:49 +00:00
}
2008-12-05 22:56:19 +00:00
static tr_bool
2008-12-02 03:41:58 +00:00
peerIsInUse ( const Torrent * ct ,
const tr_address * addr )
2007-09-30 23:55:49 +00:00
{
2007-10-02 16:12:44 +00:00
Torrent * t = ( Torrent * ) ct ;
2007-09-30 23:55:49 +00:00
assert ( torrentIsLocked ( t ) ) ;
2007-10-03 16:42:43 +00:00
return getExistingPeer ( t , addr )
2008-12-29 08:54:36 +00:00
| | getExistingHandshake ( & t - > outgoingHandshakes , addr )
| | getExistingHandshake ( & t - > manager - > incomingHandshakes , addr ) ;
2007-10-03 16:42:43 +00:00
}
static tr_peer *
2009-01-02 19:56:06 +00:00
peerConstructor ( const tr_address * addr )
2007-10-03 16:42:43 +00:00
{
tr_peer * p ;
p = tr_new0 ( tr_peer , 1 ) ;
2008-12-02 03:41:58 +00:00
p - > addr = * addr ;
2007-10-03 16:42:43 +00:00
return p ;
2007-09-30 23:55:49 +00:00
}
2007-09-20 16:32:01 +00:00
static tr_peer *
2008-12-02 03:41:58 +00:00
getPeer ( Torrent * torrent ,
const tr_address * addr )
2007-09-20 16:32:01 +00:00
{
2007-09-29 06:37:03 +00:00
tr_peer * peer ;
assert ( torrentIsLocked ( torrent ) ) ;
2008-12-02 03:41:58 +00:00
peer = getExistingPeer ( torrent , addr ) ;
2007-09-20 16:32:01 +00:00
2008-09-23 19:11:04 +00:00
if ( peer = = NULL )
{
2009-01-02 19:56:06 +00:00
peer = peerConstructor ( addr ) ;
2008-12-29 08:54:36 +00:00
tr_ptrArrayInsertSorted ( & torrent - > peers , peer , peerCompare ) ;
2007-09-20 16:32:01 +00:00
}
return peer ;
}
static void
2007-10-04 20:49:37 +00:00
peerDestructor ( tr_peer * peer )
2007-09-20 16:32:01 +00:00
{
2008-08-01 16:43:22 +00:00
assert ( peer ) ;
2007-09-20 16:32:01 +00:00
2008-12-02 17:10:54 +00:00
if ( peer - > msgs ! = NULL )
{
tr_peerMsgsUnsubscribe ( peer - > msgs , peer - > msgsTag ) ;
tr_peerMsgsFree ( peer - > msgs ) ;
}
2007-09-20 16:32:01 +00:00
2009-01-05 18:20:47 +00:00
tr_peerIoClear ( peer - > io ) ;
2009-01-05 06:45:08 +00:00
tr_peerIoUnref ( peer - > io ) ; /* balanced by the ref in handshakeDoneCB() */
2007-09-20 16:32:01 +00:00
tr_bitfieldFree ( peer - > have ) ;
tr_bitfieldFree ( peer - > blame ) ;
tr_free ( peer - > client ) ;
2008-11-06 02:56:51 +00:00
2007-09-20 16:32:01 +00:00
tr_free ( peer ) ;
}
2007-09-30 23:55:49 +00:00
static void
2009-05-09 06:08:21 +00:00
removePeer ( Torrent * t , tr_peer * peer )
2007-09-30 23:55:49 +00:00
{
2009-05-09 06:08:21 +00:00
tr_peer * removed ;
struct peer_atom * atom = peer - > atom ;
2007-09-30 23:55:49 +00:00
assert ( torrentIsLocked ( t ) ) ;
2008-08-01 16:43:22 +00:00
assert ( atom ) ;
2009-05-09 06:08:21 +00:00
2007-09-30 23:55:49 +00:00
atom - > time = time ( NULL ) ;
2008-12-29 08:54:36 +00:00
removed = tr_ptrArrayRemoveSorted ( & t - > peers , peer , peerCompare ) ;
2007-09-30 23:55:49 +00:00
assert ( removed = = peer ) ;
2007-10-03 16:42:43 +00:00
peerDestructor ( removed ) ;
2007-09-30 23:55:49 +00:00
}
2007-10-01 16:50:51 +00:00
static void
removeAllPeers ( Torrent * t )
{
2008-12-29 08:54:36 +00:00
while ( ! tr_ptrArrayEmpty ( & t - > peers ) )
removePeer ( t , tr_ptrArrayNth ( & t - > peers , 0 ) ) ;
2007-10-01 16:50:51 +00:00
}
2009-02-18 17:19:36 +00:00
static void blockIteratorFree ( struct tr_blockIterator * * inout ) ;
2007-09-20 16:32:01 +00:00
static void
2008-09-17 19:44:24 +00:00
torrentDestructor ( void * vt )
2007-09-20 16:32:01 +00:00
{
2008-09-17 19:44:24 +00:00
Torrent * t = vt ;
2008-09-23 19:11:04 +00:00
uint8_t hash [ SHA_DIGEST_LENGTH ] ;
2007-09-20 16:32:01 +00:00
2008-08-01 16:43:22 +00:00
assert ( t ) ;
2007-10-02 16:12:44 +00:00
assert ( ! t - > isRunning ) ;
2007-09-29 06:37:03 +00:00
assert ( torrentIsLocked ( t ) ) ;
2008-12-29 08:54:36 +00:00
assert ( tr_ptrArrayEmpty ( & t - > outgoingHandshakes ) ) ;
assert ( tr_ptrArrayEmpty ( & t - > peers ) ) ;
2007-09-20 16:32:01 +00:00
memcpy ( hash , t - > hash , SHA_DIGEST_LENGTH ) ;
2009-02-11 16:34:35 +00:00
tr_timerFree ( & t - > refillTimer ) ;
2009-02-18 17:19:36 +00:00
blockIteratorFree ( & t - > refillQueue ) ;
2008-12-29 08:54:36 +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
2008-10-25 02:20:16 +00:00
tr_free ( t - > pendingRequestCount ) ;
2007-09-20 16:32:01 +00:00
tr_free ( t ) ;
}
2008-09-23 19:11:04 +00:00
static void peerCallbackFunc ( void * vpeer ,
void * vevent ,
void * vt ) ;
2008-06-07 21:26:41 +00:00
2007-10-02 16:12:44 +00:00
static Torrent *
2008-09-23 19:11:04 +00:00
torrentConstructor ( tr_peerMgr * manager ,
tr_torrent * tor )
2007-10-02 16:12:44 +00:00
{
2008-09-23 19:11:04 +00:00
int i ;
2007-10-02 16:12:44 +00:00
Torrent * t ;
t = tr_new0 ( Torrent , 1 ) ;
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
memcpy ( t - > hash , tor - > info . hash , SHA_DIGEST_LENGTH ) ;
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < tor - > info . webseedCount ; + + i )
{
tr_webseed * w =
2008-12-29 08:54:36 +00:00
tr_webseedNew ( tor , tor - > info . webseeds [ i ] , peerCallbackFunc , t ) ;
tr_ptrArrayAppend ( & t - > webseeds , w ) ;
2008-06-07 21:26:41 +00:00
}
2007-10-02 16:12:44 +00:00
return t ;
}
2007-09-28 16:40:21 +00:00
2009-02-04 16:58:52 +00:00
static int bandwidthPulse ( void * vmgr ) ;
static int rechokePulse ( void * vmgr ) ;
static int reconnectPulse ( void * vmgr ) ;
2009-02-18 17:19:36 +00:00
static int refillUpkeep ( void * vmgr ) ;
2008-11-08 02:49:04 +00:00
2007-09-20 16:32:01 +00:00
tr_peerMgr *
2008-09-17 19:44:24 +00:00
tr_peerMgrNew ( tr_session * session )
2007-09-20 16:32:01 +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 ;
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
deleteTimers ( struct tr_peerMgr * m )
{
if ( m - > bandwidthTimer )
tr_timerFree ( & m - > bandwidthTimer ) ;
2009-02-04 16:58:52 +00:00
2009-05-15 02:12:50 +00:00
if ( m - > rechokeTimer )
2009-05-13 20:54:35 +00:00
tr_timerFree ( & m - > rechokeTimer ) ;
2009-05-15 02:12:50 +00:00
if ( m - > reconnectTimer )
2009-05-13 20:54:35 +00:00
tr_timerFree ( & m - > reconnectTimer ) ;
2009-05-15 02:12:50 +00:00
if ( m - > refillUpkeepTimer )
2009-05-13 20:54:35 +00:00
tr_timerFree ( & m - > refillUpkeepTimer ) ;
2007-09-20 16:32:01 +00:00
}
void
tr_peerMgrFree ( tr_peerMgr * manager )
{
2007-09-29 06:37:03 +00:00
managerLock ( manager ) ;
2009-05-13 20:54:35 +00:00
deleteTimers ( manager ) ;
2008-09-17 19:44:24 +00:00
2007-10-02 14:35:02 +00:00
/* free the handshakes. Abort invokes handshakeDoneCB(), which removes
* the item from manager - > handshakes , so this is a little roundabout . . . */
2008-12-29 08:54:36 +00:00
while ( ! tr_ptrArrayEmpty ( & manager - > incomingHandshakes ) )
tr_handshakeAbort ( tr_ptrArrayNth ( & manager - > incomingHandshakes , 0 ) ) ;
2008-09-23 19:11:04 +00:00
2008-12-29 08:54:36 +00:00
tr_ptrArrayDestruct ( & manager - > incomingHandshakes , NULL ) ;
2007-10-02 14:35:02 +00:00
2007-09-29 06:37:03 +00:00
managerUnlock ( manager ) ;
2007-09-20 16:32:01 +00:00
tr_free ( manager ) ;
}
2008-02-10 04:03:19 +00:00
static int
clientIsDownloadingFrom ( const tr_peer * peer )
{
return peer - > clientIsInterested & & ! peer - > clientIsChoked ;
}
static int
clientIsUploadingTo ( const tr_peer * peer )
{
return peer - > peerIsInterested & & ! peer - > peerIsChoked ;
}
2008-04-17 03:48:56 +00:00
/***
* * * *
* * */
2008-12-05 22:56:19 +00:00
tr_bool
2009-01-13 21:00:05 +00:00
tr_peerMgrPeerIsSeed ( const tr_torrent * tor ,
2008-12-22 00:52:44 +00:00
const tr_address * addr )
2008-04-17 03:48:56 +00:00
{
2008-12-05 22:56:19 +00:00
tr_bool isSeed = FALSE ;
2009-01-13 21:00:05 +00:00
const Torrent * t = tor - > torrentPeers ;
const struct peer_atom * atom = getExistingAtom ( t , addr ) ;
2008-04-17 03:48:56 +00:00
if ( atom )
isSeed = ( atom - > flags & ADDED_F_SEED_FLAG ) ! = 0 ;
return isSeed ;
}
2008-10-25 02:20:16 +00:00
/****
* * * * *
* * * * * REFILL
* * * * *
* * * */
static void
assertValidPiece ( Torrent * t , tr_piece_index_t piece )
{
assert ( t ) ;
assert ( t - > tor ) ;
assert ( piece < t - > tor - > info . pieceCount ) ;
}
static int
getPieceRequests ( Torrent * t , tr_piece_index_t piece )
{
assertValidPiece ( t , piece ) ;
return t - > pendingRequestCount ? t - > pendingRequestCount [ piece ] : 0 ;
}
static void
incrementPieceRequests ( Torrent * t , tr_piece_index_t piece )
{
assertValidPiece ( t , piece ) ;
if ( t - > pendingRequestCount = = NULL )
t - > pendingRequestCount = tr_new0 ( int , t - > tor - > info . pieceCount ) ;
t - > pendingRequestCount [ piece ] + + ;
}
static void
decrementPieceRequests ( Torrent * t , tr_piece_index_t piece )
{
assertValidPiece ( t , piece ) ;
if ( t - > pendingRequestCount )
t - > pendingRequestCount [ piece ] - - ;
}
2007-09-20 16:32:01 +00:00
struct tr_refill_piece
{
2008-09-23 19:11:04 +00:00
tr_priority_t priority ;
uint32_t piece ;
uint32_t peerCount ;
2008-10-25 02:20:16 +00:00
int random ;
int pendingRequestCount ;
2008-10-25 15:19:46 +00:00
int missingBlockCount ;
2007-09-20 16:32:01 +00:00
} ;
static int
2008-12-05 22:56:19 +00:00
compareRefillPiece ( const void * aIn , const void * bIn )
2007-09-20 16:32:01 +00:00
{
const struct tr_refill_piece * a = aIn ;
const struct tr_refill_piece * b = bIn ;
2008-02-10 04:03:19 +00:00
2007-12-25 05:42:33 +00:00
/* if one piece has a higher priority, it goes first */
2007-12-25 06:37:21 +00:00
if ( a - > priority ! = b - > priority )
2007-12-25 05:42:33 +00:00
return a - > priority > b - > priority ? - 1 : 1 ;
2008-08-22 02:15:37 +00:00
2008-10-25 02:20:16 +00:00
/* have a per-priority endgame */
if ( a - > pendingRequestCount ! = b - > pendingRequestCount )
return a - > pendingRequestCount < b - > pendingRequestCount ? - 1 : 1 ;
/* fewer missing pieces goes first */
if ( a - > missingBlockCount ! = b - > missingBlockCount )
return a - > missingBlockCount < b - > missingBlockCount ? - 1 : 1 ;
2007-09-20 16:32:01 +00:00
/* otherwise if one has fewer peers, it goes first */
2008-08-22 02:34:22 +00:00
if ( a - > peerCount ! = b - > peerCount )
2007-09-20 16:32:01 +00:00
return a - > peerCount < b - > peerCount ? - 1 : 1 ;
2007-10-01 14:24:22 +00:00
/* otherwise go with our random seed */
2008-08-22 02:34:22 +00:00
if ( a - > random ! = b - > random )
2008-08-22 02:15:37 +00:00
return a - > random < b - > random ? - 1 : 1 ;
return 0 ;
2007-09-20 16:32:01 +00:00
}
2008-10-25 02:20:16 +00:00
static tr_piece_index_t *
2008-12-22 00:52:44 +00:00
getPreferredPieces ( Torrent * t , tr_piece_index_t * pieceCount )
2007-09-20 16:32:01 +00:00
{
2008-10-25 02:20:16 +00:00
const tr_torrent * tor = t - > tor ;
const tr_info * inf = & tor - > info ;
tr_piece_index_t i ;
tr_piece_index_t poolSize = 0 ;
tr_piece_index_t * pool = tr_new ( tr_piece_index_t , inf - > pieceCount ) ;
int peerCount ;
2008-12-30 08:20:16 +00:00
const tr_peer * * peers ;
2007-09-29 06:37:03 +00:00
assert ( torrentIsLocked ( t ) ) ;
2009-01-04 16:59:15 +00:00
peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
peerCount = tr_ptrArraySize ( & t - > peers ) ;
2007-09-20 16:32:01 +00:00
2008-10-25 02:20:16 +00:00
/* make a list of the pieces that we want but don't have */
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < inf - > pieceCount ; + + i )
2008-10-25 15:19:46 +00:00
if ( ! tor - > info . pieces [ i ] . dnd
2009-01-02 17:01:55 +00:00
& & ! tr_cpPieceIsComplete ( & tor - > completion , i ) )
2007-09-20 16:32:01 +00:00
pool [ poolSize + + ] = i ;
2008-10-25 15:19:46 +00:00
/* sort the pool by which to request next */
2007-09-20 16:32:01 +00:00
if ( poolSize > 1 )
{
2008-10-25 02:20:16 +00:00
tr_piece_index_t j ;
struct tr_refill_piece * p = tr_new ( struct tr_refill_piece , poolSize ) ;
2007-09-20 16:32:01 +00:00
2008-09-23 19:11:04 +00:00
for ( j = 0 ; j < poolSize ; + + j )
2007-09-20 16:32:01 +00:00
{
2008-10-25 02:20:16 +00:00
int k ;
const tr_piece_index_t piece = pool [ j ] ;
2007-09-20 16:32:01 +00:00
struct tr_refill_piece * setme = p + j ;
setme - > piece = piece ;
setme - > priority = inf - > pieces [ piece ] . priority ;
setme - > peerCount = 0 ;
2008-08-27 18:50:21 +00:00
setme - > random = tr_cryptoWeakRandInt ( INT_MAX ) ;
2008-10-25 02:20:16 +00:00
setme - > pendingRequestCount = getPieceRequests ( t , piece ) ;
2008-10-25 15:19:46 +00:00
setme - > missingBlockCount
2009-01-02 17:01:55 +00:00
= tr_cpMissingBlocksInPiece ( & tor - > completion , piece ) ;
2007-09-20 16:32:01 +00:00
2008-09-23 19:11:04 +00:00
for ( k = 0 ; k < peerCount ; + + k )
{
2007-09-20 16:32:01 +00:00
const tr_peer * peer = peers [ k ] ;
2008-10-25 15:19:46 +00:00
if ( peer - > peerIsInterested
& & ! peer - > clientIsChoked
& & tr_bitfieldHas ( peer - > have , piece ) )
2007-09-20 16:32:01 +00:00
+ + setme - > peerCount ;
}
}
2008-09-23 19:11:04 +00:00
qsort ( p , poolSize , sizeof ( struct tr_refill_piece ) ,
compareRefillPiece ) ;
2007-09-20 16:32:01 +00:00
2008-09-23 19:11:04 +00:00
for ( j = 0 ; j < poolSize ; + + j )
2007-09-20 16:32:01 +00:00
pool [ j ] = p [ j ] . piece ;
tr_free ( p ) ;
}
* pieceCount = poolSize ;
return pool ;
}
2008-10-25 02:20:16 +00:00
static struct tr_blockIterator *
blockIteratorNew ( Torrent * t )
{
struct tr_blockIterator * i = tr_new0 ( struct tr_blockIterator , 1 ) ;
2009-02-18 17:19:36 +00:00
i - > expirationDate = time ( NULL ) + PIECE_LIST_SHELF_LIFE_SECS ;
2008-10-25 02:20:16 +00:00
i - > t = t ;
i - > pieces = getPreferredPieces ( t , & i - > pieceCount ) ;
2008-12-30 21:18:30 +00:00
i - > blocks = tr_new0 ( tr_block_index_t , t - > tor - > blockCountInPiece ) ;
2009-02-18 21:27:44 +00:00
tordbg ( t , " creating new refill queue.. it contains % " PRIu32 " pieces " , i - > pieceCount ) ;
2008-10-25 02:20:16 +00:00
return i ;
}
2008-10-11 04:07:50 +00:00
2009-02-18 17:19:36 +00:00
static tr_bool
2008-10-25 02:20:16 +00:00
blockIteratorNext ( struct tr_blockIterator * i , tr_block_index_t * setme )
{
2009-02-18 17:19:36 +00:00
tr_bool found ;
2008-10-25 02:20:16 +00:00
Torrent * t = i - > t ;
tr_torrent * tor = t - > tor ;
2008-10-11 04:07:50 +00:00
2008-10-25 02:20:16 +00:00
while ( ( i - > blockIndex = = i - > blockCount )
& & ( i - > pieceIndex < i - > pieceCount ) )
2008-10-11 04:07:50 +00:00
{
2008-10-25 02:20:16 +00:00
const tr_piece_index_t index = i - > pieces [ i - > pieceIndex + + ] ;
const tr_block_index_t b = tr_torPieceFirstBlock ( tor , index ) ;
const tr_block_index_t e = b + tr_torPieceCountBlocks ( tor , index ) ;
2008-10-11 04:07:50 +00:00
tr_block_index_t block ;
2008-10-25 02:20:16 +00:00
assert ( index < tor - > info . pieceCount ) ;
2008-10-11 04:07:50 +00:00
2008-10-25 02:20:16 +00:00
i - > blockCount = 0 ;
i - > blockIndex = 0 ;
for ( block = b ; block ! = e ; + + block )
2009-04-11 03:24:36 +00:00
if ( ! tr_cpBlockIsCompleteFast ( & tor - > completion , block ) )
2008-10-25 02:20:16 +00:00
i - > blocks [ i - > blockCount + + ] = block ;
2008-10-11 04:07:50 +00:00
}
2008-12-30 21:18:30 +00:00
assert ( i - > blockCount < = tor - > blockCountInPiece ) ;
2008-10-25 02:20:16 +00:00
if ( ( found = ( i - > blockIndex < i - > blockCount ) ) )
* setme = i - > blocks [ i - > blockIndex + + ] ;
2008-10-11 04:07:50 +00:00
2008-10-25 02:20:16 +00:00
return found ;
}
2009-02-25 13:04:51 +00:00
static void
blockIteratorSkipCurrentPiece ( struct tr_blockIterator * i )
{
i - > blockIndex = i - > blockCount ;
}
2008-10-25 02:20:16 +00:00
static void
2009-02-18 17:19:36 +00:00
blockIteratorFree ( struct tr_blockIterator * * inout )
2008-10-25 02:20:16 +00:00
{
2009-02-18 17:19:36 +00:00
struct tr_blockIterator * it = * inout ;
if ( it ! = NULL )
{
tr_free ( it - > blocks ) ;
tr_free ( it - > pieces ) ;
tr_free ( it ) ;
}
* inout = NULL ;
2008-10-11 04:07:50 +00:00
}
2008-02-10 04:03:19 +00:00
static tr_peer * *
2008-09-23 19:11:04 +00:00
getPeersUploadingToClient ( Torrent * t ,
int * setmeCount )
2008-02-10 04:03:19 +00:00
{
2008-10-25 02:20:16 +00:00
int j ;
int peerCount = 0 ;
int retCount = 0 ;
2008-12-29 08:54:36 +00:00
tr_peer * * peers = ( tr_peer * * ) tr_ptrArrayPeek ( & t - > peers , & peerCount ) ;
2008-09-23 19:11:04 +00:00
tr_peer * * ret = tr_new ( tr_peer * , peerCount ) ;
2008-02-10 04:03:19 +00:00
2008-10-25 02:20:16 +00:00
j = 0 ; /* this is a temporary test to make sure we walk through all the peers */
if ( peerCount )
2008-09-23 19:11:04 +00:00
{
2008-10-25 02:20:16 +00:00
/* Get a list of peers we're downloading from.
Pick a different starting point each time so all peers
2008-10-25 15:19:46 +00:00
get a chance at being the first in line */
2008-10-25 02:20:16 +00:00
const int fencepost = tr_cryptoWeakRandInt ( peerCount ) ;
int i = fencepost ;
do {
if ( clientIsDownloadingFrom ( peers [ i ] ) )
ret [ retCount + + ] = peers [ i ] ;
i = ( i + 1 ) % peerCount ;
+ + j ;
} while ( i ! = fencepost ) ;
2008-02-10 04:03:19 +00:00
}
2008-10-25 02:20:16 +00:00
assert ( j = = peerCount ) ;
2008-02-10 04:03:19 +00:00
* setmeCount = retCount ;
return ret ;
}
2008-10-25 15:19:46 +00:00
static uint32_t
getBlockOffsetInPiece ( const tr_torrent * tor , uint64_t b )
{
const uint64_t piecePos = tor - > info . pieceSize * tr_torBlockPiece ( tor , b ) ;
const uint64_t blockPos = tor - > blockSize * b ;
assert ( blockPos > = piecePos ) ;
return ( uint32_t ) ( blockPos - piecePos ) ;
}
2009-02-18 17:19:36 +00:00
static int
refillUpkeep ( void * vmgr )
{
tr_torrent * tor = NULL ;
tr_peerMgr * mgr = vmgr ;
time_t now ;
managerLock ( mgr ) ;
now = time ( NULL ) ;
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) ) {
Torrent * t = tor - > torrentPeers ;
if ( t & & t - > refillQueue & & ( t - > refillQueue - > expirationDate < = now ) ) {
tordbg ( t , " refill queue is past its shelf date; discarding. " ) ;
blockIteratorFree ( & t - > refillQueue ) ;
}
}
managerUnlock ( mgr ) ;
return TRUE ;
}
2009-02-11 16:34:35 +00:00
static int
refillPulse ( void * vtorrent )
2007-09-20 16:32:01 +00:00
{
2008-10-25 02:20:16 +00:00
tr_block_index_t block ;
int peerCount ;
int webseedCount ;
tr_peer * * peers ;
tr_webseed * * webseeds ;
2009-02-11 16:34:35 +00:00
Torrent * t = vtorrent ;
2008-10-25 02:20:16 +00:00
tr_torrent * tor = t - > tor ;
2009-02-18 17:19:36 +00:00
tr_bool hasNext = TRUE ;
2007-09-20 16:32:01 +00:00
if ( ! t - > isRunning )
2009-02-11 16:34:35 +00:00
return TRUE ;
2007-10-19 23:23:21 +00:00
if ( tr_torrentIsSeed ( t - > tor ) )
2009-02-11 16:34:35 +00:00
return TRUE ;
2007-09-20 16:32:01 +00:00
2009-02-11 16:34:35 +00:00
torrentLock ( t ) ;
2007-10-06 18:20:52 +00:00
tordbg ( t , " Refilling Request Buffers... " ) ;
2007-09-29 06:37:03 +00:00
2009-02-18 17:19:36 +00:00
if ( t - > refillQueue = = NULL )
t - > refillQueue = blockIteratorNew ( t ) ;
2008-02-10 04:03:19 +00:00
peers = getPeersUploadingToClient ( t , & peerCount ) ;
2008-12-29 08:54:36 +00:00
webseedCount = tr_ptrArraySize ( & t - > webseeds ) ;
2009-01-04 16:59:15 +00:00
webseeds = tr_memdup ( tr_ptrArrayBase ( & t - > webseeds ) ,
2008-10-25 02:20:16 +00:00
webseedCount * sizeof ( tr_webseed * ) ) ;
2008-06-07 21:26:41 +00:00
2008-10-25 02:20:16 +00:00
while ( ( webseedCount | | peerCount )
2009-02-18 17:19:36 +00:00
& & ( ( hasNext = blockIteratorNext ( t - > refillQueue , & block ) ) ) )
2007-09-20 16:32:01 +00:00
{
2008-10-11 04:07:50 +00:00
int j ;
2009-02-25 13:04:51 +00:00
tr_bool handled = FALSE ;
2008-10-11 04:07:50 +00:00
const tr_piece_index_t index = tr_torBlockPiece ( tor , block ) ;
2008-10-25 15:19:46 +00:00
const uint32_t offset = getBlockOffsetInPiece ( tor , block ) ;
2008-10-11 04:07:50 +00:00
const uint32_t length = tr_torBlockCountBytes ( tor , block ) ;
2008-02-10 04:03:19 +00:00
2009-02-18 22:25:13 +00:00
assert ( block < tor - > blockCount ) ;
2008-10-11 04:07:50 +00:00
/* find a peer who can ask for this block */
2008-10-25 02:20:16 +00:00
for ( j = 0 ; ! handled & & j < peerCount ; )
2007-09-20 16:32:01 +00:00
{
2008-12-22 00:52:44 +00:00
const tr_addreq_t val = tr_peerMsgsAddRequest ( peers [ j ] - > msgs , index , offset , length ) ;
2007-09-20 16:32:01 +00:00
switch ( val )
{
2008-08-22 16:30:02 +00:00
case TR_ADDREQ_FULL :
2007-09-20 16:32:01 +00:00
case TR_ADDREQ_CLIENT_CHOKED :
2008-08-22 16:34:16 +00:00
peers [ j ] = peers [ - - peerCount ] ;
2007-09-20 16:32:01 +00:00
break ;
2008-09-23 19:11:04 +00:00
2008-08-22 16:30:02 +00:00
case TR_ADDREQ_MISSING :
case TR_ADDREQ_DUPLICATE :
2007-09-20 16:32:01 +00:00
+ + j ;
break ;
2008-09-23 19:11:04 +00:00
2007-09-20 16:32:01 +00:00
case TR_ADDREQ_OK :
2008-10-25 02:20:16 +00:00
incrementPieceRequests ( t , index ) ;
2008-06-07 21:26:41 +00:00
handled = TRUE ;
break ;
2008-09-23 19:11:04 +00:00
2008-06-07 21:26:41 +00:00
default :
assert ( 0 & & " unhandled value " ) ;
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
/* maybe one of the webseeds can do it */
2008-10-25 02:20:16 +00:00
for ( j = 0 ; ! handled & & j < webseedCount ; )
2008-06-07 21:26:41 +00:00
{
2008-12-22 00:52:44 +00:00
const tr_addreq_t val = tr_webseedAddRequest ( webseeds [ j ] , index , offset , length ) ;
2008-06-07 21:26:41 +00:00
switch ( val )
{
2008-08-22 16:30:02 +00:00
case TR_ADDREQ_FULL :
2008-08-22 16:34:16 +00:00
webseeds [ j ] = webseeds [ - - webseedCount ] ;
2008-06-07 21:26:41 +00:00
break ;
2008-09-23 19:11:04 +00:00
2008-06-07 21:26:41 +00:00
case TR_ADDREQ_OK :
2008-10-25 02:20:16 +00:00
incrementPieceRequests ( t , index ) ;
2008-06-07 21:26:41 +00:00
handled = TRUE ;
break ;
2008-09-23 19:11:04 +00:00
2007-09-20 16:32:01 +00:00
default :
assert ( 0 & & " unhandled value " ) ;
break ;
}
}
2009-02-25 13:04:51 +00:00
if ( ! handled )
blockIteratorSkipCurrentPiece ( t - > refillQueue ) ;
2007-09-20 16:32:01 +00:00
}
/* cleanup */
2008-06-07 21:26:41 +00:00
tr_free ( webseeds ) ;
2007-10-02 02:01:57 +00:00
tr_free ( peers ) ;
2009-02-04 16:58:52 +00:00
2009-02-18 21:27:44 +00:00
if ( ! hasNext ) {
tordbg ( t , " refill queue has no more blocks to request... freeing (webseed count: %d, peer count: %d) " , webseedCount , peerCount ) ;
2009-02-18 17:19:36 +00:00
blockIteratorFree ( & t - > refillQueue ) ;
2009-02-18 21:27:44 +00:00
}
2009-02-18 17:19:36 +00:00
2009-02-11 16:34:35 +00:00
t - > refillTimer = NULL ;
torrentUnlock ( t ) ;
return FALSE ;
2007-09-20 16:32:01 +00:00
}
2008-10-11 04:07:50 +00:00
static void
broadcastGotBlock ( Torrent * t , uint32_t index , uint32_t offset , uint32_t length )
{
2008-12-30 08:20:16 +00:00
size_t i ;
size_t peerCount ;
2008-10-11 04:07:50 +00:00
tr_peer * * peers ;
assert ( torrentIsLocked ( t ) ) ;
2008-12-16 21:12:14 +00:00
tordbg ( t , " got a block; cancelling any duplicate requests from peers % " PRIu32 " :% " PRIu32 " ->% " PRIu32 , index , offset , length ) ;
2008-12-30 08:20:16 +00:00
2009-01-04 16:59:15 +00:00
peerCount = tr_ptrArraySize ( & t - > peers ) ;
peers = ( tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
2008-12-30 08:20:16 +00:00
for ( i = 0 ; i < peerCount ; + + i )
if ( peers [ i ] - > msgs )
tr_peerMsgsCancel ( peers [ i ] - > msgs , index , offset , length ) ;
2008-10-11 04:07:50 +00:00
}
2007-11-13 05:36:43 +00:00
static void
2009-05-09 06:08:21 +00:00
addStrike ( Torrent * t , tr_peer * peer )
2007-11-13 05:36:43 +00:00
{
2008-09-23 19:11:04 +00:00
tordbg ( t , " increasing peer %s strike count to %d " ,
2008-12-02 03:41:58 +00:00
tr_peerIoAddrStr ( & peer - > addr ,
2008-09-23 19:11:04 +00:00
peer - > port ) , peer - > strikes + 1 ) ;
2007-11-13 05:36:43 +00:00
if ( + + peer - > strikes > = MAX_BAD_PIECES_PER_PEER )
{
2009-05-09 06:08:21 +00:00
struct peer_atom * atom = peer - > atom ;
2007-11-13 05:36:43 +00:00
atom - > myflags | = MYFLAG_BANNED ;
peer - > doPurge = 1 ;
2008-12-24 02:50:08 +00:00
tordbg ( t , " banning peer %s " , tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2007-11-13 05:36:43 +00:00
}
}
2007-09-20 16:32:01 +00:00
static void
2008-09-23 19:11:04 +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 ;
2008-06-07 21:26:41 +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 ;
tor - > downloadedCur - = MIN ( tor - > downloadedCur , byteCount ) ;
}
2009-02-11 16:34:35 +00:00
static void
refillSoon ( Torrent * t )
{
if ( t - > refillTimer = = NULL )
t - > refillTimer = tr_timerNew ( t - > manager - > session ,
refillPulse , t ,
REFILL_PERIOD_MSEC ) ;
}
2008-12-02 17:10:54 +00:00
static void
2008-12-22 00:52:44 +00:00
peerSuggestedPiece ( Torrent * t UNUSED ,
tr_peer * peer UNUSED ,
tr_piece_index_t pieceIndex UNUSED ,
int isFastAllowed UNUSED )
2008-12-02 17:10:54 +00:00
{
2008-12-22 00:52:44 +00:00
#if 0
2008-12-02 17:10:54 +00:00
assert ( t ) ;
assert ( peer ) ;
assert ( peer - > msgs ) ;
/* is this a valid piece? */
if ( pieceIndex > = t - > tor - > info . pieceCount )
return ;
/* don't ask for it if we've already got it */
if ( tr_cpPieceIsComplete ( t - > tor - > completion , pieceIndex ) )
return ;
/* don't ask for it if they don't have it */
if ( ! tr_bitfieldHas ( peer - > have , pieceIndex ) )
return ;
/* don't ask for it if we're choked and it's not fast */
if ( ! isFastAllowed & & peer - > clientIsChoked )
return ;
/* request the blocks that we don't have in this piece */
{
tr_block_index_t block ;
const tr_torrent * tor = t - > tor ;
const tr_block_index_t start = tr_torPieceFirstBlock ( tor , pieceIndex ) ;
const tr_block_index_t end = start + tr_torPieceCountBlocks ( tor , pieceIndex ) ;
for ( block = start ; block < end ; + + block )
{
if ( ! tr_cpBlockIsComplete ( tor - > completion , block ) )
{
const uint32_t offset = getBlockOffsetInPiece ( tor , block ) ;
const uint32_t length = tr_torBlockCountBytes ( tor , block ) ;
2008-12-22 00:52:44 +00:00
tr_peerMsgsAddRequest ( peer - > msgs , pieceIndex , offset , length ) ;
2008-12-02 17:10:54 +00:00
incrementPieceRequests ( t , pieceIndex ) ;
}
}
}
2008-12-22 00:52:44 +00:00
# endif
2008-12-02 17:10:54 +00:00
}
2008-06-07 21:26:41 +00:00
static void
2008-12-22 00:52:44 +00:00
peerCallbackFunc ( void * vpeer , void * vevent , void * vt )
2008-06-07 21:26:41 +00:00
{
2008-12-22 00:52:44 +00:00
tr_peer * peer = vpeer ; /* may be NULL if peer is a webseed */
Torrent * t = vt ;
2008-06-07 21:26:41 +00:00
const tr_peer_event * e = vevent ;
2007-09-20 16:32:01 +00:00
2007-10-01 15:17:15 +00:00
torrentLock ( t ) ;
2007-09-29 06:37:03 +00:00
2007-09-20 16:32:01 +00:00
switch ( e - > eventType )
{
2008-12-02 19:46:51 +00:00
case TR_PEER_UPLOAD_ONLY :
/* update our atom */
2009-05-11 16:04:31 +00:00
if ( peer )
2009-05-09 06:08:21 +00:00
peer - > atom - > uploadOnly = e - > uploadOnly ? UPLOAD_ONLY_YES : UPLOAD_ONLY_NO ;
2008-12-02 19:46:51 +00:00
break ;
2009-02-11 16:34:35 +00:00
case TR_PEER_NEED_REQ :
refillSoon ( t ) ;
break ;
2008-06-07 21:26:41 +00:00
case TR_PEER_CANCEL :
2008-10-25 02:20:16 +00:00
decrementPieceRequests ( t , e - > pieceIndex ) ;
2007-10-06 18:20:52 +00:00
break ;
2008-09-23 19:11:04 +00:00
case TR_PEER_PEER_GOT_DATA :
{
2008-06-07 21:26:41 +00:00
const time_t now = time ( NULL ) ;
tr_torrent * tor = t - > tor ;
2008-11-17 04:00:57 +00:00
2009-03-28 16:47:01 +00:00
tr_torrentSetActivityDate ( tor , now ) ;
2008-11-17 04:00:57 +00:00
if ( e - > wasPieceData )
tor - > uploadedCur + = e - > length ;
/* update the stats */
if ( e - > wasPieceData )
tr_statsAddUploaded ( tor - > session , e - > length ) ;
/* update our atom */
2009-05-11 16:04:31 +00:00
if ( peer & & e - > wasPieceData )
2009-05-09 06:08:21 +00:00
peer - > atom - > piece_data_time = now ;
2008-11-17 04:00:57 +00:00
2009-04-09 14:10:31 +00:00
tor - > needsSeedRatioCheck = TRUE ;
2009-02-13 18:23:56 +00:00
2008-01-05 18:17:56 +00:00
break ;
}
2008-12-02 17:10:54 +00:00
case TR_PEER_CLIENT_GOT_SUGGEST :
if ( peer )
peerSuggestedPiece ( t , peer , e - > pieceIndex , FALSE ) ;
break ;
case TR_PEER_CLIENT_GOT_ALLOWED_FAST :
if ( peer )
peerSuggestedPiece ( t , peer , e - > pieceIndex , TRUE ) ;
break ;
2008-09-23 19:11:04 +00:00
case TR_PEER_CLIENT_GOT_DATA :
{
2008-06-07 21:26:41 +00:00
const time_t now = time ( NULL ) ;
tr_torrent * tor = t - > tor ;
2009-03-28 16:47:01 +00:00
tr_torrentSetActivityDate ( tor , now ) ;
2008-11-17 04:00:57 +00:00
2008-06-09 22:53:45 +00:00
/* only add this to downloadedCur if we got it from a peer --
* webseeds shouldn ' t count against our ratio . As one tracker
* 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 . " */
2008-11-17 04:00:57 +00:00
if ( peer & & e - > wasPieceData )
2008-06-09 22:53:45 +00:00
tor - > downloadedCur + = e - > length ;
2008-11-17 04:00:57 +00:00
/* update the stats */
if ( e - > wasPieceData )
tr_statsAddDownloaded ( tor - > session , e - > length ) ;
/* update our atom */
2009-05-11 16:04:31 +00:00
if ( peer & & 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-09-23 19:11:04 +00:00
case TR_PEER_PEER_PROGRESS :
{
if ( peer )
{
2009-05-09 06:08:21 +00:00
struct peer_atom * atom = peer - > atom ;
2008-12-05 22:56:19 +00:00
const int peerIsSeed = e - > progress > = 1.0 ;
if ( peerIsSeed ) {
tordbg ( t , " marking peer %s as a seed " , tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2008-06-07 21:26:41 +00:00
atom - > flags | = ADDED_F_SEED_FLAG ;
2008-12-05 22:56:19 +00:00
} else {
tordbg ( t , " marking peer %s as a non-seed " , tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2008-06-07 21:26:41 +00:00
atom - > flags & = ~ ADDED_F_SEED_FLAG ;
}
}
break ;
2007-09-20 23:07:36 +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 ;
2008-06-07 21:26:41 +00:00
2008-12-05 22:56:19 +00:00
tr_block_index_t block = _tr_block ( tor , e - > pieceIndex , e - > offset ) ;
2008-06-07 21:26:41 +00:00
2009-01-02 17:01:55 +00:00
tr_cpBlockAdd ( & tor - > completion , block ) ;
2008-10-25 02:20:16 +00:00
decrementPieceRequests ( t , e - > pieceIndex ) ;
2008-06-07 21:26:41 +00:00
2008-10-11 04:07:50 +00:00
broadcastGotBlock ( t , e - > pieceIndex , e - > offset , e - > length ) ;
2009-01-02 17:01:55 +00:00
if ( tr_cpPieceIsComplete ( & tor - > completion , e - > pieceIndex ) )
2008-06-07 21:26:41 +00:00
{
const tr_piece_index_t p = e - > pieceIndex ;
2008-12-31 18:08:13 +00:00
const tr_bool ok = tr_ioTestPiece ( tor , p , NULL , 0 ) ;
2008-06-07 21:26:41 +00:00
2008-10-02 20:30:29 +00:00
if ( ! ok )
2008-09-23 19:11:04 +00:00
{
2008-12-05 22:56:19 +00:00
tr_torerr ( tor , _ ( " Piece %lu, which was just downloaded, failed its checksum test " ) ,
( unsigned long ) p ) ;
2008-06-07 21:26:41 +00:00
}
2008-10-02 20:30:29 +00:00
tr_torrentSetHasPiece ( tor , p , ok ) ;
2008-06-07 21:26:41 +00:00
tr_torrentSetPieceChecked ( tor , p , TRUE ) ;
2009-01-13 21:00:05 +00:00
tr_peerMgrSetBlame ( tor , p , ok ) ;
2008-06-07 21:26:41 +00:00
2008-10-02 20:30:29 +00:00
if ( ! ok )
2009-01-12 21:59:53 +00:00
{
2008-06-07 21:26:41 +00:00
gotBadPiece ( t , p ) ;
2009-01-12 21:59:53 +00:00
}
2008-09-23 19:11:04 +00:00
else
{
2008-12-30 08:20:16 +00:00
int i ;
2009-01-12 21:59:53 +00:00
int peerCount ;
tr_peer * * peers ;
tr_file_index_t fileIndex ;
peerCount = tr_ptrArraySize ( & t - > peers ) ;
peers = ( tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
2008-12-30 08:20:16 +00:00
for ( i = 0 ; i < peerCount ; + + i )
2008-06-21 01:03:31 +00:00
tr_peerMsgsHave ( peers [ i ] - > msgs , p ) ;
2009-01-12 21:59:53 +00:00
for ( fileIndex = 0 ; fileIndex < tor - > info . fileCount ; + + fileIndex )
{
const tr_file * file = & tor - > info . files [ fileIndex ] ;
if ( ( file - > firstPiece < = p ) & & ( p < = file - > lastPiece ) & & tr_cpFileIsComplete ( & tor - > completion , fileIndex ) )
{
char * path = tr_buildPath ( tor - > downloadDir , file - > name , NULL ) ;
tordbg ( t , " closing recently-completed file \" %s \" " , path ) ;
tr_fdFileClose ( path ) ;
tr_free ( path ) ;
}
}
2008-06-21 01:03:31 +00:00
}
2008-06-07 21:26:41 +00:00
tr_torrentRecheckCompleteness ( tor ) ;
}
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 :
2008-10-03 04:49:06 +00:00
if ( e - > err = = EINVAL )
2008-09-23 19:11:04 +00:00
{
2008-10-03 04:49:06 +00:00
addStrike ( t , peer ) ;
peer - > doPurge = 1 ;
2008-12-24 02:50:08 +00:00
tordbg ( t , " setting %s doPurge flag because we got an EINVAL error " , tr_peerIoAddrStr ( & peer - > addr , peer - > port ) ) ;
2008-09-23 19:11:04 +00:00
}
2008-10-10 00:38:37 +00:00
else if ( ( e - > err = = ERANGE )
2008-10-03 04:49:06 +00:00
| | ( 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 ;
2008-12-24 02:50:08 +00:00
tordbg ( t , " setting %s doPurge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error " , tr_peerIoAddrStr ( & peer - > addr , peer - > port ) ) ;
2008-10-03 04:49:06 +00:00
}
else /* a local error, such as an IO error */
{
t - > tor - > error = e - > err ;
tr_strlcpy ( t - > tor - > errorString ,
tr_strerror ( t - > tor - > error ) ,
sizeof ( t - > tor - > errorString ) ) ;
tr_torrentStop ( t - > tor ) ;
2008-01-18 19:13:32 +00:00
}
2007-09-20 16:32:01 +00:00
break ;
default :
2008-09-23 19:11:04 +00:00
assert ( 0 ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
2007-10-01 15:17:15 +00:00
torrentUnlock ( t ) ;
2007-09-20 16:32:01 +00:00
}
2007-10-01 05:32:34 +00:00
static void
2008-12-02 03:41:58 +00:00
ensureAtomExists ( Torrent * t ,
const tr_address * addr ,
tr_port port ,
uint8_t flags ,
uint8_t from )
2007-10-01 05:32:34 +00:00
{
2007-10-16 03:14:07 +00:00
if ( getExistingAtom ( t , addr ) = = NULL )
2007-10-01 05:32:34 +00:00
{
2007-10-16 03:14:07 +00:00
struct peer_atom * a ;
2007-10-16 02:16:57 +00:00
a = tr_new0 ( struct peer_atom , 1 ) ;
2007-10-01 05:32:34 +00:00
a - > addr = * addr ;
a - > port = port ;
a - > flags = flags ;
2007-10-16 03:14:07 +00:00
a - > from = from ;
2008-12-05 22:56:19 +00:00
tordbg ( t , " got a new atom: %s " , tr_peerIoAddrStr ( & a - > addr , a - > port ) ) ;
2008-12-29 08:54:36 +00:00
tr_ptrArrayInsertSorted ( & t - > pool , a , comparePeerAtoms ) ;
2007-10-01 05:32:34 +00:00
}
}
2008-01-20 03:21:51 +00:00
static int
2008-09-05 05:14:49 +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
getPeerCount ( const Torrent * t )
{
2009-05-08 14:56:11 +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. */
2008-12-05 22:56:19 +00:00
static tr_bool
2008-12-22 00:52:44 +00:00
myHandshakeDoneCB ( tr_handshake * handshake ,
2008-12-20 22:19:34 +00:00
tr_peerIo * io ,
2009-01-24 17:20:07 +00:00
tr_bool isConnected ,
2008-09-23 19:11:04 +00:00
const uint8_t * peer_id ,
2008-12-20 22:19:34 +00:00
void * vmanager )
2008-09-23 19:11:04 +00:00
{
2008-12-05 22:56:19 +00:00
tr_bool ok = isConnected ;
tr_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
2008-08-01 16:43:22 +00:00
assert ( io ) ;
2009-01-24 17:20:07 +00:00
assert ( tr_isBool ( ok ) ) ;
2007-09-20 16:32:01 +00:00
2007-10-02 16:12:44 +00:00
t = tr_peerIoHasTorrentHash ( io )
? getExistingTorrent ( manager , tr_peerIoGetTorrentHash ( io ) )
: NULL ;
2007-09-20 16:32:01 +00:00
2007-10-02 16:12:44 +00:00
if ( tr_peerIoIsIncoming ( io ) )
2008-12-29 08:54:36 +00:00
ours = tr_ptrArrayRemoveSorted ( & manager - > incomingHandshakes ,
2007-10-02 16:12:44 +00:00
handshake , handshakeCompare ) ;
2008-08-01 16:43:22 +00:00
else if ( t )
2008-12-29 08:54:36 +00:00
ours = tr_ptrArrayRemoveSorted ( & t - > outgoingHandshakes ,
2007-10-02 16:12:44 +00:00
handshake , handshakeCompare ) ;
else
ours = handshake ;
2007-09-20 16:32:01 +00:00
2008-08-01 16:43:22 +00:00
assert ( ours ) ;
2007-10-02 16:12:44 +00:00
assert ( ours = = handshake ) ;
2007-09-29 06:37:03 +00:00
2008-08-01 16:43:22 +00:00
if ( t )
2007-09-29 06:37:03 +00:00
torrentLock ( t ) ;
2007-10-16 03:14:07 +00:00
addr = tr_peerIoGetAddress ( io , & port ) ;
2007-10-02 16:12:44 +00:00
2007-10-10 15:59:59 +00:00
if ( ! ok | | ! t | | ! t - > isRunning )
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
if ( t )
{
2007-11-08 04:11:09 +00:00
struct peer_atom * atom = getExistingAtom ( t , addr ) ;
if ( atom )
2008-08-08 22:44:32 +00:00
+ + atom - > numFails ;
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 ;
2007-10-01 05:32:34 +00:00
ensureAtomExists ( t , addr , port , 0 , TR_PEER_FROM_INCOMING ) ;
2007-10-08 01:31:27 +00:00
atom = getExistingAtom ( t , addr ) ;
2008-09-05 05:14:49 +00:00
atom - > time = time ( NULL ) ;
2008-12-11 07:04:46 +00:00
atom - > piece_data_time = 0 ;
2007-10-11 00:09:58 +00:00
2007-10-08 01:31:27 +00:00
if ( atom - > myflags & MYFLAG_BANNED )
{
2008-09-23 19:11:04 +00:00
tordbg ( t , " banned peer %s tried to reconnect " ,
2008-12-05 22:56:19 +00:00
tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2007-10-08 01:31:27 +00:00
}
2008-09-05 05:14:49 +00:00
else if ( tr_peerIoIsIncoming ( io )
2008-09-23 19:11:04 +00:00
& & ( 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
{
2007-10-11 00:09:58 +00:00
tr_peer * peer = getExistingPeer ( t , addr ) ;
2008-08-01 16:43:22 +00:00
if ( peer ) /* we already have this peer */
2007-10-11 00:09:58 +00:00
{
}
else
{
peer = getPeer ( t , addr ) ;
tr_free ( peer - > client ) ;
2008-04-29 16:57:16 +00:00
if ( ! peer_id )
peer - > client = NULL ;
2008-11-25 21:35:17 +00:00
else {
2008-04-29 16:57:16 +00:00
char client [ 128 ] ;
tr_clientForId ( client , sizeof ( client ) , peer_id ) ;
peer - > client = tr_strdup ( client ) ;
}
2008-11-25 21:35:17 +00:00
2007-10-11 00:09:58 +00:00
peer - > port = port ;
2009-05-09 06:08:21 +00:00
peer - > atom = atom ;
2009-01-06 03:21:22 +00:00
peer - > io = tr_handshakeStealIO ( handshake ) ; /* this steals its refcount too, which is
balanced by our unref in peerDestructor ( ) */
2009-06-14 22:19:19 +00:00
tr_peerIoSetParent ( peer - > io , & t - > tor - > bandwidth ) ;
2008-12-02 19:06:08 +00:00
tr_peerMsgsNew ( t - > tor , peer , peerCallbackFunc , t , & peer - > msgsTag ) ;
2008-09-19 17:03:25 +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
2008-08-01 16:43:22 +00:00
if ( t )
2007-09-29 06:37:03 +00:00
torrentUnlock ( t ) ;
2008-09-19 17:03:25 +00:00
return success ;
2007-09-20 16:32:01 +00:00
}
void
2008-12-02 03:41:58 +00:00
tr_peerMgrAddIncoming ( tr_peerMgr * manager ,
tr_address * addr ,
tr_port port ,
int socket )
2007-09-20 16:32:01 +00:00
{
2007-09-29 06:37:03 +00:00
managerLock ( manager ) ;
2008-09-17 19:44:24 +00:00
if ( tr_sessionIsAddressBlocked ( manager - > session , addr ) )
2008-03-30 00:57:55 +00:00
{
2008-12-05 22:56:19 +00:00
tr_dbg ( " Banned IP address \" %s \" tried to connect to us " , tr_ntop_non_ts ( addr ) ) ;
2008-03-30 00:57:55 +00:00
tr_netClose ( socket ) ;
}
2008-12-29 08:54:36 +00:00
else if ( getExistingHandshake ( & manager - > incomingHandshakes , addr ) )
2007-10-25 13:38:34 +00:00
{
tr_netClose ( socket ) ;
}
else /* we don't have a connetion 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
2009-01-02 19:56:06 +00:00
io = tr_peerIoNewIncoming ( manager - > session , manager - > session - > bandwidth , addr , port , socket ) ;
2007-10-15 16:01:42 +00:00
handshake = tr_handshakeNew ( io ,
2008-09-17 19:44:24 +00:00
manager - > session - > encryptionMode ,
2007-10-15 16:01:42 +00:00
myHandshakeDoneCB ,
manager ) ;
2007-10-02 16:12:44 +00:00
2009-01-05 06:45:08 +00:00
tr_peerIoUnref ( io ) ; /* balanced by the implicit ref in tr_peerIoNewIncoming() */
2008-12-29 08:54:36 +00:00
tr_ptrArrayInsertSorted ( & manager - > incomingHandshakes , handshake ,
2008-09-23 19:11:04 +00:00
handshakeCompare ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
managerUnlock ( manager ) ;
2007-09-20 16:32:01 +00:00
}
2008-12-22 00:52:44 +00:00
static tr_bool
2008-12-16 23:31:05 +00:00
tr_isPex ( const tr_pex * pex )
{
return pex & & tr_isAddress ( & pex - > addr ) ;
}
2007-09-20 16:32:01 +00:00
void
2009-01-13 21:00:05 +00:00
tr_peerMgrAddPex ( tr_torrent * tor ,
2008-09-23 19:11:04 +00:00
uint8_t from ,
const tr_pex * pex )
2007-09-20 16:32:01 +00:00
{
2008-12-17 03:38:02 +00:00
if ( tr_isPex ( pex ) ) /* safeguard against corrupt data */
{
2009-01-13 21:00:05 +00:00
Torrent * t = tor - > torrentPeers ;
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2008-12-17 03:38:02 +00:00
if ( ! tr_sessionIsAddressBlocked ( t - > manager - > session , & pex - > addr ) )
2009-01-17 23:14:35 +00:00
if ( tr_isValidPeerAddress ( & pex - > addr , pex - > port ) )
ensureAtomExists ( t , & pex - > addr , pex - > port , pex - > flags , from ) ;
2008-12-22 00:52:44 +00:00
2009-01-13 21:00:05 +00:00
managerUnlock ( t - > manager ) ;
2008-12-17 03:38:02 +00:00
}
2007-09-20 16:32:01 +00:00
}
2008-04-19 15:07:59 +00:00
tr_pex *
2008-09-23 19:11:04 +00:00
tr_peerMgrCompactToPex ( const void * compact ,
size_t compactLen ,
const uint8_t * added_f ,
size_t added_f_len ,
size_t * pexCount )
{
size_t i ;
size_t n = compactLen / 6 ;
2008-04-19 15:07:59 +00:00
const uint8_t * walk = compact ;
2008-09-23 19:11:04 +00:00
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
2008-08-09 16:17:59 +00:00
2008-09-23 19:11:04 +00:00
for ( i = 0 ; i < n ; + + i )
{
2008-12-02 03:41:58 +00:00
pex [ i ] . addr . type = TR_AF_INET ;
memcpy ( & pex [ i ] . addr . addr , walk , 4 ) ; walk + = 4 ;
2008-04-19 15:07:59 +00:00
memcpy ( & pex [ i ] . port , walk , 2 ) ; walk + = 2 ;
2008-08-10 14:58:11 +00:00
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 *
tr_peerMgrCompact6ToPex ( const void * compact ,
size_t compactLen ,
const uint8_t * added_f ,
size_t added_f_len ,
size_t * pexCount )
{
size_t i ;
size_t n = compactLen / 18 ;
const uint8_t * walk = compact ;
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
for ( i = 0 ; i < n ; + + i )
{
pex [ i ] . addr . type = TR_AF_INET6 ;
memcpy ( & pex [ i ] . addr . addr . addr6 . s6_addr , walk , 16 ) ; walk + = 16 ;
memcpy ( & pex [ i ] . port , walk , 2 ) ; walk + = 2 ;
if ( added_f & & ( n = = added_f_len ) )
pex [ i ] . flags = added_f [ i ] ;
}
* pexCount = n ;
return pex ;
}
tr_pex *
tr_peerMgrArrayToPex ( const void * array ,
size_t arrayLen ,
size_t * pexCount )
{
size_t i ;
size_t n = arrayLen / ( sizeof ( tr_address ) + 2 ) ;
/*size_t n = arrayLen / sizeof( tr_peerArrayElement );*/
const uint8_t * walk = array ;
tr_pex * pex = tr_new0 ( tr_pex , n ) ;
for ( i = 0 ; i < n ; i + + ) {
memcpy ( & pex [ i ] . addr , walk , sizeof ( tr_address ) ) ;
memcpy ( & pex [ i ] . port , walk + sizeof ( tr_address ) , 2 ) ;
pex [ i ] . flags = 0x00 ;
walk + = sizeof ( tr_address ) + 2 ;
}
* pexCount = n ;
return pex ;
}
2007-09-20 16:32:01 +00:00
/**
* * *
* */
void
2009-01-13 21:00:05 +00:00
tr_peerMgrSetBlame ( tr_torrent * tor ,
2008-08-20 13:45:52 +00:00
tr_piece_index_t pieceIndex ,
2007-10-08 01:31:27 +00:00
int success )
2007-09-20 16:32:01 +00:00
{
2007-10-08 01:31:27 +00:00
if ( ! success )
{
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 ;
assert ( torrentIsLocked ( t ) ) ;
2008-12-29 08:54:36 +00:00
peers = ( tr_peer * * ) tr_ptrArrayPeek ( & t - > peers , & peerCount ) ;
2008-09-23 19:11:04 +00:00
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 ] ;
if ( tr_bitfieldHas ( peer - > blame , pieceIndex ) )
{
2008-12-05 22:56:19 +00:00
tordbg ( t , " peer %s contributed to corrupt piece (%d); now has %d strikes " ,
tr_peerIoAddrStr ( & peer - > addr , peer - > port ) ,
pieceIndex , ( int ) peer - > strikes + 1 ) ;
2007-11-13 05:36:43 +00:00
addStrike ( t , peer ) ;
}
2007-10-08 01:31:27 +00:00
}
}
2007-09-20 16:32:01 +00:00
}
int
2008-12-05 22:56:19 +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 ;
assert ( tr_isPex ( a ) ) ;
assert ( tr_isPex ( b ) ) ;
if ( ( i = tr_compareAddresses ( & a - > addr , & b - > addr ) ) )
return i ;
if ( a - > port ! = b - > port )
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
}
2007-09-29 00:46:41 +00:00
static int
peerPrefersCrypto ( const tr_peer * peer )
{
if ( peer - > encryption_preference = = ENCRYPTION_PREFERENCE_YES )
return TRUE ;
if ( peer - > encryption_preference = = ENCRYPTION_PREFERENCE_NO )
return FALSE ;
return tr_peerIoIsEncrypted ( peer - > io ) ;
2008-09-23 19:11:04 +00:00
}
2007-09-20 16:32:01 +00:00
int
2009-01-13 21:00:05 +00:00
tr_peerMgrGetPeers ( tr_torrent * tor ,
2008-12-16 22:52:04 +00:00
tr_pex * * setme_pex ,
uint8_t af )
2007-09-20 16:32:01 +00:00
{
2008-12-15 00:17:08 +00:00
int peersReturning = 0 ;
2009-01-13 21:00:05 +00:00
const Torrent * t = tor - > torrentPeers ;
2007-09-20 16:32:01 +00:00
2009-01-13 21:00:05 +00:00
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2008-10-05 22:51:18 +00:00
{
int i ;
2009-01-04 16:59:15 +00:00
const tr_peer * * peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
const int peerCount = tr_ptrArraySize ( & t - > peers ) ;
2008-12-15 00:17:08 +00:00
/* for now, this will waste memory on torrents that have both
* ipv6 and ipv4 peers */
2008-10-05 22:51:18 +00:00
tr_pex * pex = tr_new ( tr_pex , peerCount ) ;
tr_pex * walk = pex ;
2007-09-20 16:32:01 +00:00
2008-12-16 22:28:19 +00:00
for ( i = 0 ; i < peerCount ; + + i )
2008-10-05 22:51:18 +00:00
{
const tr_peer * peer = peers [ i ] ;
2008-12-15 00:17:08 +00:00
if ( peer - > addr . type = = af )
{
2009-05-09 06:08:21 +00:00
const struct peer_atom * atom = peer - > atom ;
2008-12-22 00:52:44 +00:00
2008-12-16 21:12:14 +00:00
assert ( tr_isAddress ( & peer - > addr ) ) ;
walk - > addr = peer - > addr ;
2008-12-15 00:17:08 +00:00
walk - > port = peer - > port ;
walk - > flags = 0 ;
if ( peerPrefersCrypto ( peer ) )
walk - > flags | = ADDED_F_ENCRYPTION_FLAG ;
2008-12-22 00:52:44 +00:00
if ( ( atom - > uploadOnly = = UPLOAD_ONLY_YES ) | | ( peer - > progress > = 1.0 ) )
2008-12-15 00:17:08 +00:00
walk - > flags | = ADDED_F_SEED_FLAG ;
2008-12-16 22:28:19 +00:00
+ + peersReturning ;
+ + walk ;
2008-12-15 00:17:08 +00:00
}
2008-10-05 22:51:18 +00:00
}
2007-09-20 16:32:01 +00:00
2008-12-16 22:52:04 +00:00
assert ( ( walk - pex ) = = peersReturning ) ;
2008-12-15 00:17:08 +00:00
qsort ( pex , peersReturning , sizeof ( tr_pex ) , tr_pexCompare ) ;
2008-10-05 22:51:18 +00:00
* setme_pex = pex ;
2007-09-20 16:32:01 +00:00
}
2009-01-13 21:00:05 +00:00
managerUnlock ( t - > manager ) ;
2008-12-15 00:17:08 +00:00
return peersReturning ;
2007-09-20 16:32:01 +00:00
}
2009-05-13 20:54:35 +00:00
static void
ensureMgrTimersExist ( struct tr_peerMgr * m )
{
tr_session * s = m - > session ;
if ( m - > bandwidthTimer = = NULL )
m - > bandwidthTimer = tr_timerNew ( s , bandwidthPulse , m , BANDWIDTH_PERIOD_MSEC ) ;
if ( m - > rechokeTimer = = NULL )
m - > rechokeTimer = tr_timerNew ( s , rechokePulse , m , RECHOKE_PERIOD_MSEC ) ;
if ( m - > reconnectTimer = = NULL )
m - > reconnectTimer = tr_timerNew ( s , reconnectPulse , m , RECONNECT_PERIOD_MSEC ) ;
if ( m - > refillUpkeepTimer = = NULL )
m - > refillUpkeepTimer = tr_timerNew ( s , refillUpkeep , m , REFILL_UPKEEP_PERIOD_MSEC ) ;
}
2007-09-20 16:32:01 +00:00
void
2009-01-13 21:00:05 +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 ;
2009-05-13 20:54:35 +00:00
assert ( t ! = NULL ) ;
2009-02-11 16:34:35 +00:00
managerLock ( t - > manager ) ;
2009-05-13 20:54:35 +00:00
ensureMgrTimersExist ( t - > manager ) ;
2009-02-11 16:34:35 +00:00
if ( ! t - > isRunning )
{
t - > isRunning = TRUE ;
if ( ! tr_ptrArrayEmpty ( & t - > webseeds ) )
refillSoon ( t ) ;
}
2009-05-13 20:54:35 +00:00
rechokePulse ( t - > manager ) ;
2009-02-11 16:34:35 +00:00
managerUnlock ( t - > manager ) ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
static void
stopTorrent ( Torrent * t )
2007-09-20 16:32:01 +00:00
{
2007-09-29 06:37:03 +00:00
assert ( torrentIsLocked ( t ) ) ;
2009-02-04 16:58:52 +00:00
t - > isRunning = FALSE ;
2007-10-02 02:01:57 +00:00
2007-10-02 16:12:44 +00:00
/* disconnect the peers. */
2008-12-29 08:54:36 +00:00
tr_ptrArrayForeach ( & t - > peers , ( PtrArrayForeachFunc ) peerDestructor ) ;
tr_ptrArrayClear ( & t - > peers ) ;
2007-10-02 02:01:57 +00:00
2007-10-02 16:12:44 +00:00
/* disconnect the handshakes. handshakeAbort calls handshakeDoneCB(),
* which removes the handshake from t - > outgoingHandshakes . . . */
2008-12-29 08:54:36 +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
2009-01-13 21:00:05 +00:00
tr_peerMgrStopTorrent ( tr_torrent * tor )
2007-09-29 06:37:03 +00:00
{
2009-01-13 21:00:05 +00:00
Torrent * t = tor - > torrentPeers ;
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
stopTorrent ( t ) ;
managerUnlock ( t - > manager ) ;
2007-09-20 16:32:01 +00:00
}
void
tr_peerMgrAddTorrent ( tr_peerMgr * manager ,
tr_torrent * tor )
{
2007-09-29 06:37:03 +00:00
managerLock ( manager ) ;
2008-08-01 16:43:22 +00:00
assert ( tor ) ;
2009-01-13 21:00:05 +00:00
assert ( tor - > torrentPeers = = NULL ) ;
2007-09-20 16:32:01 +00:00
2009-01-13 21:00:05 +00:00
tor - > torrentPeers = torrentConstructor ( manager , tor ) ;
2007-09-29 06:37:03 +00:00
managerUnlock ( manager ) ;
2007-09-20 16:32:01 +00:00
}
void
2009-01-13 21:00:05 +00:00
tr_peerMgrRemoveTorrent ( tr_torrent * tor )
2007-09-20 16:32:01 +00:00
{
2009-01-13 21:00:05 +00:00
tr_torrentLock ( tor ) ;
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
stopTorrent ( tor - > torrentPeers ) ;
torrentDestructor ( tor - > torrentPeers ) ;
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
tr_torrentUnlock ( tor ) ;
2007-09-20 16:32:01 +00:00
}
void
2009-01-13 21:00:05 +00:00
tr_peerMgrTorrentAvailability ( const tr_torrent * tor ,
int8_t * tab ,
2008-08-20 13:45:52 +00:00
unsigned int tabCount )
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
tr_piece_index_t i ;
const Torrent * t ;
float interval ;
2008-12-22 00:52:44 +00:00
tr_bool isSeed ;
2008-09-23 19:11:04 +00:00
int peerCount ;
const tr_peer * * peers ;
2009-01-13 21:00:05 +00:00
tr_torrentLock ( tor ) ;
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
t = tor - > torrentPeers ;
2007-09-29 06:37:03 +00:00
tor = t - > tor ;
interval = tor - > info . pieceCount / ( float ) tabCount ;
2009-01-02 17:01:55 +00:00
isSeed = tor & & ( tr_cpGetStatus ( & tor - > completion ) = = TR_SEED ) ;
2009-01-04 16:59:15 +00:00
peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
peerCount = tr_ptrArraySize ( & t - > peers ) ;
2007-09-20 16:32:01 +00:00
memset ( tab , 0 , tabCount ) ;
2008-09-23 19:11:04 +00:00
for ( i = 0 ; tor & & i < tabCount ; + + i )
2007-09-20 16:32:01 +00:00
{
const int piece = i * interval ;
2009-01-02 17:01:55 +00:00
if ( isSeed | | tr_cpPieceIsComplete ( & tor - > completion , piece ) )
2007-09-20 16:32:01 +00:00
tab [ i ] = - 1 ;
2008-12-22 00:52:44 +00:00
else if ( peerCount ) {
2008-06-09 23:11:15 +00:00
int j ;
2008-09-23 19:11:04 +00:00
for ( j = 0 ; j < peerCount ; + + j )
2007-09-20 16:32:01 +00:00
if ( tr_bitfieldHas ( peers [ j ] - > have , i ) )
+ + tab [ i ] ;
}
}
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
tr_torrentUnlock ( tor ) ;
2007-09-20 16:32:01 +00:00
}
2008-04-11 23:05:14 +00:00
/* Returns the pieces that are available from peers */
2007-09-27 03:03:38 +00:00
tr_bitfield *
2009-01-13 21:00:05 +00:00
tr_peerMgrGetAvailable ( const tr_torrent * tor )
2007-09-27 03:03:38 +00:00
{
2008-12-30 08:20:16 +00:00
int i ;
int peerCount ;
2009-01-13 21:00:05 +00:00
Torrent * t = tor - > torrentPeers ;
2008-12-30 08:20:16 +00:00
const tr_peer * * peers ;
2007-09-27 03:03:38 +00:00
tr_bitfield * pieces ;
2009-01-13 21:00:05 +00:00
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2008-04-11 23:05:14 +00:00
pieces = tr_bitfieldNew ( t - > tor - > info . pieceCount ) ;
2009-01-04 16:59:15 +00:00
peerCount = tr_ptrArraySize ( & t - > peers ) ;
peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
2008-12-30 08:20:16 +00:00
for ( i = 0 ; i < peerCount ; + + i )
2008-04-11 23:05:14 +00:00
tr_bitfieldOr ( pieces , peers [ i ] - > have ) ;
2007-09-27 03:03:38 +00:00
2009-01-13 21:00:05 +00:00
managerUnlock ( t - > manager ) ;
2007-09-27 03:03:38 +00:00
return pieces ;
}
2007-09-20 16:32:01 +00:00
void
2009-01-13 21:00:05 +00:00
tr_peerMgrTorrentStats ( tr_torrent * tor ,
2008-12-05 22:56:19 +00:00
int * setmePeersKnown ,
int * setmePeersConnected ,
int * setmeSeedsConnected ,
int * setmeWebseedsSendingToUs ,
int * setmePeersSendingToUs ,
int * setmePeersGettingFromUs ,
int * setmePeersFrom )
{
int i , size ;
2009-01-13 21:00:05 +00:00
const Torrent * t = tor - > torrentPeers ;
2008-12-05 22:56:19 +00:00
const tr_peer * * peers ;
2008-06-10 02:36:52 +00:00
const tr_webseed * * webseeds ;
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2009-01-04 16:59:15 +00:00
peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
size = tr_ptrArraySize ( & t - > peers ) ;
2007-09-20 16:32:01 +00:00
2008-12-29 08:54:36 +00:00
* setmePeersKnown = tr_ptrArraySize ( & t - > pool ) ;
2008-06-10 02:36:52 +00:00
* setmePeersConnected = 0 ;
* setmeSeedsConnected = 0 ;
* setmePeersGettingFromUs = 0 ;
* setmePeersSendingToUs = 0 ;
* setmeWebseedsSendingToUs = 0 ;
2007-09-20 16:32:01 +00:00
2008-12-05 22:56:19 +00:00
for ( i = 0 ; i < TR_PEER_FROM__MAX ; + + i )
2007-09-21 15:13:23 +00:00
setmePeersFrom [ i ] = 0 ;
2008-12-05 22:56:19 +00:00
for ( i = 0 ; i < size ; + + i )
2007-09-20 16:32:01 +00:00
{
2008-12-05 22:56:19 +00:00
const tr_peer * peer = peers [ i ] ;
2009-05-09 06:08:21 +00:00
const struct peer_atom * atom = peer - > atom ;
2007-09-20 16:32:01 +00:00
if ( peer - > io = = NULL ) /* not connected */
continue ;
2008-12-05 22:56:19 +00:00
+ + * setmePeersConnected ;
2007-09-20 16:32:01 +00:00
2007-10-01 15:36:31 +00:00
+ + setmePeersFrom [ atom - > from ] ;
2007-09-20 16:32:01 +00:00
2008-01-16 17:52:47 +00:00
if ( clientIsDownloadingFrom ( peer ) )
2008-12-05 22:56:19 +00:00
+ + * setmePeersSendingToUs ;
2008-01-16 17:52:47 +00:00
if ( clientIsUploadingTo ( peer ) )
2008-12-05 22:56:19 +00:00
+ + * setmePeersGettingFromUs ;
2008-05-31 05:22:10 +00:00
if ( atom - > flags & ADDED_F_SEED_FLAG )
2008-12-05 22:56:19 +00:00
+ + * setmeSeedsConnected ;
2007-09-20 16:32:01 +00:00
}
2007-09-29 06:37:03 +00:00
2009-01-04 16:59:15 +00:00
webseeds = ( const tr_webseed * * ) tr_ptrArrayBase ( & t - > webseeds ) ;
size = tr_ptrArraySize ( & t - > webseeds ) ;
2008-12-05 22:56:19 +00:00
for ( i = 0 ; i < size ; + + i )
2008-06-10 02:36:52 +00:00
if ( tr_webseedIsActive ( webseeds [ i ] ) )
2008-12-05 22:56:19 +00:00
+ + * setmeWebseedsSendingToUs ;
2008-06-10 02:36:52 +00:00
2009-01-13 21:00:05 +00:00
managerUnlock ( t - > manager ) ;
2008-06-10 01:38:12 +00:00
}
2009-05-28 02:28:14 +00:00
float
tr_peerMgrGetWebseedSpeed ( const tr_torrent * tor , uint64_t now )
{
int i ;
float tmp ;
float ret = 0 ;
const Torrent * t = tor - > torrentPeers ;
const int n = tr_ptrArraySize ( & t - > webseeds ) ;
const tr_webseed * * webseeds = ( const tr_webseed * * ) tr_ptrArrayBase ( & t - > webseeds ) ;
for ( i = 0 ; i < n ; + + i )
if ( tr_webseedGetSpeed ( webseeds [ i ] , now , & tmp ) )
ret + = tmp ;
return ret ;
}
2008-06-10 01:38:12 +00:00
float *
2009-01-13 21:00:05 +00:00
tr_peerMgrWebSpeeds ( const tr_torrent * tor )
2008-06-10 01:38:12 +00:00
{
2009-01-13 21:00:05 +00:00
const Torrent * t = tor - > torrentPeers ;
2008-06-10 01:38:12 +00:00
const tr_webseed * * webseeds ;
2008-12-05 22:56:19 +00:00
int i ;
int webseedCount ;
float * ret ;
2009-01-05 04:27:54 +00:00
uint64_t now ;
2008-06-10 01:38:12 +00:00
2009-01-13 21:00:05 +00:00
assert ( t - > manager ) ;
managerLock ( t - > manager ) ;
2008-06-10 01:38:12 +00:00
2009-01-04 16:59:15 +00:00
webseeds = ( const tr_webseed * * ) tr_ptrArrayBase ( & t - > webseeds ) ;
webseedCount = tr_ptrArraySize ( & t - > webseeds ) ;
2009-01-13 21:00:05 +00:00
assert ( webseedCount = = tor - > info . webseedCount ) ;
2008-06-10 01:38:12 +00:00
ret = tr_new0 ( float , webseedCount ) ;
2009-01-05 04:27:54 +00:00
now = tr_date ( ) ;
2008-06-10 01:38:12 +00:00
2008-12-05 22:56:19 +00:00
for ( i = 0 ; i < webseedCount ; + + i )
2009-01-05 04:27:54 +00:00
if ( ! tr_webseedGetSpeed ( webseeds [ i ] , now , & ret [ i ] ) )
2008-06-10 01:46:36 +00:00
ret [ i ] = - 1.0 ;
2008-06-10 01:38:12 +00:00
2009-01-13 21:00:05 +00:00
managerUnlock ( t - > manager ) ;
2008-06-10 01:38:12 +00:00
return ret ;
2007-09-20 16:32:01 +00:00
}
2008-11-06 02:56:51 +00:00
double
2009-01-05 04:27:54 +00:00
tr_peerGetPieceSpeed ( const tr_peer * peer , uint64_t now , tr_direction direction )
2008-11-06 02:56:51 +00:00
{
2009-01-05 04:27:54 +00:00
return peer - > io ? tr_peerIoGetPieceSpeed ( 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 *
2009-01-13 21:00:05 +00:00
tr_peerMgrPeerStats ( const tr_torrent * tor ,
2009-01-01 18:36:58 +00:00
int * setmeCount )
2007-09-20 16:32:01 +00:00
{
2008-12-30 08:20:16 +00:00
int i , size ;
2009-01-13 21:00:05 +00:00
const Torrent * t = tor - > torrentPeers ;
2008-12-30 08:20:16 +00:00
const tr_peer * * peers ;
tr_peer_stat * ret ;
2009-01-05 04:27:54 +00:00
uint64_t now ;
2007-09-20 16:32:01 +00:00
2009-01-13 21:00:05 +00:00
assert ( t - > manager ) ;
managerLock ( t - > manager ) ;
2007-09-29 06:37:03 +00:00
2009-01-04 16:59:15 +00:00
size = tr_ptrArraySize ( & t - > peers ) ;
peers = ( const tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
2007-09-20 16:32:01 +00:00
ret = tr_new0 ( tr_peer_stat , size ) ;
2009-01-05 04:27:54 +00:00
now = tr_date ( ) ;
2007-09-20 16:32:01 +00:00
2009-05-09 06:08:21 +00:00
for ( i = 0 ; i < size ; + + i )
2007-09-20 16:32:01 +00:00
{
2008-09-23 19:11:04 +00:00
char * pch ;
const tr_peer * peer = peers [ i ] ;
2009-05-09 06:08:21 +00:00
const struct peer_atom * atom = peer - > atom ;
2008-09-23 19:11:04 +00:00
tr_peer_stat * stat = ret + i ;
2007-09-20 16:32:01 +00:00
2009-03-27 01:31:17 +00:00
tr_ntop ( & peer - > addr , stat - > addr , sizeof ( stat - > addr ) ) ;
2008-12-15 00:17:08 +00:00
tr_strlcpy ( stat - > client , ( peer - > client ? peer - > client : " " ) ,
sizeof ( stat - > client ) ) ;
2008-11-20 20:39:19 +00:00
stat - > port = ntohs ( peer - > port ) ;
2008-01-09 17:33:43 +00:00
stat - > from = atom - > from ;
stat - > progress = peer - > progress ;
stat - > isEncrypted = tr_peerIoIsEncrypted ( peer - > io ) ? 1 : 0 ;
2009-01-05 04:27:54 +00:00
stat - > rateToPeer = tr_peerGetPieceSpeed ( peer , now , TR_CLIENT_TO_PEER ) ;
stat - > rateToClient = tr_peerGetPieceSpeed ( peer , now , TR_PEER_TO_CLIENT ) ;
2008-01-09 17:33:43 +00:00
stat - > peerIsChoked = peer - > peerIsChoked ;
stat - > peerIsInterested = peer - > peerIsInterested ;
stat - > clientIsChoked = peer - > clientIsChoked ;
stat - > clientIsInterested = peer - > clientIsInterested ;
stat - > isIncoming = tr_peerIoIsIncoming ( peer - > io ) ;
2008-01-16 17:52:47 +00:00
stat - > isDownloadingFrom = clientIsDownloadingFrom ( peer ) ;
stat - > isUploadingTo = clientIsUploadingTo ( peer ) ;
2008-12-02 23:16:01 +00:00
stat - > isSeed = ( atom - > uploadOnly = = UPLOAD_ONLY_YES ) | | ( peer - > progress > = 1.0 ) ;
2008-01-09 17:33:43 +00:00
pch = stat - > flagStr ;
2008-01-11 02:09:20 +00:00
if ( t - > optimistic = = peer ) * pch + + = ' O ' ;
2008-01-10 00:52:02 +00:00
if ( stat - > isDownloadingFrom ) * pch + + = ' D ' ;
2008-01-09 17:33:43 +00:00
else if ( stat - > clientIsInterested ) * pch + + = ' d ' ;
2008-01-10 00:52:02 +00:00
if ( stat - > isUploadingTo ) * pch + + = ' U ' ;
2008-01-09 17:33:43 +00:00
else if ( stat - > peerIsInterested ) * pch + + = ' u ' ;
2008-12-05 22:56:19 +00:00
if ( ! stat - > clientIsChoked & & ! stat - > clientIsInterested ) * pch + + = ' K ' ;
2008-01-09 17:33:43 +00:00
if ( ! stat - > peerIsChoked & & ! stat - > peerIsInterested ) * pch + + = ' ? ' ;
if ( stat - > isEncrypted ) * pch + + = ' E ' ;
2009-05-19 18:38:26 +00:00
if ( stat - > from = = TR_PEER_FROM_DHT ) * pch + + = ' H ' ;
2008-01-09 17:33:43 +00:00
if ( stat - > from = = TR_PEER_FROM_PEX ) * pch + + = ' X ' ;
if ( stat - > isIncoming ) * pch + + = ' I ' ;
* pch = ' \0 ' ;
2007-09-20 16:32:01 +00:00
}
* setmeCount = size ;
2007-09-29 06:37:03 +00:00
2009-01-13 21:00:05 +00:00
managerUnlock ( t - > manager ) ;
2007-09-20 16:32:01 +00:00
return ret ;
}
/**
* * *
* */
2007-10-03 16:42:43 +00:00
struct ChokeData
2007-09-20 16:32:01 +00:00
{
2008-11-28 22:11:41 +00:00
tr_bool doUnchoke ;
tr_bool isInterested ;
tr_bool isChoked ;
2008-11-15 01:07:08 +00:00
int rate ;
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
2008-09-23 19:11:04 +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
2008-11-15 01:07:08 +00:00
if ( a - > rate ! = b - > rate ) /* prefer higher overall speeds */
return a - > rate > b - > rate ? - 1 : 1 ;
2008-11-15 00:46:51 +00:00
2008-11-15 01:07:08 +00:00
if ( a - > isChoked ! = b - > isChoked ) /* prefer unchoked */
return a - > isChoked ? 1 : - 1 ;
2008-06-27 02:42:44 +00:00
2008-11-15 01:07:08 +00:00
return 0 ;
2007-09-20 16:32:01 +00:00
}
2008-01-11 02:09:20 +00:00
static int
isNew ( const tr_peer * peer )
{
return peer & & peer - > io & & tr_peerIoGetAge ( peer - > io ) < 45 ;
}
static int
isSame ( const tr_peer * peer )
{
return peer & & peer - > client & & strstr ( peer - > client , " Transmission " ) ;
}
2007-09-22 00:22:10 +00:00
/**
* * *
* */
2007-09-20 16:32:01 +00:00
static void
2009-02-04 16:58:52 +00:00
rechokeTorrent ( Torrent * t )
2007-09-20 16:32:01 +00:00
{
2008-12-30 08:20:16 +00:00
int i , size , unchokedInterested ;
2009-01-04 16:59:15 +00:00
const int peerCount = tr_ptrArraySize ( & t - > peers ) ;
tr_peer * * peers = ( tr_peer * * ) tr_ptrArrayBase ( & t - > peers ) ;
2007-10-03 16:42:43 +00:00
struct ChokeData * choke = tr_new0 ( struct ChokeData , peerCount ) ;
2009-01-09 15:45:44 +00:00
const tr_session * session = t - > manager - > session ;
2008-12-30 08:20:16 +00:00
const int chokeAll = ! tr_torrentIsPieceTransferAllowed ( t - > tor , TR_CLIENT_TO_PEER ) ;
2009-01-05 04:27:54 +00:00
const uint64_t now = tr_date ( ) ;
2007-09-29 06:37:03 +00:00
assert ( torrentIsLocked ( t ) ) ;
2008-09-23 19:11:04 +00:00
2007-09-20 16:32:01 +00:00
/* sort the peers by preference and rate */
2008-09-23 19:11:04 +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
2008-01-09 17:33:43 +00:00
if ( peer - > progress > = 1.0 ) /* choke all seeds */
2008-12-02 19:46:51 +00:00
{
2008-01-09 17:33:43 +00:00
tr_peerMsgsSetChoke ( peer - > msgs , TRUE ) ;
2008-12-02 19:46:51 +00:00
}
else if ( atom - > uploadOnly = = UPLOAD_ONLY_YES ) /* choke partial seeds */
{
2008-11-07 04:10:27 +00:00
tr_peerMsgsSetChoke ( peer - > msgs , TRUE ) ;
2008-12-02 19:46:51 +00:00
}
else if ( chokeAll ) /* choke everyone if we're not uploading */
{
tr_peerMsgsSetChoke ( peer - > msgs , TRUE ) ;
}
else
{
2008-11-06 02:56:51 +00:00
struct ChokeData * n = & choke [ size + + ] ;
n - > peer = peer ;
n - > isInterested = peer - > peerIsInterested ;
2008-11-15 01:07:08 +00:00
n - > isChoked = peer - > peerIsChoked ;
2009-01-05 04:27:54 +00:00
n - > rate = tr_peerGetPieceSpeed ( peer , now , TR_CLIENT_TO_PEER ) * 1024 ;
2007-11-18 06:15:13 +00:00
}
2007-09-20 16:32:01 +00:00
}
2007-09-22 00:22:10 +00:00
2008-09-23 19:11:04 +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 .
2008-01-09 17:33:43 +00:00
*/
unchokedInterested = 0 ;
2009-01-09 15:45:44 +00:00
for ( i = 0 ; i < size & & unchokedInterested < session - > uploadSlotsPerTorrent ; + + i ) {
2007-09-20 16:32:01 +00:00
choke [ i ] . doUnchoke = 1 ;
2008-01-09 17:33:43 +00:00
if ( choke [ i ] . isInterested )
+ + 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 */
2008-01-11 02:09:20 +00:00
if ( i < size )
{
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
2008-12-05 22:56:19 +00:00
for ( ; i < size ; + + i )
2008-01-11 02:09:20 +00:00
{
2008-06-03 04:29:56 +00:00
if ( choke [ i ] . isInterested )
{
const tr_peer * peer = choke [ i ] . peer ;
2008-12-05 22:56:19 +00:00
int x = 1 , y ;
2008-06-03 04:29:56 +00:00
if ( isNew ( peer ) ) x * = 3 ;
if ( isSame ( peer ) ) x * = 3 ;
2008-12-05 22:56:19 +00:00
for ( y = 0 ; y < x ; + + y )
2008-12-29 08:54:36 +00:00
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
2008-12-29 08:54:36 +00:00
if ( ( n = tr_ptrArraySize ( & randPool ) ) )
2008-06-03 04:29:56 +00:00
{
2008-12-29 08:54:36 +00:00
c = tr_ptrArrayNth ( & randPool , tr_cryptoWeakRandInt ( n ) ) ;
2008-06-03 04:29:56 +00:00
c - > doUnchoke = 1 ;
t - > optimistic = c - > peer ;
}
2008-12-29 08:54:36 +00:00
tr_ptrArrayDestruct ( & randPool , NULL ) ;
2007-09-20 16:32:01 +00:00
}
2008-12-22 00:52:44 +00:00
for ( i = 0 ; i < size ; + + i )
2007-09-20 16:32:01 +00:00
tr_peerMsgsSetChoke ( choke [ i ] . peer - > msgs , ! choke [ i ] . doUnchoke ) ;
/* cleanup */
tr_free ( choke ) ;
}
static int
2009-02-04 16:58:52 +00:00
rechokePulse ( 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 ;
managerLock ( mgr ) ;
2008-09-23 19:11:04 +00:00
2009-02-04 16:58:52 +00:00
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
if ( tor - > isRunning )
rechokeTorrent ( tor - > torrentPeers ) ;
managerUnlock ( mgr ) ;
2007-09-20 16:32:01 +00:00
return TRUE ;
}
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
* * * *
* * */
2009-01-20 15:47:25 +00:00
typedef enum
{
TR_CAN_KEEP ,
TR_CAN_CLOSE ,
TR_MUST_CLOSE ,
}
tr_close_type_t ;
static tr_close_type_t
shouldPeerBeClosed ( const Torrent * t ,
const tr_peer * peer ,
int peerCount )
2007-09-30 23:55:49 +00:00
{
2008-09-23 19:11:04 +00:00
const tr_torrent * tor = t - > tor ;
const time_t now = time ( NULL ) ;
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 */
2008-09-23 19:11:04 +00:00
if ( peer - > doPurge )
{
tordbg ( t , " purging peer %s because its doPurge flag is set " ,
2008-12-05 22:56:19 +00:00
tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2009-01-20 15:47:25 +00:00
return TR_MUST_CLOSE ;
2007-10-13 13:54:05 +00:00
}
2007-09-29 06:37:03 +00:00
2008-05-06 19:06:46 +00:00
/* if we're seeding and the peer has everything we have,
* and enough time has passed for a pex exchange , then disconnect */
2008-09-23 19:11:04 +00:00
if ( tr_torrentIsSeed ( tor ) )
{
2008-05-06 19:06:46 +00:00
int peerHasEverything ;
if ( atom - > flags & ADDED_F_SEED_FLAG )
peerHasEverything = TRUE ;
2009-01-02 17:01:55 +00:00
else if ( peer - > progress < tr_cpPercentDone ( & tor - > completion ) )
2008-05-06 19:39:16 +00:00
peerHasEverything = FALSE ;
2008-12-05 22:56:19 +00:00
else {
2009-01-02 17:01:55 +00:00
tr_bitfield * tmp = tr_bitfieldDup ( tr_cpPieceBitfield ( & tor - > completion ) ) ;
2008-05-06 19:06:46 +00:00
tr_bitfieldDifference ( tmp , peer - > have ) ;
peerHasEverything = tr_bitfieldCountTrueBits ( tmp ) = = 0 ;
tr_bitfieldFree ( tmp ) ;
}
2008-12-22 00:52:44 +00:00
if ( peerHasEverything & & ( ! tr_torrentAllowsPex ( tor ) | | ( now - atom - > time > = 30 ) ) )
{
2008-09-23 19:11:04 +00:00
tordbg ( t , " purging peer %s because we're both seeds " ,
2008-12-22 00:52:44 +00:00
tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2009-01-20 15:47:25 +00:00
return TR_MUST_CLOSE ;
2007-10-11 03:12:48 +00:00
}
2007-10-13 13:54:05 +00:00
}
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
{
2008-12-05 22:56:19 +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 ;
2008-12-11 07:04: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 );*/
2008-12-05 22:56:19 +00:00
if ( idleTime > limit ) {
tordbg ( t , " purging peer %s because it's been %d secs since we shared anything " ,
tr_peerIoAddrStr ( & atom - > addr , atom - > port ) , idleTime ) ;
2009-01-20 15:47:25 +00:00
return TR_CAN_CLOSE ;
2007-10-13 13:54:05 +00:00
}
2007-09-22 14:18:52 +00:00
}
2009-01-20 15:47:25 +00:00
return TR_CAN_KEEP ;
2007-10-13 13:54:05 +00:00
}
static tr_peer * *
2009-01-20 15:47:25 +00:00
getPeersToClose ( Torrent * t , tr_close_type_t closeType , int * setmeSize )
2007-10-13 13:54:05 +00:00
{
2008-12-05 22:56:19 +00:00
int i , peerCount , outsize ;
2008-12-29 08:54:36 +00:00
tr_peer * * peers = ( tr_peer * * ) tr_ptrArrayPeek ( & t - > peers , & peerCount ) ;
2008-09-23 19:11:04 +00:00
struct tr_peer * * ret = tr_new ( tr_peer * , peerCount ) ;
2007-10-13 13:54:05 +00:00
assert ( torrentIsLocked ( t ) ) ;
2008-09-23 19:11:04 +00:00
for ( i = outsize = 0 ; i < peerCount ; + + i )
2009-01-20 15:47:25 +00:00
if ( shouldPeerBeClosed ( t , peers [ i ] , peerCount ) = = closeType )
2007-10-13 13:54:05 +00:00
ret [ outsize + + ] = peers [ i ] ;
2007-09-30 23:55:49 +00:00
* setmeSize = outsize ;
return ret ;
2007-09-22 14:18:52 +00:00
}
static int
2008-09-23 19:11:04 +00:00
compareCandidates ( const void * va ,
const void * vb )
2007-09-22 14:18:52 +00:00
{
2008-09-23 19:11:04 +00:00
const struct peer_atom * a = * ( const struct peer_atom * * ) va ;
const struct peer_atom * b = * ( const struct peer_atom * * ) vb ;
2007-11-08 04:11:09 +00:00
2008-08-22 02:34:22 +00:00
/* <Charles> Here we would probably want to try reconnecting to
* peers that had most recently given us data . Lots of users have
* trouble with resets due to their routers and / or ISPs . This way we
* can quickly recover from an unwanted reset . So we sort
* piece_data_time in descending order .
*/
2008-08-22 02:15:37 +00:00
if ( a - > piece_data_time ! = b - > piece_data_time )
2008-08-22 02:34:22 +00:00
return a - > piece_data_time < b - > piece_data_time ? 1 : - 1 ;
2008-01-09 17:33:43 +00:00
2008-08-22 01:27:00 +00:00
if ( a - > numFails ! = b - > numFails )
return a - > numFails < b - > numFails ? - 1 : 1 ;
2007-11-08 04:11:09 +00:00
if ( a - > time ! = b - > time )
return a - > time < b - > time ? - 1 : 1 ;
2009-05-19 18:38:26 +00:00
/* In order to avoid fragmenting the swarm, peers from trackers and
* from the DHT should be preferred to peers from PEX . */
2008-12-03 01:22:24 +00:00
if ( a - > from ! = b - > from )
return a - > from < b - > from ? - 1 : 1 ;
2007-09-30 23:55:49 +00:00
return 0 ;
2007-09-22 14:18:52 +00:00
}
2008-08-16 05:12:55 +00:00
static int
getReconnectIntervalSecs ( const struct peer_atom * atom )
{
2008-09-23 19:11:04 +00:00
int sec ;
2008-09-05 05:14:49 +00:00
const time_t now = time ( NULL ) ;
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 . */
2008-12-05 22:56:19 +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 */
else if ( ( now - atom - > time ) < MINIMUM_RECONNECT_INTERVAL_SECS )
sec = MINIMUM_RECONNECT_INTERVAL_SECS ;
/* otherwise, the interval depends on how many times we've tried
* and failed to connect to the peer */
2008-12-05 22:56:19 +00:00
else switch ( atom - > numFails ) {
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
2008-08-16 06:07:11 +00:00
return sec ;
2008-08-16 05:12:55 +00:00
}
2007-09-30 23:55:49 +00:00
static struct peer_atom * *
2008-12-05 22:56:19 +00:00
getPeerCandidates ( Torrent * t , int * setmeSize )
2007-09-22 00:22:10 +00:00
{
2008-09-23 19:11:04 +00:00
int i , atomCount , retCount ;
2007-09-30 23:55:49 +00:00
struct peer_atom * * atoms ;
struct peer_atom * * ret ;
2008-09-23 19:11:04 +00:00
const time_t now = time ( NULL ) ;
const int seed = tr_torrentIsSeed ( t - > tor ) ;
2007-09-22 14:18:52 +00:00
2007-09-30 23:55:49 +00:00
assert ( torrentIsLocked ( t ) ) ;
2007-09-22 14:18:52 +00:00
2008-12-29 08:54:36 +00:00
atoms = ( struct peer_atom * * ) tr_ptrArrayPeek ( & t - > pool , & atomCount ) ;
2007-10-15 16:01:42 +00:00
ret = tr_new ( struct peer_atom * , atomCount ) ;
2008-09-23 19:11:04 +00:00
for ( i = retCount = 0 ; i < atomCount ; + + i )
2007-09-26 04:44:54 +00:00
{
2008-09-23 19:11:04 +00:00
int interval ;
2007-09-30 23:55:49 +00:00
struct peer_atom * atom = atoms [ i ] ;
2007-09-26 04:44:54 +00:00
2007-10-08 01:31:27 +00:00
/* peer fed us too much bad data ... we only keep it around
* now to weed it out in case someone sends it to us via pex */
2007-12-15 04:26:31 +00:00
if ( atom - > myflags & MYFLAG_BANNED )
continue ;
/* peer was unconnectable before, so we're not going to keep trying.
* this is needs a separate flag from ` banned ' , since if they try
* to connect to us later , we ' ll let them in */
if ( atom - > myflags & MYFLAG_UNREACHABLE )
2007-10-08 01:31:27 +00:00
continue ;
2007-09-30 23:55:49 +00:00
/* we don't need two connections to the same peer... */
2007-12-15 04:26:31 +00:00
if ( peerIsInUse ( t , & atom - > addr ) )
2007-09-26 04:44:54 +00:00
continue ;
2007-09-30 23:55:49 +00:00
/* no need to connect if we're both seeds... */
2008-12-02 19:46:51 +00:00
if ( seed & & ( ( atom - > flags & ADDED_F_SEED_FLAG ) | |
( atom - > uploadOnly = = UPLOAD_ONLY_YES ) ) )
2007-09-30 23:55:49 +00:00
continue ;
2007-09-26 04:44:54 +00:00
2008-09-05 05:14:49 +00:00
/* don't reconnect too often */
interval = getReconnectIntervalSecs ( atom ) ;
2008-09-23 19:11:04 +00:00
if ( ( now - atom - > time ) < interval )
{
2008-12-05 22:56:19 +00:00
tordbg ( t , " RECONNECT peer %d (%s) is in its grace period of %d seconds.. " ,
i , tr_peerIoAddrStr ( & atom - > addr , atom - > port ) , interval ) ;
2008-09-05 05:14:49 +00:00
continue ;
2007-09-30 23:55:49 +00:00
}
2008-03-29 21:05:51 +00:00
/* Don't connect to peers in our blocklist */
2008-09-17 19:44:24 +00:00
if ( tr_sessionIsAddressBlocked ( t - > manager - > session , & atom - > addr ) )
2008-03-29 21:05:51 +00:00
continue ;
2007-10-15 16:01:42 +00:00
ret [ retCount + + ] = atom ;
2007-09-22 14:18:52 +00:00
}
2007-09-25 22:30:41 +00:00
2008-09-23 19:11:04 +00:00
qsort ( ret , retCount , sizeof ( struct peer_atom * ) , compareCandidates ) ;
2007-10-15 16:01:42 +00:00
* setmeSize = retCount ;
2007-09-30 23:55:49 +00:00
return ret ;
}
2007-09-22 14:18:52 +00:00
2009-01-20 15:47:25 +00:00
static void
closePeer ( Torrent * t , tr_peer * peer )
{
struct peer_atom * atom ;
assert ( t ! = NULL ) ;
assert ( peer ! = NULL ) ;
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,
so reset their ` numFails ' weight to zero . otherwise we connected
to them fruitlessly , so mark it as another fail */
if ( atom - > piece_data_time )
atom - > numFails = 0 ;
else
+ + atom - > numFails ;
tordbg ( t , " removing bad peer %s " , tr_peerIoGetAddrStr ( peer - > io ) ) ;
removePeer ( t , peer ) ;
}
2009-02-04 16:58:52 +00:00
static void
reconnectTorrent ( Torrent * t )
2007-09-30 23:55:49 +00:00
{
2008-01-11 18:13:09 +00:00
static time_t prevTime = 0 ;
2008-09-23 19:11:04 +00:00
static int newConnectionsThisSecond = 0 ;
time_t now ;
2007-09-22 14:18:52 +00:00
2008-01-11 18:13:09 +00:00
now = time ( NULL ) ;
if ( prevTime ! = now )
{
prevTime = now ;
newConnectionsThisSecond = 0 ;
}
2007-10-01 16:50:51 +00:00
if ( ! t - > isRunning )
{
removeAllPeers ( t ) ;
2007-09-22 14:18:52 +00:00
}
2007-10-01 16:50:51 +00:00
else
{
2009-01-20 15:47:25 +00:00
int i ;
int canCloseCount ;
int mustCloseCount ;
int candidateCount ;
2009-01-20 03:32:54 +00:00
int maxCandidates ;
2009-01-20 15:47:25 +00:00
struct tr_peer * * canClose = getPeersToClose ( t , TR_CAN_CLOSE , & canCloseCount ) ;
struct tr_peer * * mustClose = getPeersToClose ( t , TR_MUST_CLOSE , & mustCloseCount ) ;
struct peer_atom * * candidates = getPeerCandidates ( t , & candidateCount ) ;
tordbg ( t , " reconnect pulse for [%s]: "
" %d must-close connections, "
" %d can-close connections, "
" %d connection candidates, "
" %d atoms, "
" max per pulse is %d " ,
t - > tor - > info . name ,
mustCloseCount ,
canCloseCount ,
candidateCount ,
tr_ptrArraySize ( & t - > pool ) ,
MAX_RECONNECTIONS_PER_PULSE ) ;
/* disconnect the really bad peers */
for ( i = 0 ; i < mustCloseCount ; + + i )
closePeer ( t , mustClose [ i ] ) ;
/* decide how many peers can we try to add in this pass */
maxCandidates = candidateCount ;
2009-01-20 05:45:03 +00:00
maxCandidates = MIN ( maxCandidates , MAX_RECONNECTIONS_PER_PULSE ) ;
maxCandidates = MIN ( maxCandidates , getMaxPeerCount ( t - > tor ) - getPeerCount ( t ) ) ;
maxCandidates = MIN ( maxCandidates , MAX_CONNECTIONS_PER_SECOND - newConnectionsThisSecond ) ;
2007-10-01 16:50:51 +00:00
2009-01-20 15:47:25 +00:00
/* maybe disconnect some lesser peers, if we have candidates to replace them with */
for ( i = 0 ; ( i < canCloseCount ) & & ( i < maxCandidates ) ; + + i )
closePeer ( t , canClose [ i ] ) ;
2007-10-01 16:50:51 +00:00
2009-01-20 15:47:25 +00:00
tordbg ( t , " candidateCount is %d, MAX_RECONNECTIONS_PER_PULSE is %d, "
" getPeerCount(t) is %d, getMaxPeerCount(t) is %d, "
" newConnectionsThisSecond is %d, MAX_CONNECTIONS_PER_SECOND is %d " ,
candidateCount ,
MAX_RECONNECTIONS_PER_PULSE ,
getPeerCount ( t ) ,
getMaxPeerCount ( t - > tor ) ,
newConnectionsThisSecond , MAX_CONNECTIONS_PER_SECOND ) ;
2009-01-03 07:23:26 +00:00
2007-10-01 16:50:51 +00:00
/* add some new ones */
2009-01-20 15:47:25 +00:00
for ( i = 0 ; i < maxCandidates ; + + i )
2007-10-02 16:12:44 +00:00
{
2009-01-20 15:47:25 +00:00
tr_peerMgr * mgr = t - > manager ;
struct peer_atom * atom = candidates [ i ] ;
tr_peerIo * io ;
2007-10-15 16:01:42 +00:00
tordbg ( t , " Starting an OUTGOING connection with %s " ,
2008-09-23 19:11:04 +00:00
tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2007-10-15 16:01:42 +00:00
2009-01-02 19:56:06 +00:00
io = tr_peerIoNewOutgoing ( mgr - > session , mgr - > session - > bandwidth , & atom - > addr , atom - > port , t - > hash ) ;
2007-12-15 04:26:31 +00:00
if ( io = = NULL )
{
2009-01-02 21:50:51 +00:00
tordbg ( t , " peerIo not created; marking peer %s as unreachable " ,
tr_peerIoAddrStr ( & atom - > addr , atom - > port ) ) ;
2008-08-08 22:44:32 +00:00
atom - > myflags | = MYFLAG_UNREACHABLE ;
2007-12-15 04:26:31 +00:00
}
else
{
2008-12-05 22:56:19 +00:00
tr_handshake * handshake = tr_handshakeNew ( io ,
mgr - > session - > encryptionMode ,
myHandshakeDoneCB ,
mgr ) ;
2007-10-02 16:12:44 +00:00
2008-08-01 16:43:22 +00:00
assert ( tr_peerIoGetTorrentHash ( io ) ) ;
2007-10-02 16:12:44 +00:00
2009-01-05 06:45:08 +00:00
tr_peerIoUnref ( io ) ; /* balanced by the implicit ref in tr_peerIoNewOutgoing() */
2008-01-11 18:13:09 +00:00
+ + newConnectionsThisSecond ;
2008-12-29 08:54:36 +00:00
tr_ptrArrayInsertSorted ( & t - > outgoingHandshakes , handshake ,
2008-09-23 19:11:04 +00:00
handshakeCompare ) ;
2007-12-15 04:26:31 +00:00
}
2007-10-02 16:12:44 +00:00
2007-10-01 16:50:51 +00:00
atom - > time = time ( NULL ) ;
}
2007-09-22 14:18:52 +00:00
2007-10-01 16:50:51 +00:00
/* cleanup */
tr_free ( candidates ) ;
2009-01-20 15:47:25 +00:00
tr_free ( mustClose ) ;
tr_free ( canClose ) ;
2007-09-30 23:55:49 +00:00
}
2009-02-04 16:58:52 +00:00
}
2007-09-30 23:55:49 +00:00
2009-02-04 16:58:52 +00:00
static int
reconnectPulse ( void * vmgr )
{
tr_torrent * tor = NULL ;
tr_peerMgr * mgr = vmgr ;
managerLock ( mgr ) ;
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) )
if ( tor - > isRunning )
reconnectTorrent ( tor - > torrentPeers ) ;
managerUnlock ( mgr ) ;
2007-09-22 00:22:10 +00:00
return TRUE ;
}
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
pumpAllPeers ( tr_peerMgr * mgr )
{
2009-01-13 21:00:05 +00:00
tr_torrent * tor = NULL ;
2008-11-24 04:21:23 +00:00
2009-01-13 21:00:05 +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 ;
2008-12-29 08:54:36 +00:00
for ( j = 0 ; j < tr_ptrArraySize ( & t - > peers ) ; + + j )
2008-11-24 04:21:23 +00:00
{
2008-12-29 08:54:36 +00:00
tr_peer * peer = tr_ptrArrayNth ( & t - > peers , j ) ;
2008-11-24 04:21:23 +00:00
tr_peerMsgsPulse ( peer - > msgs ) ;
}
}
}
2008-09-17 19:44:24 +00:00
static int
bandwidthPulse ( void * vmgr )
{
2009-04-09 14:10:31 +00:00
tr_torrent * tor = NULL ;
2008-09-17 19:44:24 +00:00
tr_peerMgr * mgr = vmgr ;
managerLock ( mgr ) ;
2008-12-20 22:19:34 +00:00
/* FIXME: this next line probably isn't necessary... */
2008-11-25 21:35:17 +00:00
pumpAllPeers ( mgr ) ;
2008-12-20 22:19:34 +00:00
/* allocate bandwidth to the peers */
2008-11-25 21:35:17 +00:00
tr_bandwidthAllocate ( mgr - > session - > bandwidth , TR_UP , BANDWIDTH_PERIOD_MSEC ) ;
tr_bandwidthAllocate ( mgr - > session - > bandwidth , TR_DOWN , BANDWIDTH_PERIOD_MSEC ) ;
2008-12-20 22:19:34 +00:00
2009-04-09 14:10:31 +00:00
/* possibly stop torrents that have seeded enough */
while ( ( tor = tr_torrentNext ( mgr - > session , tor ) ) ) {
if ( tor - > needsSeedRatioCheck ) {
tor - > needsSeedRatioCheck = FALSE ;
tr_torrentCheckSeedRatio ( tor ) ;
}
}
2008-09-17 19:44:24 +00:00
managerUnlock ( mgr ) ;
return TRUE ;
}