2 * This file Copyright (C) Mnemosyne LLC
4 * This file is licensed by the GPL version 2. Works owned by the
5 * Transmission project are granted a special exemption to clause 2(b)
6 * so that the bulk of its code can remain under the MIT license.
7 * This exemption does not extend to derived works not owned by
8 * the Transmission project.
10 * $Id: peer-mgr.c 12539 2011-07-10 15:24:51Z jordan $
14 #include <errno.h> /* error codes ERANGE, ... */
15 #include <limits.h> /* INT_MAX */
16 #include <string.h> /* memcpy, memcmp, strstr */
17 #include <stdlib.h> /* qsort */
19 #include <event2/event.h>
20 #include <libutp/utp.h>
22 #include "transmission.h"
23 #include "announcer.h"
24 #include "bandwidth.h"
25 #include "blocklist.h"
28 #include "completion.h"
30 #include "handshake.h"
34 #include "peer-msgs.h"
37 #include "stats.h" /* tr_statsAddUploaded, tr_statsAddDownloaded */
44 /* how frequently to cull old atoms */
45 ATOM_PERIOD_MSEC
= ( 60 * 1000 ),
47 /* how frequently to change which peers are choked */
48 RECHOKE_PERIOD_MSEC
= ( 10 * 1000 ),
50 /* an optimistically unchoked peer is immune from rechoking
51 for this many calls to rechokeUploads(). */
52 OPTIMISTIC_UNCHOKE_MULTIPLIER
= 4,
54 /* how frequently to reallocate bandwidth */
55 BANDWIDTH_PERIOD_MSEC
= 500,
57 /* how frequently to age out old piece request lists */
58 REFILL_UPKEEP_PERIOD_MSEC
= ( 10 * 1000 ),
60 /* how frequently to decide which peers live and die */
61 RECONNECT_PERIOD_MSEC
= 500,
63 /* when many peers are available, keep idle ones this long */
64 MIN_UPLOAD_IDLE_SECS
= ( 60 ),
66 /* when few peers are available, keep idle ones this long */
67 MAX_UPLOAD_IDLE_SECS
= ( 60 * 5 ),
69 /* max number of peers to ask for per second overall.
70 * this throttle is to avoid overloading the router */
71 MAX_CONNECTIONS_PER_SECOND
= 12,
73 MAX_CONNECTIONS_PER_PULSE
= (int)(MAX_CONNECTIONS_PER_SECOND
* (RECONNECT_PERIOD_MSEC
/1000.0)),
75 /* number of bad pieces a peer is allowed to send before we ban them */
76 MAX_BAD_PIECES_PER_PEER
= 5,
78 /* amount of time to keep a list of request pieces lying around
79 before it's considered too old and needs to be rebuilt */
80 PIECE_LIST_SHELF_LIFE_SECS
= 60,
82 /* use for bitwise operations w/peer_atom.flags2 */
85 /* use for bitwise operations w/peer_atom.flags2 */
86 /* unreachable for now... but not banned.
87 * if they try to connect to us it's okay */
88 MYFLAG_UNREACHABLE
= 2,
90 /* the minimum we'll wait before attempting to reconnect to a peer */
91 MINIMUM_RECONNECT_INTERVAL_SECS
= 5,
93 /** how long we'll let requests we've made linger before we cancel them */
94 REQUEST_TTL_SECS
= 120,
96 NO_BLOCKS_CANCEL_HISTORY
= 120,
98 CANCEL_HISTORY_SEC
= 60
101 const tr_peer_event TR_PEER_EVENT_INIT
= { 0, 0, NULL
, 0, 0, 0, false, 0 };
108 * Peer information that should be kept even before we've connected and
109 * after we've disconnected. These are kept in a pool of peer_atoms to decide
110 * which ones would make good candidates for connecting to, and to watch out
118 uint8_t fromFirst
; /* where the peer was first found */
119 uint8_t fromBest
; /* the "best" value of where the peer has been found */
120 uint8_t flags
; /* these match the added_f flags */
121 uint8_t flags2
; /* flags that aren't defined in added_f */
122 int8_t seedProbability
; /* how likely is this to be a seed... [0..100] or -1 for unknown */
123 int8_t blocklisted
; /* -1 for unknown, true for blocklisted, false for not blocklisted */
126 bool utp_failed
; /* We recently failed to connect over uTP */
128 time_t time
; /* when the peer's connection status last changed */
129 time_t piece_data_time
;
131 time_t lastConnectionAttemptAt
;
132 time_t lastConnectionAt
;
134 /* similar to a TTL field, but less rigid --
135 * if the swarm is small, the atom will be kept past this date. */
137 tr_peer
* peer
; /* will be NULL if not connected */
142 #define tr_isAtom(a) (TRUE)
145 tr_isAtom( const struct peer_atom
* atom
)
147 return ( atom
!= NULL
)
148 && ( atom
->fromFirst
< TR_PEER_FROM__MAX
)
149 && ( atom
->fromBest
< TR_PEER_FROM__MAX
)
150 && ( tr_address_is_valid( &atom
->addr
) );
155 tr_atomAddrStr( const struct peer_atom
* atom
)
157 return atom
? tr_peerIoAddrStr( &atom
->addr
, atom
->port
) : "[no atom]";
162 tr_block_index_t block
;
167 struct weighted_piece
169 tr_piece_index_t index
;
171 int16_t requestCount
;
174 enum piece_sort_state
177 PIECES_SORTED_BY_INDEX
,
178 PIECES_SORTED_BY_WEIGHT
181 /** @brief Opaque, per-torrent data structure for peer connection information */
182 typedef struct tr_torrent_peers
184 tr_ptrArray outgoingHandshakes
; /* tr_handshake */
185 tr_ptrArray pool
; /* struct peer_atom */
186 tr_ptrArray peers
; /* tr_peer */
187 tr_ptrArray webseeds
; /* tr_webseed */
190 struct tr_peerMgr
* manager
;
192 tr_peer
* optimistic
; /* the optimistic peer, or NULL if none */
193 int optimisticUnchokeTimeScaler
;
196 bool needsCompletenessCheck
;
198 struct block_request
* requests
;
202 struct weighted_piece
* pieces
;
204 enum piece_sort_state pieceSortState
;
206 /* An array of pieceCount items stating how many peers have each piece.
207 This is used to help us for downloading pieces "rarest first."
208 This may be NULL if we don't have metainfo yet, or if we're not
209 downloading and don't care about rarity */
210 uint16_t * pieceReplication
;
211 size_t pieceReplicationSize
;
217 /* Before the endgame this should be 0. In endgame, is contains the average
218 * number of pending requests per peer. Only peers which have more pending
219 * requests are considered 'fast' are allowed to request a block that's
220 * already been requested from another (slower?) peer. */
227 tr_session
* session
;
228 tr_ptrArray incomingHandshakes
; /* tr_handshake */
229 struct event
* bandwidthTimer
;
230 struct event
* rechokeTimer
;
231 struct event
* refillUpkeepTimer
;
232 struct event
* atomTimer
;
235 #define tordbg( t, ... ) \
237 if( tr_deepLoggingIsActive( ) ) \
238 tr_deepLog( __FILE__, __LINE__, tr_torrentName( t->tor ), __VA_ARGS__ ); \
241 #define dbgmsg( ... ) \
243 if( tr_deepLoggingIsActive( ) ) \
244 tr_deepLog( __FILE__, __LINE__, NULL, __VA_ARGS__ ); \
252 managerLock( const struct tr_peerMgr
* manager
)
254 tr_sessionLock( manager
->session
);
258 managerUnlock( const struct tr_peerMgr
* manager
)
260 tr_sessionUnlock( manager
->session
);
264 torrentLock( Torrent
* torrent
)
266 managerLock( torrent
->manager
);
270 torrentUnlock( Torrent
* torrent
)
272 managerUnlock( torrent
->manager
);
276 torrentIsLocked( const Torrent
* t
)
278 return tr_sessionIsLocked( t
->manager
->session
);
286 handshakeCompareToAddr( const void * va
, const void * vb
)
288 const tr_handshake
* a
= va
;
290 return tr_address_compare( tr_handshakeGetAddr( a
, NULL
), vb
);
294 handshakeCompare( const void * a
, const void * b
)
296 return handshakeCompareToAddr( a
, tr_handshakeGetAddr( b
, NULL
) );
299 static inline tr_handshake
*
300 getExistingHandshake( tr_ptrArray
* handshakes
, const tr_address
* addr
)
302 if( tr_ptrArrayEmpty( handshakes
) )
305 return tr_ptrArrayFindSorted( handshakes
, addr
, handshakeCompareToAddr
);
309 comparePeerAtomToAddress( const void * va
, const void * vb
)
311 const struct peer_atom
* a
= va
;
313 return tr_address_compare( &a
->addr
, vb
);
317 compareAtomsByAddress( const void * va
, const void * vb
)
319 const struct peer_atom
* b
= vb
;
321 assert( tr_isAtom( b
) );
323 return comparePeerAtomToAddress( va
, &b
->addr
);
331 tr_peerAddress( const tr_peer
* peer
)
333 return &peer
->atom
->addr
;
337 getExistingTorrent( tr_peerMgr
* manager
,
338 const uint8_t * hash
)
340 tr_torrent
* tor
= tr_torrentFindFromHash( manager
->session
, hash
);
342 return tor
== NULL
? NULL
: tor
->torrentPeers
;
346 peerCompare( const void * a
, const void * b
)
348 return tr_address_compare( tr_peerAddress( a
), tr_peerAddress( b
) );
351 static struct peer_atom
*
352 getExistingAtom( const Torrent
* t
,
353 const tr_address
* addr
)
355 Torrent
* tt
= (Torrent
*)t
;
356 assert( torrentIsLocked( t
) );
357 return tr_ptrArrayFindSorted( &tt
->pool
, addr
, comparePeerAtomToAddress
);
361 peerIsInUse( const Torrent
* ct
, const struct peer_atom
* atom
)
363 Torrent
* t
= (Torrent
*) ct
;
365 assert( torrentIsLocked ( t
) );
367 return ( atom
->peer
!= NULL
)
368 || getExistingHandshake( &t
->outgoingHandshakes
, &atom
->addr
)
369 || getExistingHandshake( &t
->manager
->incomingHandshakes
, &atom
->addr
);
373 tr_peerConstruct( tr_peer
* peer
)
375 memset( peer
, 0, sizeof( tr_peer
) );
377 peer
->have
= TR_BITFIELD_INIT
;
381 peerNew( struct peer_atom
* atom
)
383 tr_peer
* peer
= tr_new( tr_peer
, 1 );
384 tr_peerConstruct( peer
);
393 getPeer( Torrent
* torrent
, struct peer_atom
* atom
)
397 assert( torrentIsLocked( torrent
) );
403 peer
= peerNew( atom
);
404 tr_bitfieldConstruct( &peer
->have
, torrent
->tor
->blockCount
);
405 tr_bitfieldConstruct( &peer
->blame
, torrent
->tor
->blockCount
);
406 tr_ptrArrayInsertSorted( &torrent
->peers
, peer
, peerCompare
);
412 static void peerDeclinedAllRequests( Torrent
*, const tr_peer
* );
415 tr_peerDestruct( tr_torrent
* tor
, tr_peer
* peer
)
417 assert( peer
!= NULL
);
419 peerDeclinedAllRequests( tor
->torrentPeers
, peer
);
421 if( peer
->msgs
!= NULL
)
422 tr_peerMsgsFree( peer
->msgs
);
425 tr_peerIoClear( peer
->io
);
426 tr_peerIoUnref( peer
->io
); /* balanced by the ref in handshakeDoneCB() */
429 tr_bitfieldDestruct( &peer
->have
);
430 tr_bitfieldDestruct( &peer
->blame
);
431 tr_free( peer
->client
);
434 peer
->atom
->peer
= NULL
;
438 peerDelete( Torrent
* t
, tr_peer
* peer
)
440 tr_peerDestruct( t
->tor
, peer
);
445 replicationExists( const Torrent
* t
)
447 return t
->pieceReplication
!= NULL
;
451 replicationFree( Torrent
* t
)
453 tr_free( t
->pieceReplication
);
454 t
->pieceReplication
= NULL
;
455 t
->pieceReplicationSize
= 0;
459 replicationNew( Torrent
* t
)
461 tr_piece_index_t piece_i
;
462 const tr_piece_index_t piece_count
= t
->tor
->info
.pieceCount
;
463 tr_peer
** peers
= (tr_peer
**) tr_ptrArrayBase( &t
->peers
);
464 const int peer_count
= tr_ptrArraySize( &t
->peers
);
466 assert( !replicationExists( t
) );
468 t
->pieceReplicationSize
= piece_count
;
469 t
->pieceReplication
= tr_new0( uint16_t, piece_count
);
471 for( piece_i
=0; piece_i
<piece_count
; ++piece_i
)
476 for( peer_i
=0; peer_i
<peer_count
; ++peer_i
)
477 if( tr_bitfieldHas( &peers
[peer_i
]->have
, piece_i
) )
480 t
->pieceReplication
[piece_i
] = r
;
485 torrentFree( void * vt
)
490 assert( !t
->isRunning
);
491 assert( torrentIsLocked( t
) );
492 assert( tr_ptrArrayEmpty( &t
->outgoingHandshakes
) );
493 assert( tr_ptrArrayEmpty( &t
->peers
) );
495 tr_ptrArrayDestruct( &t
->webseeds
, (PtrArrayForeachFunc
)tr_webseedFree
);
496 tr_ptrArrayDestruct( &t
->pool
, (PtrArrayForeachFunc
)tr_free
);
497 tr_ptrArrayDestruct( &t
->outgoingHandshakes
, NULL
);
498 tr_ptrArrayDestruct( &t
->peers
, NULL
);
500 replicationFree( t
);
502 tr_free( t
->requests
);
503 tr_free( t
->pieces
);
507 static void peerCallbackFunc( tr_peer
*, const tr_peer_event
*, void * );
510 torrentNew( tr_peerMgr
* manager
, tr_torrent
* tor
)
515 t
= tr_new0( Torrent
, 1 );
516 t
->manager
= manager
;
518 t
->pool
= TR_PTR_ARRAY_INIT
;
519 t
->peers
= TR_PTR_ARRAY_INIT
;
520 t
->webseeds
= TR_PTR_ARRAY_INIT
;
521 t
->outgoingHandshakes
= TR_PTR_ARRAY_INIT
;
523 for( i
= 0; i
< tor
->info
.webseedCount
; ++i
)
526 tr_webseedNew( tor
, tor
->info
.webseeds
[i
], peerCallbackFunc
, t
);
527 tr_ptrArrayAppend( &t
->webseeds
, w
);
534 tr_peerMgrNew( tr_session
* session
)
536 tr_peerMgr
* m
= tr_new0( tr_peerMgr
, 1 );
537 m
->session
= session
;
538 m
->incomingHandshakes
= TR_PTR_ARRAY_INIT
;
543 deleteTimer( struct event
** t
)
553 deleteTimers( struct tr_peerMgr
* m
)
555 deleteTimer( &m
->atomTimer
);
556 deleteTimer( &m
->bandwidthTimer
);
557 deleteTimer( &m
->rechokeTimer
);
558 deleteTimer( &m
->refillUpkeepTimer
);
562 tr_peerMgrFree( tr_peerMgr
* manager
)
564 managerLock( manager
);
566 deleteTimers( manager
);
568 /* free the handshakes. Abort invokes handshakeDoneCB(), which removes
569 * the item from manager->handshakes, so this is a little roundabout... */
570 while( !tr_ptrArrayEmpty( &manager
->incomingHandshakes
) )
571 tr_handshakeAbort( tr_ptrArrayNth( &manager
->incomingHandshakes
, 0 ) );
573 tr_ptrArrayDestruct( &manager
->incomingHandshakes
, NULL
);
575 managerUnlock( manager
);
580 clientIsDownloadingFrom( const tr_torrent
* tor
, const tr_peer
* peer
)
582 if( !tr_torrentHasMetadata( tor
) )
585 return peer
->clientIsInterested
&& !peer
->clientIsChoked
;
589 clientIsUploadingTo( const tr_peer
* peer
)
591 return peer
->peerIsInterested
&& !peer
->peerIsChoked
;
599 tr_peerMgrOnBlocklistChanged( tr_peerMgr
* mgr
)
601 tr_torrent
* tor
= NULL
;
602 tr_session
* session
= mgr
->session
;
604 /* we cache whether or not a peer is blocklisted...
605 since the blocklist has changed, erase that cached value */
606 while(( tor
= tr_torrentNext( session
, tor
)))
609 Torrent
* t
= tor
->torrentPeers
;
610 const int n
= tr_ptrArraySize( &t
->pool
);
611 for( i
=0; i
<n
; ++i
) {
612 struct peer_atom
* atom
= tr_ptrArrayNth( &t
->pool
, i
);
613 atom
->blocklisted
= -1;
619 isAtomBlocklisted( tr_session
* session
, struct peer_atom
* atom
)
621 if( atom
->blocklisted
< 0 )
622 atom
->blocklisted
= tr_sessionIsAddressBlocked( session
, &atom
->addr
);
624 assert( tr_isBool( atom
->blocklisted
) );
625 return atom
->blocklisted
;
634 atomSetSeedProbability( struct peer_atom
* atom
, int seedProbability
)
636 assert( atom
!= NULL
);
637 assert( -1<=seedProbability
&& seedProbability
<=100 );
639 atom
->seedProbability
= seedProbability
;
641 if( seedProbability
== 100 )
642 atom
->flags
|= ADDED_F_SEED_FLAG
;
643 else if( seedProbability
!= -1 )
644 atom
->flags
&= ~ADDED_F_SEED_FLAG
;
648 atomIsSeed( const struct peer_atom
* atom
)
650 return atom
->seedProbability
== 100;
654 atomSetSeed( const Torrent
* t
, struct peer_atom
* atom
)
656 if( !atomIsSeed( atom
) )
658 tordbg( t
, "marking peer %s as a seed", tr_atomAddrStr( atom
) );
660 atomSetSeedProbability( atom
, 100 );
666 tr_peerMgrPeerIsSeed( const tr_torrent
* tor
,
667 const tr_address
* addr
)
670 const Torrent
* t
= tor
->torrentPeers
;
671 const struct peer_atom
* atom
= getExistingAtom( t
, addr
);
674 isSeed
= atomIsSeed( atom
);
680 tr_peerMgrSetUtpSupported( tr_torrent
* tor
, const tr_address
* addr
)
682 struct peer_atom
* atom
= getExistingAtom( tor
->torrentPeers
, addr
);
685 atom
->flags
|= ADDED_F_UTP_FLAGS
;
689 tr_peerMgrSetUtpFailed( tr_torrent
*tor
, const tr_address
*addr
, bool failed
)
691 struct peer_atom
* atom
= getExistingAtom( tor
->torrentPeers
, addr
);
694 atom
->utp_failed
= failed
;
701 *** There are two data structures associated with managing block requests:
703 *** 1. Torrent::requests, an array of "struct block_request" which keeps
704 *** track of which blocks have been requested, and when, and by which peers.
705 *** This is list is used for (a) cancelling requests that have been pending
706 *** for too long and (b) avoiding duplicate requests before endgame.
708 *** 2. Torrent::pieces, an array of "struct weighted_piece" which lists the
709 *** pieces that we want to request. It's used to decide which blocks to
710 *** return next when tr_peerMgrGetBlockRequests() is called.
714 *** struct block_request
718 compareReqByBlock( const void * va
, const void * vb
)
720 const struct block_request
* a
= va
;
721 const struct block_request
* b
= vb
;
723 /* primary key: block */
724 if( a
->block
< b
->block
) return -1;
725 if( a
->block
> b
->block
) return 1;
727 /* secondary key: peer */
728 if( a
->peer
< b
->peer
) return -1;
729 if( a
->peer
> b
->peer
) return 1;
735 requestListAdd( Torrent
* t
, tr_block_index_t block
, tr_peer
* peer
)
737 struct block_request key
;
739 /* ensure enough room is available... */
740 if( t
->requestCount
+ 1 >= t
->requestAlloc
)
742 const int CHUNK_SIZE
= 128;
743 t
->requestAlloc
+= CHUNK_SIZE
;
744 t
->requests
= tr_renew( struct block_request
,
745 t
->requests
, t
->requestAlloc
);
748 /* populate the record we're inserting */
751 key
.sentAt
= tr_time( );
753 /* insert the request to our array... */
756 const int pos
= tr_lowerBound( &key
, t
->requests
, t
->requestCount
,
757 sizeof( struct block_request
),
758 compareReqByBlock
, &exact
);
760 memmove( t
->requests
+ pos
+ 1,
762 sizeof( struct block_request
) * ( t
->requestCount
++ - pos
) );
763 t
->requests
[pos
] = key
;
768 ++peer
->pendingReqsToPeer
;
769 assert( peer
->pendingReqsToPeer
>= 0 );
772 /*fprintf( stderr, "added request of block %lu from peer %s... "
773 "there are now %d block\n",
774 (unsigned long)block, tr_atomAddrStr( peer->atom ), t->requestCount );*/
777 static struct block_request
*
778 requestListLookup( Torrent
* t
, tr_block_index_t block
, const tr_peer
* peer
)
780 struct block_request key
;
782 key
.peer
= (tr_peer
*) peer
;
784 return bsearch( &key
, t
->requests
, t
->requestCount
,
785 sizeof( struct block_request
),
790 * Find the peers are we currently requesting the block
791 * with index @a block from and append them to @a peerArr.
794 getBlockRequestPeers( Torrent
* t
, tr_block_index_t block
,
795 tr_ptrArray
* peerArr
)
799 struct block_request key
;
803 pos
= tr_lowerBound( &key
, t
->requests
, t
->requestCount
,
804 sizeof( struct block_request
),
805 compareReqByBlock
, &exact
);
807 assert( !exact
); /* shouldn't have a request with .peer == NULL */
809 for( i
= pos
; i
< t
->requestCount
; ++i
)
811 if( t
->requests
[i
].block
!= block
)
813 tr_ptrArrayAppend( peerArr
, t
->requests
[i
].peer
);
818 decrementPendingReqCount( const struct block_request
* b
)
820 if( b
->peer
!= NULL
)
821 if( b
->peer
->pendingReqsToPeer
> 0 )
822 --b
->peer
->pendingReqsToPeer
;
826 requestListRemove( Torrent
* t
, tr_block_index_t block
, const tr_peer
* peer
)
828 const struct block_request
* b
= requestListLookup( t
, block
, peer
);
831 const int pos
= b
- t
->requests
;
832 assert( pos
< t
->requestCount
);
834 decrementPendingReqCount( b
);
836 tr_removeElementFromArray( t
->requests
,
838 sizeof( struct block_request
),
841 /*fprintf( stderr, "removing request of block %lu from peer %s... "
842 "there are now %d block requests left\n",
843 (unsigned long)block, tr_atomAddrStr( peer->atom ), t->requestCount );*/
848 countActiveWebseeds( const Torrent
* t
)
851 const tr_webseed
** w
= (const tr_webseed
**) tr_ptrArrayBase( &t
->webseeds
);
852 const tr_webseed
** const wend
= w
+ tr_ptrArraySize( &t
->webseeds
);
854 for( ; w
!=wend
; ++w
)
855 if( tr_webseedIsActive( *w
) )
862 testForEndgame( const Torrent
* t
)
864 /* we consider ourselves to be in endgame if the number of bytes
865 we've got requested is >= the number of bytes left to download */
866 return ( t
->requestCount
* t
->tor
->blockSize
)
867 >= tr_cpLeftUntilDone( &t
->tor
->completion
);
871 updateEndgame( Torrent
* t
)
873 assert( t
->requestCount
>= 0 );
875 if( !testForEndgame( t
) )
880 else if( !t
->endgame
) /* only recalculate when endgame first begins */
882 int numDownloading
= 0;
883 const tr_peer
** p
= (const tr_peer
**) tr_ptrArrayBase( &t
->peers
);
884 const tr_peer
** const pend
= p
+ tr_ptrArraySize( &t
->peers
);
886 /* add the active bittorrent peers... */
887 for( ; p
!=pend
; ++p
)
888 if( (*p
)->pendingReqsToPeer
> 0 )
891 /* add the active webseeds... */
892 numDownloading
+= countActiveWebseeds( t
);
894 /* average number of pending requests per downloading peer */
895 t
->endgame
= t
->requestCount
/ MAX( numDownloading
, 1 );
902 ***** Piece List Manipulation / Accessors
907 invalidatePieceSorting( Torrent
* t
)
909 t
->pieceSortState
= PIECES_UNSORTED
;
912 static const tr_torrent
* weightTorrent
;
914 static const uint16_t * weightReplication
;
917 setComparePieceByWeightTorrent( Torrent
* t
)
919 if( !replicationExists( t
) )
922 weightTorrent
= t
->tor
;
923 weightReplication
= t
->pieceReplication
;
926 /* we try to create a "weight" s.t. high-priority pieces come before others,
927 * and that partially-complete pieces come before empty ones. */
929 comparePieceByWeight( const void * va
, const void * vb
)
931 const struct weighted_piece
* a
= va
;
932 const struct weighted_piece
* b
= vb
;
933 int ia
, ib
, missing
, pending
;
934 const tr_torrent
* tor
= weightTorrent
;
935 const uint16_t * rep
= weightReplication
;
937 /* primary key: weight */
938 missing
= tr_cpMissingBlocksInPiece( &tor
->completion
, a
->index
);
939 pending
= a
->requestCount
;
940 ia
= missing
> pending
? missing
- pending
: (tor
->blockCountInPiece
+ pending
);
941 missing
= tr_cpMissingBlocksInPiece( &tor
->completion
, b
->index
);
942 pending
= b
->requestCount
;
943 ib
= missing
> pending
? missing
- pending
: (tor
->blockCountInPiece
+ pending
);
944 if( ia
< ib
) return -1;
945 if( ia
> ib
) return 1;
947 /* secondary key: higher priorities go first */
948 ia
= tor
->info
.pieces
[a
->index
].priority
;
949 ib
= tor
->info
.pieces
[b
->index
].priority
;
950 if( ia
> ib
) return -1;
951 if( ia
< ib
) return 1;
953 /* tertiary key: rarest first. */
956 if( ia
< ib
) return -1;
957 if( ia
> ib
) return 1;
959 /* quaternary key: random */
960 if( a
->salt
< b
->salt
) return -1;
961 if( a
->salt
> b
->salt
) return 1;
963 /* okay, they're equal */
968 comparePieceByIndex( const void * va
, const void * vb
)
970 const struct weighted_piece
* a
= va
;
971 const struct weighted_piece
* b
= vb
;
972 if( a
->index
< b
->index
) return -1;
973 if( a
->index
> b
->index
) return 1;
978 pieceListSort( Torrent
* t
, enum piece_sort_state state
)
980 assert( state
==PIECES_SORTED_BY_INDEX
981 || state
==PIECES_SORTED_BY_WEIGHT
);
984 if( state
== PIECES_SORTED_BY_WEIGHT
)
986 setComparePieceByWeightTorrent( t
);
987 qsort( t
->pieces
, t
->pieceCount
, sizeof( struct weighted_piece
), comparePieceByWeight
);
990 qsort( t
->pieces
, t
->pieceCount
, sizeof( struct weighted_piece
), comparePieceByIndex
);
992 t
->pieceSortState
= state
;
996 * These functions are useful for testing, but too expensive for nightly builds.
997 * let's leave it disabled but add an easy hook to compile it back in
1000 #define assertWeightedPiecesAreSorted(t)
1001 #define assertReplicationCountIsExact(t)
1004 assertWeightedPiecesAreSorted( Torrent
* t
)
1009 setComparePieceByWeightTorrent( t
);
1010 for( i
=0; i
<t
->pieceCount
-1; ++i
)
1011 assert( comparePieceByWeight( &t
->pieces
[i
], &t
->pieces
[i
+1] ) <= 0 );
1015 assertReplicationCountIsExact( Torrent
* t
)
1017 /* This assert might fail due to errors of implementations in other
1018 * clients. It happens when receiving duplicate bitfields/HaveAll/HaveNone
1019 * from a client. If a such a behavior is noticed,
1020 * a bug report should be filled to the faulty client. */
1023 const uint16_t * rep
= t
->pieceReplication
;
1024 const size_t piece_count
= t
->pieceReplicationSize
;
1025 const tr_peer
** peers
= (const tr_peer
**) tr_ptrArrayBase( &t
->peers
);
1026 const int peer_count
= tr_ptrArraySize( &t
->peers
);
1028 assert( piece_count
== t
->tor
->info
.pieceCount
);
1030 for( piece_i
=0; piece_i
<piece_count
; ++piece_i
)
1035 for( peer_i
=0; peer_i
<peer_count
; ++peer_i
)
1036 if( tr_bitsetHas( &peers
[peer_i
]->have
, piece_i
) )
1039 assert( rep
[piece_i
] == r
);
1044 static struct weighted_piece
*
1045 pieceListLookup( Torrent
* t
, tr_piece_index_t index
)
1049 for( i
=0; i
<t
->pieceCount
; ++i
)
1050 if( t
->pieces
[i
].index
== index
)
1051 return &t
->pieces
[i
];
1057 pieceListRebuild( Torrent
* t
)
1060 if( !tr_torrentIsSeed( t
->tor
) )
1063 tr_piece_index_t
* pool
;
1064 tr_piece_index_t poolCount
= 0;
1065 const tr_torrent
* tor
= t
->tor
;
1066 const tr_info
* inf
= tr_torrentInfo( tor
);
1067 struct weighted_piece
* pieces
;
1070 /* build the new list */
1071 pool
= tr_new( tr_piece_index_t
, inf
->pieceCount
);
1072 for( i
=0; i
<inf
->pieceCount
; ++i
)
1073 if( !inf
->pieces
[i
].dnd
)
1074 if( !tr_cpPieceIsComplete( &tor
->completion
, i
) )
1075 pool
[poolCount
++] = i
;
1076 pieceCount
= poolCount
;
1077 pieces
= tr_new0( struct weighted_piece
, pieceCount
);
1078 for( i
=0; i
<poolCount
; ++i
) {
1079 struct weighted_piece
* piece
= pieces
+ i
;
1080 piece
->index
= pool
[i
];
1081 piece
->requestCount
= 0;
1082 piece
->salt
= tr_cryptoWeakRandInt( 4096 );
1085 /* if we already had a list of pieces, merge it into
1086 * the new list so we don't lose its requestCounts */
1087 if( t
->pieces
!= NULL
)
1089 struct weighted_piece
* o
= t
->pieces
;
1090 struct weighted_piece
* oend
= o
+ t
->pieceCount
;
1091 struct weighted_piece
* n
= pieces
;
1092 struct weighted_piece
* nend
= n
+ pieceCount
;
1094 pieceListSort( t
, PIECES_SORTED_BY_INDEX
);
1096 while( o
!=oend
&& n
!=nend
) {
1097 if( o
->index
< n
->index
)
1099 else if( o
->index
> n
->index
)
1105 tr_free( t
->pieces
);
1109 t
->pieceCount
= pieceCount
;
1111 pieceListSort( t
, PIECES_SORTED_BY_WEIGHT
);
1119 pieceListRemovePiece( Torrent
* t
, tr_piece_index_t piece
)
1121 struct weighted_piece
* p
;
1123 if(( p
= pieceListLookup( t
, piece
)))
1125 const int pos
= p
- t
->pieces
;
1127 tr_removeElementFromArray( t
->pieces
,
1129 sizeof( struct weighted_piece
),
1132 if( t
->pieceCount
== 0 )
1134 tr_free( t
->pieces
);
1141 pieceListResortPiece( Torrent
* t
, struct weighted_piece
* p
)
1144 bool isSorted
= true;
1149 /* is the torrent already sorted? */
1150 pos
= p
- t
->pieces
;
1151 setComparePieceByWeightTorrent( t
);
1152 if( isSorted
&& ( pos
> 0 ) && ( comparePieceByWeight( p
-1, p
) > 0 ) )
1154 if( isSorted
&& ( pos
< t
->pieceCount
- 1 ) && ( comparePieceByWeight( p
, p
+1 ) > 0 ) )
1157 if( t
->pieceSortState
!= PIECES_SORTED_BY_WEIGHT
)
1159 pieceListSort( t
, PIECES_SORTED_BY_WEIGHT
);
1163 /* if it's not sorted, move it around */
1167 const struct weighted_piece tmp
= *p
;
1169 tr_removeElementFromArray( t
->pieces
,
1171 sizeof( struct weighted_piece
),
1174 pos
= tr_lowerBound( &tmp
, t
->pieces
, t
->pieceCount
,
1175 sizeof( struct weighted_piece
),
1176 comparePieceByWeight
, &exact
);
1178 memmove( &t
->pieces
[pos
+ 1],
1180 sizeof( struct weighted_piece
) * ( t
->pieceCount
++ - pos
) );
1182 t
->pieces
[pos
] = tmp
;
1185 assertWeightedPiecesAreSorted( t
);
1189 pieceListRemoveRequest( Torrent
* t
, tr_block_index_t block
)
1191 struct weighted_piece
* p
;
1192 const tr_piece_index_t index
= tr_torBlockPiece( t
->tor
, block
);
1194 if( ((p
= pieceListLookup( t
, index
))) && ( p
->requestCount
> 0 ) )
1197 pieceListResortPiece( t
, p
);
1204 ***** Replication count ( for rarest first policy )
1209 * Increase the replication count of this piece and sort it if the
1210 * piece list is already sorted
1213 tr_incrReplicationOfPiece( Torrent
* t
, const size_t index
)
1215 assert( replicationExists( t
) );
1216 assert( t
->pieceReplicationSize
== t
->tor
->info
.pieceCount
);
1218 /* One more replication of this piece is present in the swarm */
1219 ++t
->pieceReplication
[index
];
1221 /* we only resort the piece if the list is already sorted */
1222 if( t
->pieceSortState
== PIECES_SORTED_BY_WEIGHT
)
1223 pieceListResortPiece( t
, pieceListLookup( t
, index
) );
1227 * Increases the replication count of pieces present in the bitfield
1230 tr_incrReplicationFromBitfield( Torrent
* t
, const tr_bitfield
* b
)
1233 uint16_t * rep
= t
->pieceReplication
;
1234 const size_t n
= t
->tor
->info
.pieceCount
;
1236 assert( replicationExists( t
) );
1238 for( i
=0; i
<n
; ++i
)
1239 if( tr_bitfieldHas( b
, i
) )
1242 if( t
->pieceSortState
== PIECES_SORTED_BY_WEIGHT
)
1243 invalidatePieceSorting( t
);
1247 * Increase the replication count of every piece
1250 tr_incrReplication( Torrent
* t
)
1253 const int n
= t
->pieceReplicationSize
;
1255 assert( replicationExists( t
) );
1256 assert( t
->pieceReplicationSize
== t
->tor
->info
.pieceCount
);
1258 for( i
=0; i
<n
; ++i
)
1259 ++t
->pieceReplication
[i
];
1263 * Decrease the replication count of pieces present in the bitset.
1266 tr_decrReplicationFromBitfield( Torrent
* t
, const tr_bitfield
* b
)
1269 const int n
= t
->pieceReplicationSize
;
1271 assert( replicationExists( t
) );
1272 assert( t
->pieceReplicationSize
== t
->tor
->info
.pieceCount
);
1274 if( tr_bitfieldHasAll( b
) )
1276 for( i
=0; i
<n
; ++i
)
1277 --t
->pieceReplication
[i
];
1279 else if ( !tr_bitfieldHasNone( b
) )
1281 for( i
=0; i
<n
; ++i
)
1282 if( tr_bitfieldHas( b
, i
) )
1283 --t
->pieceReplication
[i
];
1285 if( t
->pieceSortState
== PIECES_SORTED_BY_WEIGHT
)
1286 invalidatePieceSorting( t
);
1295 tr_peerMgrRebuildRequests( tr_torrent
* tor
)
1297 assert( tr_isTorrent( tor
) );
1299 pieceListRebuild( tor
->torrentPeers
);
1303 tr_peerMgrGetNextRequests( tr_torrent
* tor
,
1306 tr_block_index_t
* setme
,
1308 bool get_intervals
)
1313 struct weighted_piece
* pieces
;
1314 const tr_bitfield
* const have
= &peer
->have
;
1317 assert( tr_isTorrent( tor
) );
1318 assert( peer
->clientIsInterested
);
1319 assert( !peer
->clientIsChoked
);
1320 assert( numwant
> 0 );
1322 /* walk through the pieces and find blocks that should be requested */
1324 t
= tor
->torrentPeers
;
1326 /* prep the pieces list */
1327 if( t
->pieces
== NULL
)
1328 pieceListRebuild( t
);
1330 if( t
->pieceSortState
!= PIECES_SORTED_BY_WEIGHT
)
1331 pieceListSort( t
, PIECES_SORTED_BY_WEIGHT
);
1333 assertReplicationCountIsExact( t
);
1334 assertWeightedPiecesAreSorted( t
);
1338 for( i
=0; i
<t
->pieceCount
&& got
<numwant
; ++i
)
1340 struct weighted_piece
* p
= pieces
+ i
;
1342 /* if the peer has this piece that we want... */
1343 if( tr_bitfieldHas( have
, p
->index
) )
1346 tr_block_index_t first
;
1347 tr_block_index_t last
;
1348 tr_ptrArray peerArr
= TR_PTR_ARRAY_INIT
;
1350 tr_torGetPieceBlockRange( tor
, p
->index
, &first
, &last
);
1352 for( b
=first
; b
<=last
&& (got
<numwant
|| (get_intervals
&& setme
[2*got
-1] == b
-1)); ++b
)
1357 /* don't request blocks we've already got */
1358 if( tr_cpBlockIsComplete( &tor
->completion
, b
) )
1361 /* always add peer if this block has no peers yet */
1362 tr_ptrArrayClear( &peerArr
);
1363 getBlockRequestPeers( t
, b
, &peerArr
);
1364 peers
= (tr_peer
**) tr_ptrArrayPeek( &peerArr
, &peerCount
);
1365 if( peerCount
!= 0 )
1367 /* don't make a second block request until the endgame */
1371 /* don't have more than two peers requesting this block */
1375 /* don't send the same request to the same peer twice */
1376 if( peer
== peers
[0] )
1379 /* in the endgame allow an additional peer to download a
1380 block but only if the peer seems to be handling requests
1382 if( peer
->pendingReqsToPeer
+ numwant
- got
< t
->endgame
)
1386 /* update the caller's table */
1387 if( !get_intervals
) {
1390 /* if intervals are requested two array entries are necessarry:
1391 one for the interval's starting block and one for its end block */
1392 else if( got
&& setme
[2 * got
- 1] == b
- 1 && b
!= first
) {
1393 /* expand the last interval */
1394 ++setme
[2 * got
- 1];
1397 /* begin a new interval */
1398 setme
[2 * got
] = setme
[2 * got
+ 1] = b
;
1402 /* update our own tables */
1403 requestListAdd( t
, b
, peer
);
1407 tr_ptrArrayDestruct( &peerArr
, NULL
);
1411 /* In most cases we've just changed the weights of a small number of pieces.
1412 * So rather than qsort()ing the entire array, it's faster to apply an
1413 * adaptive insertion sort algorithm. */
1416 /* not enough requests || last piece modified */
1417 if ( i
== t
->pieceCount
) --i
;
1419 setComparePieceByWeightTorrent( t
);
1424 /* relative position! */
1425 const int newpos
= tr_lowerBound( &t
->pieces
[i
], &t
->pieces
[i
+ 1],
1426 t
->pieceCount
- (i
+ 1),
1427 sizeof( struct weighted_piece
),
1428 comparePieceByWeight
, &exact
);
1431 const struct weighted_piece piece
= t
->pieces
[i
];
1432 memmove( &t
->pieces
[i
],
1434 sizeof( struct weighted_piece
) * ( newpos
) );
1435 t
->pieces
[i
+ newpos
] = piece
;
1440 assertWeightedPiecesAreSorted( t
);
1445 tr_peerMgrDidPeerRequest( const tr_torrent
* tor
,
1446 const tr_peer
* peer
,
1447 tr_block_index_t block
)
1449 const Torrent
* t
= tor
->torrentPeers
;
1450 return requestListLookup( (Torrent
*)t
, block
, peer
) != NULL
;
1453 /* cancel requests that are too old */
1455 refillUpkeep( int foo UNUSED
, short bar UNUSED
, void * vmgr
)
1460 int cancel_buflen
= 0;
1461 struct block_request
* cancel
= NULL
;
1462 tr_peerMgr
* mgr
= vmgr
;
1466 too_old
= now
- REQUEST_TTL_SECS
;
1468 /* alloc the temporary "cancel" buffer */
1470 while(( tor
= tr_torrentNext( mgr
->session
, tor
)))
1471 cancel_buflen
= MAX( cancel_buflen
, tor
->torrentPeers
->requestCount
);
1472 if( cancel_buflen
> 0 )
1473 cancel
= tr_new( struct block_request
, cancel_buflen
);
1475 /* prune requests that are too old */
1477 while(( tor
= tr_torrentNext( mgr
->session
, tor
)))
1479 Torrent
* t
= tor
->torrentPeers
;
1480 const int n
= t
->requestCount
;
1484 int cancelCount
= 0;
1485 const struct block_request
* it
;
1486 const struct block_request
* end
;
1488 for( it
=t
->requests
, end
=it
+n
; it
!=end
; ++it
)
1490 if( ( it
->sentAt
<= too_old
) && it
->peer
->msgs
&& !tr_peerMsgsIsReadingBlock( it
->peer
->msgs
, it
->block
) )
1491 cancel
[cancelCount
++] = *it
;
1494 if( it
!= &t
->requests
[keepCount
] )
1495 t
->requests
[keepCount
] = *it
;
1500 /* prune out the ones we aren't keeping */
1501 t
->requestCount
= keepCount
;
1503 /* send cancel messages for all the "cancel" ones */
1504 for( it
=cancel
, end
=it
+cancelCount
; it
!=end
; ++it
) {
1505 if( ( it
->peer
!= NULL
) && ( it
->peer
->msgs
!= NULL
) ) {
1506 tr_historyAdd( &it
->peer
->cancelsSentToPeer
, now
, 1 );
1507 tr_peerMsgsCancel( it
->peer
->msgs
, it
->block
);
1508 decrementPendingReqCount( it
);
1512 /* decrement the pending request counts for the timed-out blocks */
1513 for( it
=cancel
, end
=it
+cancelCount
; it
!=end
; ++it
)
1514 pieceListRemoveRequest( t
, it
->block
);
1519 tr_timerAddMsec( mgr
->refillUpkeepTimer
, REFILL_UPKEEP_PERIOD_MSEC
);
1520 managerUnlock( mgr
);
1524 addStrike( Torrent
* t
, tr_peer
* peer
)
1526 tordbg( t
, "increasing peer %s strike count to %d",
1527 tr_atomAddrStr( peer
->atom
), peer
->strikes
+ 1 );
1529 if( ++peer
->strikes
>= MAX_BAD_PIECES_PER_PEER
)
1531 struct peer_atom
* atom
= peer
->atom
;
1532 atom
->flags2
|= MYFLAG_BANNED
;
1534 tordbg( t
, "banning peer %s", tr_atomAddrStr( atom
) );
1539 gotBadPiece( Torrent
* t
, tr_piece_index_t pieceIndex
)
1541 tr_torrent
* tor
= t
->tor
;
1542 const uint32_t byteCount
= tr_torPieceCountBytes( tor
, pieceIndex
);
1544 tor
->corruptCur
+= byteCount
;
1545 tor
->downloadedCur
-= MIN( tor
->downloadedCur
, byteCount
);
1547 tr_announcerAddBytes( tor
, TR_ANN_CORRUPT
, byteCount
);
1551 peerSuggestedPiece( Torrent
* t UNUSED
,
1552 tr_peer
* peer UNUSED
,
1553 tr_piece_index_t pieceIndex UNUSED
,
1554 int isFastAllowed UNUSED
)
1559 assert( peer
->msgs
);
1561 /* is this a valid piece? */
1562 if( pieceIndex
>= t
->tor
->info
.pieceCount
)
1565 /* don't ask for it if we've already got it */
1566 if( tr_cpPieceIsComplete( t
->tor
->completion
, pieceIndex
) )
1569 /* don't ask for it if they don't have it */
1570 if( !tr_bitfieldHas( peer
->have
, pieceIndex
) )
1573 /* don't ask for it if we're choked and it's not fast */
1574 if( !isFastAllowed
&& peer
->clientIsChoked
)
1577 /* request the blocks that we don't have in this piece */
1580 tr_block_index_t first
;
1581 tr_block_index_t last
;
1582 const tr_torrent
* tor
= t
->tor
;
1584 tr_torGetPieceBlockRange( t
->tor
, pieceIndex
, &first
, &last
);
1586 for( b
=first
; b
<=last
; ++b
)
1588 if( !tr_cpBlockIsComplete( tor
->completion
, b
) )
1590 const uint32_t offset
= getBlockOffsetInPiece( tor
, b
);
1591 const uint32_t length
= tr_torBlockCountBytes( tor
, b
);
1592 tr_peerMsgsAddRequest( peer
->msgs
, pieceIndex
, offset
, length
);
1593 incrementPieceRequests( t
, pieceIndex
);
1601 removeRequestFromTables( Torrent
* t
, tr_block_index_t block
, const tr_peer
* peer
)
1603 requestListRemove( t
, block
, peer
);
1604 pieceListRemoveRequest( t
, block
);
1607 /* peer choked us, or maybe it disconnected.
1608 either way we need to remove all its requests */
1610 peerDeclinedAllRequests( Torrent
* t
, const tr_peer
* peer
)
1613 tr_block_index_t
* blocks
= tr_new( tr_block_index_t
, t
->requestCount
);
1615 for( i
=n
=0; i
<t
->requestCount
; ++i
)
1616 if( peer
== t
->requests
[i
].peer
)
1617 blocks
[n
++] = t
->requests
[i
].block
;
1619 for( i
=0; i
<n
; ++i
)
1620 removeRequestFromTables( t
, blocks
[i
], peer
);
1625 static void tr_peerMgrSetBlame( tr_torrent
*, tr_piece_index_t
, int );
1628 peerCallbackFunc( tr_peer
* peer
, const tr_peer_event
* e
, void * vt
)
1634 assert( peer
!= NULL
);
1636 switch( e
->eventType
)
1638 case TR_PEER_PEER_GOT_DATA
:
1640 const time_t now
= tr_time( );
1641 tr_torrent
* tor
= t
->tor
;
1643 if( e
->wasPieceData
)
1645 tor
->uploadedCur
+= e
->length
;
1646 tr_announcerAddBytes( tor
, TR_ANN_UP
, e
->length
);
1647 tr_torrentSetActivityDate( tor
, now
);
1648 tr_torrentSetDirty( tor
);
1651 /* update the stats */
1652 if( e
->wasPieceData
)
1653 tr_statsAddUploaded( tor
->session
, e
->length
);
1655 /* update our atom */
1656 if( peer
->atom
&& e
->wasPieceData
)
1657 peer
->atom
->piece_data_time
= now
;
1662 case TR_PEER_CLIENT_GOT_HAVE
:
1663 if( replicationExists( t
) ) {
1664 tr_incrReplicationOfPiece( t
, e
->pieceIndex
);
1665 assertReplicationCountIsExact( t
);
1669 case TR_PEER_CLIENT_GOT_HAVE_ALL
:
1670 if( replicationExists( t
) ) {
1671 tr_incrReplication( t
);
1672 assertReplicationCountIsExact( t
);
1676 case TR_PEER_CLIENT_GOT_HAVE_NONE
:
1680 case TR_PEER_CLIENT_GOT_BITFIELD
:
1681 assert( e
->bitfield
!= NULL
);
1682 if( replicationExists( t
) ) {
1683 tr_incrReplicationFromBitfield( t
, e
->bitfield
);
1684 assertReplicationCountIsExact( t
);
1688 case TR_PEER_CLIENT_GOT_REJ
: {
1689 tr_block_index_t b
= _tr_block( t
->tor
, e
->pieceIndex
, e
->offset
);
1690 if( b
< t
->tor
->blockCount
)
1691 removeRequestFromTables( t
, b
, peer
);
1693 tordbg( t
, "Peer %s sent an out-of-range reject message",
1694 tr_atomAddrStr( peer
->atom
) );
1698 case TR_PEER_CLIENT_GOT_CHOKE
:
1699 peerDeclinedAllRequests( t
, peer
);
1702 case TR_PEER_CLIENT_GOT_PORT
:
1704 peer
->atom
->port
= e
->port
;
1707 case TR_PEER_CLIENT_GOT_SUGGEST
:
1708 peerSuggestedPiece( t
, peer
, e
->pieceIndex
, false );
1711 case TR_PEER_CLIENT_GOT_ALLOWED_FAST
:
1712 peerSuggestedPiece( t
, peer
, e
->pieceIndex
, true );
1715 case TR_PEER_CLIENT_GOT_DATA
:
1717 const time_t now
= tr_time( );
1718 tr_torrent
* tor
= t
->tor
;
1720 if( e
->wasPieceData
)
1722 tor
->downloadedCur
+= e
->length
;
1723 tr_torrentSetActivityDate( tor
, now
);
1724 tr_torrentSetDirty( tor
);
1727 /* update the stats */
1728 if( e
->wasPieceData
)
1729 tr_statsAddDownloaded( tor
->session
, e
->length
);
1731 /* update our atom */
1732 if( peer
->atom
&& e
->wasPieceData
)
1733 peer
->atom
->piece_data_time
= now
;
1738 case TR_PEER_CLIENT_GOT_BLOCK
:
1740 tr_torrent
* tor
= t
->tor
;
1741 tr_block_index_t block
= _tr_block( tor
, e
->pieceIndex
, e
->offset
);
1744 tr_ptrArray peerArr
= TR_PTR_ARRAY_INIT
;
1746 removeRequestFromTables( t
, block
, peer
);
1747 getBlockRequestPeers( t
, block
, &peerArr
);
1748 peers
= (tr_peer
**) tr_ptrArrayPeek( &peerArr
, &peerCount
);
1750 /* remove additional block requests and send cancel to peers */
1751 for( i
=0; i
<peerCount
; i
++ ) {
1752 tr_peer
* p
= peers
[i
];
1753 assert( p
!= peer
);
1755 tr_historyAdd( &p
->cancelsSentToPeer
, tr_time( ), 1 );
1756 tr_peerMsgsCancel( p
->msgs
, block
);
1758 removeRequestFromTables( t
, block
, p
);
1761 tr_ptrArrayDestruct( &peerArr
, false );
1763 tr_historyAdd( &peer
->blocksSentToClient
, tr_time( ), 1 );
1765 if( tr_cpBlockIsComplete( &tor
->completion
, block
) )
1767 /* we already have this block... */
1768 const uint32_t n
= tr_torBlockCountBytes( tor
, block
);
1769 tor
->downloadedCur
-= MIN( tor
->downloadedCur
, n
);
1770 tordbg( t
, "we have this block already..." );
1774 tr_cpBlockAdd( &tor
->completion
, block
);
1775 pieceListResortPiece( t
, pieceListLookup( t
, e
->pieceIndex
) );
1776 tr_torrentSetDirty( tor
);
1778 if( tr_cpPieceIsComplete( &tor
->completion
, e
->pieceIndex
) )
1780 const tr_piece_index_t p
= e
->pieceIndex
;
1781 const bool ok
= tr_torrentCheckPiece( tor
, p
);
1783 tordbg( t
, "[LAZY] checked just-completed piece %zu", (size_t)p
);
1787 tr_torerr( tor
, _( "Piece %lu, which was just downloaded, failed its checksum test" ),
1791 tr_peerMgrSetBlame( tor
, p
, ok
);
1795 gotBadPiece( t
, p
);
1802 tr_file_index_t fileIndex
;
1804 /* only add this to downloadedCur if we got it from a peer --
1805 * webseeds shouldn't count against our ratio. As one tracker
1806 * admin put it, "Those pieces are downloaded directly from the
1807 * content distributor, not the peers, it is the tracker's job
1808 * to manage the swarms, not the web server and does not fit
1809 * into the jurisdiction of the tracker." */
1810 if( peer
->msgs
!= NULL
) {
1811 const uint32_t n
= tr_torPieceCountBytes( tor
, p
);
1812 tr_announcerAddBytes( tor
, TR_ANN_DOWN
, n
);
1815 peerCount
= tr_ptrArraySize( &t
->peers
);
1816 peers
= (tr_peer
**) tr_ptrArrayBase( &t
->peers
);
1817 for( i
=0; i
<peerCount
; ++i
)
1818 tr_peerMsgsHave( peers
[i
]->msgs
, p
);
1820 for( fileIndex
=0; fileIndex
<tor
->info
.fileCount
; ++fileIndex
) {
1821 const tr_file
* file
= &tor
->info
.files
[fileIndex
];
1822 if( ( file
->firstPiece
<= p
) && ( p
<= file
->lastPiece
) ) {
1823 if( tr_cpFileIsComplete( &tor
->completion
, fileIndex
) ) {
1824 tr_cacheFlushFile( tor
->session
->cache
, tor
, fileIndex
);
1825 tr_torrentFileCompleted( tor
, fileIndex
);
1830 pieceListRemovePiece( t
, p
);
1834 t
->needsCompletenessCheck
= true;
1840 if( ( e
->err
== ERANGE
) || ( e
->err
== EMSGSIZE
) || ( e
->err
== ENOTCONN
) )
1842 /* some protocol error from the peer */
1844 tordbg( t
, "setting %s doPurge flag because we got an ERANGE, EMSGSIZE, or ENOTCONN error",
1845 tr_atomAddrStr( peer
->atom
) );
1849 tordbg( t
, "unhandled error: %s", tr_strerror( e
->err
) );
1861 getDefaultShelfLife( uint8_t from
)
1863 /* in general, peers obtained from firsthand contact
1864 * are better than those from secondhand, etc etc */
1867 case TR_PEER_FROM_INCOMING
: return 60 * 60 * 6;
1868 case TR_PEER_FROM_LTEP
: return 60 * 60 * 6;
1869 case TR_PEER_FROM_TRACKER
: return 60 * 60 * 3;
1870 case TR_PEER_FROM_DHT
: return 60 * 60 * 3;
1871 case TR_PEER_FROM_PEX
: return 60 * 60 * 2;
1872 case TR_PEER_FROM_RESUME
: return 60 * 60;
1873 case TR_PEER_FROM_LPD
: return 10 * 60;
1874 default : return 60 * 60;
1879 ensureAtomExists( Torrent
* t
,
1880 const tr_address
* addr
,
1882 const uint8_t flags
,
1883 const int8_t seedProbability
,
1884 const uint8_t from
)
1886 struct peer_atom
* a
;
1888 assert( tr_address_is_valid( addr
) );
1889 assert( from
< TR_PEER_FROM__MAX
);
1891 a
= getExistingAtom( t
, addr
);
1895 const int jitter
= tr_cryptoWeakRandInt( 60*10 );
1896 a
= tr_new0( struct peer_atom
, 1 );
1900 a
->fromFirst
= from
;
1902 a
->shelf_date
= tr_time( ) + getDefaultShelfLife( from
) + jitter
;
1903 a
->blocklisted
= -1;
1904 atomSetSeedProbability( a
, seedProbability
);
1905 tr_ptrArrayInsertSorted( &t
->pool
, a
, compareAtomsByAddress
);
1907 tordbg( t
, "got a new atom: %s", tr_atomAddrStr( a
) );
1911 if( from
< a
->fromBest
)
1914 if( a
->seedProbability
== -1 )
1915 atomSetSeedProbability( a
, seedProbability
);
1922 getMaxPeerCount( const tr_torrent
* tor
)
1924 return tor
->maxConnectedPeers
;
1928 getPeerCount( const Torrent
* t
)
1930 return tr_ptrArraySize( &t
->peers
);/* + tr_ptrArraySize( &t->outgoingHandshakes ); */
1933 /* FIXME: this is kind of a mess. */
1935 myHandshakeDoneCB( tr_handshake
* handshake
,
1937 bool readAnythingFromPeer
,
1939 const uint8_t * peer_id
,
1942 bool ok
= isConnected
;
1943 bool success
= false;
1945 const tr_address
* addr
;
1946 tr_peerMgr
* manager
= vmanager
;
1948 tr_handshake
* ours
;
1951 assert( tr_isBool( ok
) );
1953 t
= tr_peerIoHasTorrentHash( io
)
1954 ? getExistingTorrent( manager
, tr_peerIoGetTorrentHash( io
) )
1957 if( tr_peerIoIsIncoming ( io
) )
1958 ours
= tr_ptrArrayRemoveSorted( &manager
->incomingHandshakes
,
1959 handshake
, handshakeCompare
);
1961 ours
= tr_ptrArrayRemoveSorted( &t
->outgoingHandshakes
,
1962 handshake
, handshakeCompare
);
1967 assert( ours
== handshake
);
1972 addr
= tr_peerIoGetAddress( io
, &port
);
1974 if( !ok
|| !t
|| !t
->isRunning
)
1978 struct peer_atom
* atom
= getExistingAtom( t
, addr
);
1983 if( !readAnythingFromPeer
)
1985 tordbg( t
, "marking peer %s as unreachable... numFails is %d", tr_atomAddrStr( atom
), (int)atom
->numFails
);
1986 atom
->flags2
|= MYFLAG_UNREACHABLE
;
1991 else /* looking good */
1993 struct peer_atom
* atom
;
1995 ensureAtomExists( t
, addr
, port
, 0, -1, TR_PEER_FROM_INCOMING
);
1996 atom
= getExistingAtom( t
, addr
);
1997 atom
->time
= tr_time( );
1998 atom
->piece_data_time
= 0;
1999 atom
->lastConnectionAt
= tr_time( );
2001 if( !tr_peerIoIsIncoming( io
) )
2003 atom
->flags
|= ADDED_F_CONNECTABLE
;
2004 atom
->flags2
&= ~MYFLAG_UNREACHABLE
;
2007 /* In principle, this flag specifies whether the peer groks uTP,
2008 not whether it's currently connected over uTP. */
2009 if( io
->utp_socket
)
2010 atom
->flags
|= ADDED_F_UTP_FLAGS
;
2012 if( atom
->flags2
& MYFLAG_BANNED
)
2014 tordbg( t
, "banned peer %s tried to reconnect",
2015 tr_atomAddrStr( atom
) );
2017 else if( tr_peerIoIsIncoming( io
)
2018 && ( getPeerCount( t
) >= getMaxPeerCount( t
->tor
) ) )
2024 tr_peer
* peer
= atom
->peer
;
2026 if( peer
) /* we already have this peer */
2031 peer
= getPeer( t
, atom
);
2032 tr_free( peer
->client
);
2035 peer
->client
= NULL
;
2038 tr_clientForId( client
, sizeof( client
), peer_id
);
2039 peer
->client
= tr_strdup( client
);
2042 peer
->io
= tr_handshakeStealIO( handshake
); /* this steals its refcount too, which is
2043 balanced by our unref in peerDelete() */
2044 tr_peerIoSetParent( peer
->io
, &t
->tor
->bandwidth
);
2045 tr_peerMsgsNew( t
->tor
, peer
, peerCallbackFunc
, t
);
2059 tr_peerMgrAddIncoming( tr_peerMgr
* manager
,
2063 struct UTPSocket
* utp_socket
)
2065 tr_session
* session
;
2067 managerLock( manager
);
2069 assert( tr_isSession( manager
->session
) );
2070 session
= manager
->session
;
2072 if( tr_sessionIsAddressBlocked( session
, addr
) )
2074 tr_dbg( "Banned IP address \"%s\" tried to connect to us", tr_address_to_string( addr
) );
2076 tr_netClose( session
, socket
);
2078 UTP_Close( utp_socket
);
2080 else if( getExistingHandshake( &manager
->incomingHandshakes
, addr
) )
2083 tr_netClose( session
, socket
);
2085 UTP_Close( utp_socket
);
2087 else /* we don't have a connection to them yet... */
2090 tr_handshake
* handshake
;
2092 io
= tr_peerIoNewIncoming( session
, &session
->bandwidth
, addr
, port
, socket
, utp_socket
);
2094 handshake
= tr_handshakeNew( io
,
2095 session
->encryptionMode
,
2099 tr_peerIoUnref( io
); /* balanced by the implicit ref in tr_peerIoNewIncoming() */
2101 tr_ptrArrayInsertSorted( &manager
->incomingHandshakes
, handshake
,
2105 managerUnlock( manager
);
2109 tr_peerMgrAddPex( tr_torrent
* tor
, uint8_t from
,
2110 const tr_pex
* pex
, int8_t seedProbability
)
2112 if( tr_isPex( pex
) ) /* safeguard against corrupt data */
2114 Torrent
* t
= tor
->torrentPeers
;
2115 managerLock( t
->manager
);
2117 if( !tr_sessionIsAddressBlocked( t
->manager
->session
, &pex
->addr
) )
2118 if( tr_address_is_valid_for_peers( &pex
->addr
, pex
->port
) )
2119 ensureAtomExists( t
, &pex
->addr
, pex
->port
, pex
->flags
, seedProbability
, from
);
2121 managerUnlock( t
->manager
);
2126 tr_peerMgrMarkAllAsSeeds( tr_torrent
* tor
)
2128 Torrent
* t
= tor
->torrentPeers
;
2129 const int n
= tr_ptrArraySize( &t
->pool
);
2130 struct peer_atom
** it
= (struct peer_atom
**) tr_ptrArrayBase( &t
->pool
);
2131 struct peer_atom
** end
= it
+ n
;
2134 atomSetSeed( t
, *it
++ );
2138 tr_peerMgrCompactToPex( const void * compact
,
2140 const uint8_t * added_f
,
2145 size_t n
= compactLen
/ 6;
2146 const uint8_t * walk
= compact
;
2147 tr_pex
* pex
= tr_new0( tr_pex
, n
);
2149 for( i
= 0; i
< n
; ++i
)
2151 pex
[i
].addr
.type
= TR_AF_INET
;
2152 memcpy( &pex
[i
].addr
.addr
, walk
, 4 ); walk
+= 4;
2153 memcpy( &pex
[i
].port
, walk
, 2 ); walk
+= 2;
2154 if( added_f
&& ( n
== added_f_len
) )
2155 pex
[i
].flags
= added_f
[i
];
2163 tr_peerMgrCompact6ToPex( const void * compact
,
2165 const uint8_t * added_f
,
2170 size_t n
= compactLen
/ 18;
2171 const uint8_t * walk
= compact
;
2172 tr_pex
* pex
= tr_new0( tr_pex
, n
);
2174 for( i
= 0; i
< n
; ++i
)
2176 pex
[i
].addr
.type
= TR_AF_INET6
;
2177 memcpy( &pex
[i
].addr
.addr
.addr6
.s6_addr
, walk
, 16 ); walk
+= 16;
2178 memcpy( &pex
[i
].port
, walk
, 2 ); walk
+= 2;
2179 if( added_f
&& ( n
== added_f_len
) )
2180 pex
[i
].flags
= added_f
[i
];
2188 tr_peerMgrArrayToPex( const void * array
,
2193 size_t n
= arrayLen
/ ( sizeof( tr_address
) + 2 );
2194 /*size_t n = arrayLen / sizeof( tr_peerArrayElement );*/
2195 const uint8_t * walk
= array
;
2196 tr_pex
* pex
= tr_new0( tr_pex
, n
);
2198 for( i
= 0 ; i
< n
; i
++ ) {
2199 memcpy( &pex
[i
].addr
, walk
, sizeof( tr_address
) );
2200 memcpy( &pex
[i
].port
, walk
+ sizeof( tr_address
), 2 );
2201 pex
[i
].flags
= 0x00;
2202 walk
+= sizeof( tr_address
) + 2;
2214 tr_peerMgrSetBlame( tr_torrent
* tor
,
2215 tr_piece_index_t pieceIndex
,
2221 Torrent
* t
= tor
->torrentPeers
;
2224 assert( torrentIsLocked( t
) );
2226 peers
= (tr_peer
**) tr_ptrArrayPeek( &t
->peers
, &peerCount
);
2227 for( i
= 0; i
< peerCount
; ++i
)
2229 tr_peer
* peer
= peers
[i
];
2230 if( tr_bitfieldHas( &peer
->blame
, pieceIndex
) )
2232 tordbg( t
, "peer %s contributed to corrupt piece (%d); now has %d strikes",
2233 tr_atomAddrStr( peer
->atom
),
2234 pieceIndex
, (int)peer
->strikes
+ 1 );
2235 addStrike( t
, peer
);
2242 tr_pexCompare( const void * va
, const void * vb
)
2244 const tr_pex
* a
= va
;
2245 const tr_pex
* b
= vb
;
2248 assert( tr_isPex( a
) );
2249 assert( tr_isPex( b
) );
2251 if(( i
= tr_address_compare( &a
->addr
, &b
->addr
)))
2254 if( a
->port
!= b
->port
)
2255 return a
->port
< b
->port
? -1 : 1;
2262 peerPrefersCrypto( const tr_peer
* peer
)
2264 if( peer
->encryption_preference
== ENCRYPTION_PREFERENCE_YES
)
2267 if( peer
->encryption_preference
== ENCRYPTION_PREFERENCE_NO
)
2270 return tr_peerIoIsEncrypted( peer
->io
);
2274 /* better goes first */
2276 compareAtomsByUsefulness( const void * va
, const void *vb
)
2278 const struct peer_atom
* a
= * (const struct peer_atom
**) va
;
2279 const struct peer_atom
* b
= * (const struct peer_atom
**) vb
;
2281 assert( tr_isAtom( a
) );
2282 assert( tr_isAtom( b
) );
2284 if( a
->piece_data_time
!= b
->piece_data_time
)
2285 return a
->piece_data_time
> b
->piece_data_time
? -1 : 1;
2286 if( a
->fromBest
!= b
->fromBest
)
2287 return a
->fromBest
< b
->fromBest
? -1 : 1;
2288 if( a
->numFails
!= b
->numFails
)
2289 return a
->numFails
< b
->numFails
? -1 : 1;
2295 isAtomInteresting( const tr_torrent
* tor
, struct peer_atom
* atom
)
2297 if( tr_torrentIsSeed( tor
) && atomIsSeed( atom
) )
2300 if( peerIsInUse( tor
->torrentPeers
, atom
) )
2303 if( isAtomBlocklisted( tor
->session
, atom
) )
2306 if( atom
->flags2
& MYFLAG_BANNED
)
2313 tr_peerMgrGetPeers( tr_torrent
* tor
,
2314 tr_pex
** setme_pex
,
2323 const Torrent
* t
= tor
->torrentPeers
;
2324 struct peer_atom
** atoms
= NULL
;
2328 assert( tr_isTorrent( tor
) );
2329 assert( setme_pex
!= NULL
);
2330 assert( af
==TR_AF_INET
|| af
==TR_AF_INET6
);
2331 assert( list_mode
==TR_PEERS_CONNECTED
|| list_mode
==TR_PEERS_INTERESTING
);
2333 managerLock( t
->manager
);
2336 *** build a list of atoms
2339 if( list_mode
== TR_PEERS_CONNECTED
) /* connected peers only */
2342 const tr_peer
** peers
= (const tr_peer
**) tr_ptrArrayBase( &t
->peers
);
2343 atomCount
= tr_ptrArraySize( &t
->peers
);
2344 atoms
= tr_new( struct peer_atom
*, atomCount
);
2345 for( i
=0; i
<atomCount
; ++i
)
2346 atoms
[i
] = peers
[i
]->atom
;
2348 else /* TR_PEERS_INTERESTING */
2351 struct peer_atom
** atomBase
= (struct peer_atom
**) tr_ptrArrayBase( &t
->pool
);
2352 n
= tr_ptrArraySize( &t
->pool
);
2353 atoms
= tr_new( struct peer_atom
*, n
);
2354 for( i
=0; i
<n
; ++i
)
2355 if( isAtomInteresting( tor
, atomBase
[i
] ) )
2356 atoms
[atomCount
++] = atomBase
[i
];
2359 qsort( atoms
, atomCount
, sizeof( struct peer_atom
* ), compareAtomsByUsefulness
);
2362 *** add the first N of them into our return list
2365 n
= MIN( atomCount
, maxCount
);
2366 pex
= walk
= tr_new0( tr_pex
, n
);
2368 for( i
=0; i
<atomCount
&& count
<n
; ++i
)
2370 const struct peer_atom
* atom
= atoms
[i
];
2371 if( atom
->addr
.type
== af
)
2373 assert( tr_address_is_valid( &atom
->addr
) );
2374 walk
->addr
= atom
->addr
;
2375 walk
->port
= atom
->port
;
2376 walk
->flags
= atom
->flags
;
2382 qsort( pex
, count
, sizeof( tr_pex
), tr_pexCompare
);
2384 assert( ( walk
- pex
) == count
);
2389 managerUnlock( t
->manager
);
2393 static void atomPulse ( int, short, void * );
2394 static void bandwidthPulse ( int, short, void * );
2395 static void rechokePulse ( int, short, void * );
2396 static void reconnectPulse ( int, short, void * );
2398 static struct event
*
2399 createTimer( tr_session
* session
, int msec
, void (*callback
)(int, short, void *), void * cbdata
)
2401 struct event
* timer
= evtimer_new( session
->event_base
, callback
, cbdata
);
2402 tr_timerAddMsec( timer
, msec
);
2407 ensureMgrTimersExist( struct tr_peerMgr
* m
)
2409 if( m
->atomTimer
== NULL
)
2410 m
->atomTimer
= createTimer( m
->session
, ATOM_PERIOD_MSEC
, atomPulse
, m
);
2412 if( m
->bandwidthTimer
== NULL
)
2413 m
->bandwidthTimer
= createTimer( m
->session
, BANDWIDTH_PERIOD_MSEC
, bandwidthPulse
, m
);
2415 if( m
->rechokeTimer
== NULL
)
2416 m
->rechokeTimer
= createTimer( m
->session
, RECHOKE_PERIOD_MSEC
, rechokePulse
, m
);
2418 if( m
->refillUpkeepTimer
== NULL
)
2419 m
->refillUpkeepTimer
= createTimer( m
->session
, REFILL_UPKEEP_PERIOD_MSEC
, refillUpkeep
, m
);
2423 tr_peerMgrStartTorrent( tr_torrent
* tor
)
2425 Torrent
* t
= tor
->torrentPeers
;
2427 assert( tr_isTorrent( tor
) );
2428 assert( tr_torrentIsLocked( tor
) );
2430 ensureMgrTimersExist( t
->manager
);
2432 t
->isRunning
= true;
2433 t
->maxPeers
= t
->tor
->maxConnectedPeers
;
2434 t
->pieceSortState
= PIECES_UNSORTED
;
2436 rechokePulse( 0, 0, t
->manager
);
2440 stopTorrent( Torrent
* t
)
2444 t
->isRunning
= false;
2446 replicationFree( t
);
2447 invalidatePieceSorting( t
);
2449 /* disconnect the peers. */
2450 while(( peer
= tr_ptrArrayPop( &t
->peers
)))
2451 peerDelete( t
, peer
);
2453 /* disconnect the handshakes. handshakeAbort calls handshakeDoneCB(),
2454 * which removes the handshake from t->outgoingHandshakes... */
2455 while( !tr_ptrArrayEmpty( &t
->outgoingHandshakes
) )
2456 tr_handshakeAbort( tr_ptrArrayNth( &t
->outgoingHandshakes
, 0 ) );
2460 tr_peerMgrStopTorrent( tr_torrent
* tor
)
2462 assert( tr_isTorrent( tor
) );
2463 assert( tr_torrentIsLocked( tor
) );
2465 stopTorrent( tor
->torrentPeers
);
2469 tr_peerMgrAddTorrent( tr_peerMgr
* manager
, tr_torrent
* tor
)
2471 assert( tr_isTorrent( tor
) );
2472 assert( tr_torrentIsLocked( tor
) );
2473 assert( tor
->torrentPeers
== NULL
);
2475 tor
->torrentPeers
= torrentNew( manager
, tor
);
2479 tr_peerMgrRemoveTorrent( tr_torrent
* tor
)
2481 assert( tr_isTorrent( tor
) );
2482 assert( tr_torrentIsLocked( tor
) );
2484 stopTorrent( tor
->torrentPeers
);
2485 torrentFree( tor
->torrentPeers
);
2489 tr_peerUpdateProgress( tr_torrent
* tor
, tr_peer
* peer
)
2491 const tr_bitfield
* have
= &peer
->have
;
2493 if( tr_bitfieldHasAll( have
) )
2495 peer
->progress
= 1.0;
2497 else if( tr_bitfieldHasNone( have
) )
2499 peer
->progress
= 0.0;
2503 const float true_count
= tr_bitfieldCountTrueBits( have
);
2505 if( tr_torrentHasMetadata( tor
) )
2506 peer
->progress
= true_count
/ tor
->info
.pieceCount
;
2507 else /* without pieceCount, this result is only a best guess... */
2508 peer
->progress
= true_count
/ ( have
->bit_count
+ 1 );
2511 if( peer
->atom
&& ( peer
->progress
>= 1.0 ) )
2512 atomSetSeed( tor
->torrentPeers
, peer
->atom
);
2516 tr_peerMgrOnTorrentGotMetainfo( tr_torrent
* tor
)
2519 const int peerCount
= tr_ptrArraySize( &tor
->torrentPeers
->peers
);
2520 tr_peer
** peers
= (tr_peer
**) tr_ptrArrayBase( &tor
->torrentPeers
->peers
);
2522 /* some peer_msgs' progress fields may not be accurate if we
2523 didn't have the metadata before now... so refresh them all... */
2524 for( i
=0; i
<peerCount
; ++i
)
2525 tr_peerUpdateProgress( tor
, peers
[i
] );
2529 tr_peerMgrTorrentAvailability( const tr_torrent
* tor
, int8_t * tab
, unsigned int tabCount
)
2531 assert( tr_isTorrent( tor
) );
2532 assert( torrentIsLocked( tor
->torrentPeers
) );
2533 assert( tab
!= NULL
);
2534 assert( tabCount
> 0 );
2536 memset( tab
, 0, tabCount
);
2538 if( tr_torrentHasMetadata( tor
) )
2541 const int peerCount
= tr_ptrArraySize( &tor
->torrentPeers
->peers
);
2542 const tr_peer
** peers
= (const tr_peer
**) tr_ptrArrayBase( &tor
->torrentPeers
->peers
);
2543 const float interval
= tor
->info
.pieceCount
/ (float)tabCount
;
2544 const bool isSeed
= tr_cpGetStatus( &tor
->completion
) == TR_SEED
;
2546 for( i
=0; i
<tabCount
; ++i
)
2548 const int piece
= i
* interval
;
2550 if( isSeed
|| tr_cpPieceIsComplete( &tor
->completion
, piece
) )
2552 else if( peerCount
) {
2554 for( j
=0; j
<peerCount
; ++j
)
2555 if( tr_bitfieldHas( &peers
[j
]->have
, piece
) )
2563 peerIsSeed( const tr_peer
* peer
)
2565 if( peer
->progress
>= 1.0 )
2568 if( peer
->atom
&& atomIsSeed( peer
->atom
) )
2574 /* count how many bytes we want that connected peers have */
2576 tr_peerMgrGetDesiredAvailable( const tr_torrent
* tor
)
2580 uint64_t desiredAvailable
;
2581 const Torrent
* t
= tor
->torrentPeers
;
2583 /* common shortcuts... */
2585 if( tr_torrentIsSeed( t
->tor
) )
2588 if( !tr_torrentHasMetadata( tor
) )
2591 n
= tr_ptrArraySize( &t
->peers
);
2595 const tr_peer
** peers
= (const tr_peer
**) tr_ptrArrayBase( &t
->peers
);
2596 for( i
=0; i
<n
; ++i
)
2597 if( peers
[i
]->atom
&& atomIsSeed( peers
[i
]->atom
) )
2598 return tr_cpLeftUntilDone( &tor
->completion
);
2601 if( !t
->pieceReplication
|| !t
->pieceReplicationSize
)
2604 /* do it the hard way */
2606 desiredAvailable
= 0;
2607 for( i
=0, n
=MIN(tor
->info
.pieceCount
, t
->pieceReplicationSize
); i
<n
; ++i
)
2608 if( !tor
->info
.pieces
[i
].dnd
&& ( t
->pieceReplication
[i
] > 0 ) )
2609 desiredAvailable
+= tr_cpMissingBytesInPiece( &t
->tor
->completion
, i
);
2611 assert( desiredAvailable
<= tor
->info
.totalSize
);
2612 return desiredAvailable
;
2616 tr_peerMgrTorrentStats( tr_torrent
* tor
,
2617 int * setmePeersConnected
,
2618 int * setmeWebseedsSendingToUs
,
2619 int * setmePeersSendingToUs
,
2620 int * setmePeersGettingFromUs
,
2621 int * setmePeersFrom
)
2624 const Torrent
* t
= tor
->torrentPeers
;
2625 const tr_peer
** peers
;
2627 assert( tr_torrentIsLocked( tor
) );
2629 peers
= (const tr_peer
**) tr_ptrArrayBase( &t
->peers
);
2630 size
= tr_ptrArraySize( &t
->peers
);
2632 *setmePeersConnected
= 0;
2633 *setmePeersGettingFromUs
= 0;
2634 *setmePeersSendingToUs
= 0;
2635 *setmeWebseedsSendingToUs
= 0;
2637 for( i
=0; i
<TR_PEER_FROM__MAX
; ++i
)
2638 setmePeersFrom
[i
] = 0;
2640 for( i
=0; i
<size
; ++i
)
2642 const tr_peer
* peer
= peers
[i
];
2643 const struct peer_atom
* atom
= peer
->atom
;
2645 if( peer
->io
== NULL
) /* not connected */
2648 ++*setmePeersConnected
;
2650 ++setmePeersFrom
[atom
->fromFirst
];
2652 if( clientIsDownloadingFrom( tor
, peer
) )
2653 ++*setmePeersSendingToUs
;
2655 if( clientIsUploadingTo( peer
) )
2656 ++*setmePeersGettingFromUs
;
2659 *setmeWebseedsSendingToUs
= countActiveWebseeds( t
);
2663 tr_peerMgrWebSpeeds_KBps( const tr_torrent
* tor
)
2666 const Torrent
* t
= tor
->torrentPeers
;
2667 const int webseedCount
= tr_ptrArraySize( &t
->webseeds
);
2668 const tr_webseed
** webseeds
= (const tr_webseed
**) tr_ptrArrayBase( &t
->webseeds
);
2669 const uint64_t now
= tr_time_msec( );
2670 double * ret
= tr_new0( double, webseedCount
);
2672 assert( tr_isTorrent( tor
) );
2673 assert( tr_torrentIsLocked( tor
) );
2674 assert( t
->manager
!= NULL
);
2675 assert( webseedCount
== tor
->info
.webseedCount
);
2677 for( i
=0; i
<webseedCount
; ++i
) {
2679 if( tr_webseedGetSpeed_Bps( webseeds
[i
], now
, &Bps
) )
2680 ret
[i
] = Bps
/ (double)tr_speed_K
;
2689 tr_peerGetPieceSpeed_Bps( const tr_peer
* peer
, uint64_t now
, tr_direction direction
)
2691 return peer
->io
? tr_peerIoGetPieceSpeed_Bps( peer
->io
, now
, direction
) : 0.0;
2694 struct tr_peer_stat
*
2695 tr_peerMgrPeerStats( const tr_torrent
* tor
, int * setmeCount
)
2698 const Torrent
* t
= tor
->torrentPeers
;
2699 const int size
= tr_ptrArraySize( &t
->peers
);
2700 const tr_peer
** peers
= (const tr_peer
**) tr_ptrArrayBase( &t
->peers
);
2701 const uint64_t now_msec
= tr_time_msec( );
2702 const time_t now
= tr_time();
2703 tr_peer_stat
* ret
= tr_new0( tr_peer_stat
, size
);
2705 assert( tr_isTorrent( tor
) );
2706 assert( tr_torrentIsLocked( tor
) );
2707 assert( t
->manager
);
2709 for( i
=0; i
<size
; ++i
)
2712 const tr_peer
* peer
= peers
[i
];
2713 const struct peer_atom
* atom
= peer
->atom
;
2714 tr_peer_stat
* stat
= ret
+ i
;
2716 tr_address_to_string_with_buf( &atom
->addr
, stat
->addr
, sizeof( stat
->addr
) );
2717 tr_strlcpy( stat
->client
, ( peer
->client
? peer
->client
: "" ),
2718 sizeof( stat
->client
) );
2719 stat
->port
= ntohs( peer
->atom
->port
);
2720 stat
->from
= atom
->fromFirst
;
2721 stat
->progress
= peer
->progress
;
2722 stat
->isUTP
= peer
->io
->utp_socket
!= NULL
;
2723 stat
->isEncrypted
= tr_peerIoIsEncrypted( peer
->io
) ? 1 : 0;
2724 stat
->rateToPeer_KBps
= toSpeedKBps( tr_peerGetPieceSpeed_Bps( peer
, now_msec
, TR_CLIENT_TO_PEER
) );
2725 stat
->rateToClient_KBps
= toSpeedKBps( tr_peerGetPieceSpeed_Bps( peer
, now_msec
, TR_PEER_TO_CLIENT
) );
2726 stat
->peerIsChoked
= peer
->peerIsChoked
;
2727 stat
->peerIsInterested
= peer
->peerIsInterested
;
2728 stat
->clientIsChoked
= peer
->clientIsChoked
;
2729 stat
->clientIsInterested
= peer
->clientIsInterested
;
2730 stat
->isIncoming
= tr_peerIoIsIncoming( peer
->io
);
2731 stat
->isDownloadingFrom
= clientIsDownloadingFrom( tor
, peer
);
2732 stat
->isUploadingTo
= clientIsUploadingTo( peer
);
2733 stat
->isSeed
= peerIsSeed( peer
);
2735 stat
->blocksToPeer
= tr_historyGet( &peer
->blocksSentToPeer
, now
, CANCEL_HISTORY_SEC
);
2736 stat
->blocksToClient
= tr_historyGet( &peer
->blocksSentToClient
, now
, CANCEL_HISTORY_SEC
);
2737 stat
->cancelsToPeer
= tr_historyGet( &peer
->cancelsSentToPeer
, now
, CANCEL_HISTORY_SEC
);
2738 stat
->cancelsToClient
= tr_historyGet( &peer
->cancelsSentToClient
, now
, CANCEL_HISTORY_SEC
);
2740 stat
->pendingReqsToPeer
= peer
->pendingReqsToPeer
;
2741 stat
->pendingReqsToClient
= peer
->pendingReqsToClient
;
2743 pch
= stat
->flagStr
;
2744 if( stat
->isUTP
) *pch
++ = 'T';
2745 if( t
->optimistic
== peer
) *pch
++ = 'O';
2746 if( stat
->isDownloadingFrom
) *pch
++ = 'D';
2747 else if( stat
->clientIsInterested
) *pch
++ = 'd';
2748 if( stat
->isUploadingTo
) *pch
++ = 'U';
2749 else if( stat
->peerIsInterested
) *pch
++ = 'u';
2750 if( !stat
->clientIsChoked
&& !stat
->clientIsInterested
) *pch
++ = 'K';
2751 if( !stat
->peerIsChoked
&& !stat
->peerIsInterested
) *pch
++ = '?';
2752 if( stat
->isEncrypted
) *pch
++ = 'E';
2753 if( stat
->from
== TR_PEER_FROM_DHT
) *pch
++ = 'H';
2754 else if( stat
->from
== TR_PEER_FROM_PEX
) *pch
++ = 'X';
2755 if( stat
->isIncoming
) *pch
++ = 'I';
2770 tr_peerMgrClearInterest( tr_torrent
* tor
)
2773 Torrent
* t
= tor
->torrentPeers
;
2774 const int peerCount
= tr_ptrArraySize( &t
->peers
);
2776 assert( tr_isTorrent( tor
) );
2777 assert( tr_torrentIsLocked( tor
) );
2779 for( i
=0; i
<peerCount
; ++i
)
2781 const tr_peer
* peer
= tr_ptrArrayNth( &t
->peers
, i
);
2782 tr_peerMsgsSetInterested( peer
->msgs
, false );
2786 /* does this peer have any pieces that we want? */
2788 isPeerInteresting( const tr_torrent
* const tor
,
2789 const tr_bitfield
* const interesting_pieces
,
2790 const tr_peer
* const peer
)
2792 tr_piece_index_t i
, n
;
2794 /* these cases should have already been handled by the calling code... */
2795 assert( !tr_torrentIsSeed( tor
) );
2796 assert( tr_torrentIsPieceTransferAllowed( tor
, TR_PEER_TO_CLIENT
) );
2798 if( peerIsSeed( peer
) )
2801 for( i
=0, n
=tor
->info
.pieceCount
; i
<n
; ++i
)
2802 if( tr_bitfieldHas( interesting_pieces
, i
) && tr_bitfieldHas( &peer
->have
, i
) )
2811 RECHOKE_STATE_UNTESTED
,
2816 struct tr_rechoke_info
2824 compare_rechoke_info( const void * va
, const void * vb
)
2826 const struct tr_rechoke_info
* a
= va
;
2827 const struct tr_rechoke_info
* b
= vb
;
2829 if( a
->rechoke_state
!= b
->rechoke_state
)
2830 return a
->rechoke_state
- b
->rechoke_state
;
2832 return a
->salt
- b
->salt
;
2835 /* determines who we send "interested" messages to */
2837 rechokeDownloads( Torrent
* t
)
2841 int rechoke_count
= 0;
2842 struct tr_rechoke_info
* rechoke
= NULL
;
2843 const int MIN_INTERESTING_PEERS
= 5;
2844 const int peerCount
= tr_ptrArraySize( &t
->peers
);
2845 const time_t now
= tr_time( );
2847 /* some cases where this function isn't necessary */
2848 if( tr_torrentIsSeed( t
->tor
) )
2850 if ( !tr_torrentIsPieceTransferAllowed( t
->tor
, TR_PEER_TO_CLIENT
) )
2853 /* decide HOW MANY peers to be interested in */
2857 time_t timeSinceCancel
;
2859 /* Count up how many blocks & cancels each peer has.
2861 * There are two situations where we send out cancels --
2863 * 1. We've got unresponsive peers, which is handled by deciding
2864 * -which- peers to be interested in.
2866 * 2. We've hit our bandwidth cap, which is handled by deciding
2867 * -how many- peers to be interested in.
2869 * We're working on 2. here, so we need to ignore unresponsive
2870 * peers in our calculations lest they confuse Transmission into
2871 * thinking it's hit its bandwidth cap.
2873 for( i
=0; i
<peerCount
; ++i
)
2875 const tr_peer
* peer
= tr_ptrArrayNth( &t
->peers
, i
);
2876 const int b
= tr_historyGet( &peer
->blocksSentToClient
, now
, CANCEL_HISTORY_SEC
);
2877 const int c
= tr_historyGet( &peer
->cancelsSentToPeer
, now
, CANCEL_HISTORY_SEC
);
2879 if( b
== 0 ) /* ignore unresponsive peers, as described above */
2888 /* cancelRate: of the block requests we've recently made, the percentage we cancelled.
2889 * higher values indicate more congestion. */
2890 const double cancelRate
= cancels
/ (double)(cancels
+ blocks
);
2891 const double mult
= 1 - MIN( cancelRate
, 0.5 );
2892 maxPeers
= t
->interestedCount
* mult
;
2893 tordbg( t
, "cancel rate is %.3f -- reducing the "
2894 "number of peers we're interested in by %.0f percent",
2895 cancelRate
, mult
* 100 );
2896 t
->lastCancel
= now
;
2899 timeSinceCancel
= now
- t
->lastCancel
;
2900 if( timeSinceCancel
)
2902 const int maxIncrease
= 15;
2903 const time_t maxHistory
= 2 * CANCEL_HISTORY_SEC
;
2904 const double mult
= MIN( timeSinceCancel
, maxHistory
) / (double) maxHistory
;
2905 const int inc
= maxIncrease
* mult
;
2906 maxPeers
= t
->maxPeers
+ inc
;
2907 tordbg( t
, "time since last cancel is %li -- increasing the "
2908 "number of peers we're interested in by %d",
2909 timeSinceCancel
, inc
);
2913 /* don't let the previous section's number tweaking go too far... */
2914 if( maxPeers
< MIN_INTERESTING_PEERS
)
2915 maxPeers
= MIN_INTERESTING_PEERS
;
2916 if( maxPeers
> t
->tor
->maxConnectedPeers
)
2917 maxPeers
= t
->tor
->maxConnectedPeers
;
2919 t
->maxPeers
= maxPeers
;
2923 const tr_torrent
* const tor
= t
->tor
;
2924 const int n
= tor
->info
.pieceCount
;
2925 tr_bitfield interesting_pieces
= TR_BITFIELD_INIT
;
2927 /* build a bitfield of interesting pieces... */
2928 tr_bitfieldConstruct( &interesting_pieces
, n
);
2929 for( i
=0; i
<n
; i
++ )
2930 if( !tor
->info
.pieces
[i
].dnd
&& !tr_cpPieceIsComplete( &tor
->completion
, i
) )
2931 tr_bitfieldAdd( &interesting_pieces
, i
);
2933 /* decide WHICH peers to be interested in (based on their cancel-to-block ratio) */
2934 for( i
=0; i
<peerCount
; ++i
)
2936 tr_peer
* peer
= tr_ptrArrayNth( &t
->peers
, i
);
2938 if( !isPeerInteresting( t
->tor
, &interesting_pieces
, peer
) )
2940 tr_peerMsgsSetInterested( peer
->msgs
, false );
2944 tr_rechoke_state rechoke_state
;
2945 const int blocks
= tr_historyGet( &peer
->blocksSentToClient
, now
, CANCEL_HISTORY_SEC
);
2946 const int cancels
= tr_historyGet( &peer
->cancelsSentToPeer
, now
, CANCEL_HISTORY_SEC
);
2948 if( !blocks
&& !cancels
)
2949 rechoke_state
= RECHOKE_STATE_UNTESTED
;
2951 rechoke_state
= RECHOKE_STATE_GOOD
;
2953 rechoke_state
= RECHOKE_STATE_BAD
;
2954 else if( ( cancels
* 10 ) < blocks
)
2955 rechoke_state
= RECHOKE_STATE_GOOD
;
2957 rechoke_state
= RECHOKE_STATE_BAD
;
2959 if( rechoke
== NULL
)
2960 rechoke
= tr_new( struct tr_rechoke_info
, peerCount
);
2962 rechoke
[rechoke_count
].peer
= peer
;
2963 rechoke
[rechoke_count
].rechoke_state
= rechoke_state
;
2964 rechoke
[rechoke_count
].salt
= tr_cryptoWeakRandInt( INT_MAX
);
2970 tr_bitfieldDestruct( &interesting_pieces
);
2973 /* now that we know which & how many peers to be interested in... update the peer interest */
2974 qsort( rechoke
, rechoke_count
, sizeof( struct tr_rechoke_info
), compare_rechoke_info
);
2975 t
->interestedCount
= MIN( maxPeers
, rechoke_count
);
2976 for( i
=0; i
<rechoke_count
; ++i
)
2977 tr_peerMsgsSetInterested( rechoke
[i
].peer
->msgs
, i
<t
->interestedCount
);
2998 compareChoke( const void * va
, const void * vb
)
3000 const struct ChokeData
* a
= va
;
3001 const struct ChokeData
* b
= vb
;
3003 if( a
->rate
!= b
->rate
) /* prefer higher overall speeds */
3004 return a
->rate
> b
->rate
? -1 : 1;
3006 if( a
->wasChoked
!= b
->wasChoked
) /* prefer unchoked */
3007 return a
->wasChoked
? 1 : -1;
3009 if( a
->salt
!= b
->salt
) /* random order */
3010 return a
->salt
- b
->salt
;
3015 /* is this a new connection? */
3017 isNew( const tr_peer
* peer
)
3019 return peer
&& peer
->io
&& tr_peerIoGetAge( peer
->io
) < 45;
3022 /* get a rate for deciding which peers to choke and unchoke. */
3024 getRate( const tr_torrent
* tor
, struct peer_atom
* atom
, uint64_t now
)
3028 if( tr_torrentIsSeed( tor
) )
3029 Bps
= tr_peerGetPieceSpeed_Bps( atom
->peer
, now
, TR_CLIENT_TO_PEER
);
3031 /* downloading a private torrent... take upload speed into account
3032 * because there may only be a small window of opportunity to share */
3033 else if( tr_torrentIsPrivate( tor
) )
3034 Bps
= tr_peerGetPieceSpeed_Bps( atom
->peer
, now
, TR_PEER_TO_CLIENT
)
3035 + tr_peerGetPieceSpeed_Bps( atom
->peer
, now
, TR_CLIENT_TO_PEER
);
3037 /* downloading a public torrent */
3039 Bps
= tr_peerGetPieceSpeed_Bps( atom
->peer
, now
, TR_PEER_TO_CLIENT
);
3041 /* convert it to bytes per second */
3046 isBandwidthMaxedOut( const tr_bandwidth
* b
,
3047 const uint64_t now_msec
, tr_direction dir
)
3049 if( !tr_bandwidthIsLimited( b
, dir
) )
3052 const int got
= tr_bandwidthGetPieceSpeed_Bps( b
, now_msec
, dir
);
3053 const int want
= tr_bandwidthGetDesiredSpeed_Bps( b
, dir
);
3059 rechokeUploads( Torrent
* t
, const uint64_t now
)
3061 int i
, size
, unchokedInterested
;
3062 const int peerCount
= tr_ptrArraySize( &t
->peers
);
3063 tr_peer
** peers
= (tr_peer
**) tr_ptrArrayBase( &t
->peers
);
3064 struct ChokeData
* choke
= tr_new0( struct ChokeData
, peerCount
);
3065 const tr_session
* session
= t
->manager
->session
;
3066 const int chokeAll
= !tr_torrentIsPieceTransferAllowed( t
->tor
, TR_CLIENT_TO_PEER
);
3067 const bool isMaxedOut
= isBandwidthMaxedOut( &t
->tor
->bandwidth
, now
, TR_UP
);
3069 assert( torrentIsLocked( t
) );
3071 /* an optimistic unchoke peer's "optimistic"
3072 * state lasts for N calls to rechokeUploads(). */
3073 if( t
->optimisticUnchokeTimeScaler
> 0 )
3074 t
->optimisticUnchokeTimeScaler
--;
3076 t
->optimistic
= NULL
;
3078 /* sort the peers by preference and rate */
3079 for( i
= 0, size
= 0; i
< peerCount
; ++i
)
3081 tr_peer
* peer
= peers
[i
];
3082 struct peer_atom
* atom
= peer
->atom
;
3084 if( peerIsSeed( peer
) ) /* choke seeds and partial seeds */
3086 tr_peerMsgsSetChoke( peer
->msgs
, true );
3088 else if( chokeAll
) /* choke everyone if we're not uploading */
3090 tr_peerMsgsSetChoke( peer
->msgs
, true );
3092 else if( peer
!= t
->optimistic
)
3094 struct ChokeData
* n
= &choke
[size
++];
3096 n
->isInterested
= peer
->peerIsInterested
;
3097 n
->wasChoked
= peer
->peerIsChoked
;
3098 n
->rate
= getRate( t
->tor
, atom
, now
);
3099 n
->salt
= tr_cryptoWeakRandInt( INT_MAX
);
3104 qsort( choke
, size
, sizeof( struct ChokeData
), compareChoke
);
3107 * Reciprocation and number of uploads capping is managed by unchoking
3108 * the N peers which have the best upload rate and are interested.
3109 * This maximizes the client's download rate. These N peers are
3110 * referred to as downloaders, because they are interested in downloading
3113 * Peers which have a better upload rate (as compared to the downloaders)
3114 * but aren't interested get unchoked. If they become interested, the
3115 * downloader with the worst upload rate gets choked. If a client has
3116 * a complete file, it uses its upload rate rather than its download
3117 * rate to decide which peers to unchoke.
3119 * If our bandwidth is maxed out, don't unchoke any more peers.
3121 unchokedInterested
= 0;
3122 for( i
=0; i
<size
&& unchokedInterested
<session
->uploadSlotsPerTorrent
; ++i
) {
3123 choke
[i
].isChoked
= isMaxedOut
? choke
[i
].wasChoked
: false;
3124 if( choke
[i
].isInterested
)
3125 ++unchokedInterested
;
3128 /* optimistic unchoke */
3129 if( !t
->optimistic
&& !isMaxedOut
&& (i
<size
) )
3132 struct ChokeData
* c
;
3133 tr_ptrArray randPool
= TR_PTR_ARRAY_INIT
;
3135 for( ; i
<size
; ++i
)
3137 if( choke
[i
].isInterested
)
3139 const tr_peer
* peer
= choke
[i
].peer
;
3141 if( isNew( peer
) ) x
*= 3;
3142 for( y
=0; y
<x
; ++y
)
3143 tr_ptrArrayAppend( &randPool
, &choke
[i
] );
3147 if(( n
= tr_ptrArraySize( &randPool
)))
3149 c
= tr_ptrArrayNth( &randPool
, tr_cryptoWeakRandInt( n
));
3150 c
->isChoked
= false;
3151 t
->optimistic
= c
->peer
;
3152 t
->optimisticUnchokeTimeScaler
= OPTIMISTIC_UNCHOKE_MULTIPLIER
;
3155 tr_ptrArrayDestruct( &randPool
, NULL
);
3158 for( i
=0; i
<size
; ++i
)
3159 tr_peerMsgsSetChoke( choke
[i
].peer
->msgs
, choke
[i
].isChoked
);
3166 rechokePulse( int foo UNUSED
, short bar UNUSED
, void * vmgr
)
3168 tr_torrent
* tor
= NULL
;
3169 tr_peerMgr
* mgr
= vmgr
;
3170 const uint64_t now
= tr_time_msec( );
3174 while(( tor
= tr_torrentNext( mgr
->session
, tor
))) {
3175 if( tor
->isRunning
) {
3176 Torrent
* t
= tor
->torrentPeers
;
3177 if( !tr_ptrArrayEmpty( &t
->peers
) ) {
3178 rechokeUploads( t
, now
);
3179 rechokeDownloads( t
);
3184 tr_timerAddMsec( mgr
->rechokeTimer
, RECHOKE_PERIOD_MSEC
);
3185 managerUnlock( mgr
);
3195 shouldPeerBeClosed( const Torrent
* t
,
3196 const tr_peer
* peer
,
3200 const tr_torrent
* tor
= t
->tor
;
3201 const struct peer_atom
* atom
= peer
->atom
;
3203 /* if it's marked for purging, close it */
3206 tordbg( t
, "purging peer %s because its doPurge flag is set",
3207 tr_atomAddrStr( atom
) );
3211 /* disconnect if we're both seeds and enough time has passed for PEX */
3212 if( tr_torrentIsSeed( tor
) && peerIsSeed( peer
) )
3213 return !tr_torrentAllowsPex(tor
) || (now
-atom
->time
>=30);
3215 /* disconnect if it's been too long since piece data has been transferred.
3216 * this is on a sliding scale based on number of available peers... */
3218 const int relaxStrictnessIfFewerThanN
= (int)( ( getMaxPeerCount( tor
) * 0.9 ) + 0.5 );
3219 /* if we have >= relaxIfFewerThan, strictness is 100%.
3220 * if we have zero connections, strictness is 0% */
3221 const float strictness
= peerCount
>= relaxStrictnessIfFewerThanN
3223 : peerCount
/ (float)relaxStrictnessIfFewerThanN
;
3224 const int lo
= MIN_UPLOAD_IDLE_SECS
;
3225 const int hi
= MAX_UPLOAD_IDLE_SECS
;
3226 const int limit
= hi
- ( ( hi
- lo
) * strictness
);
3227 const int idleTime
= now
- MAX( atom
->time
, atom
->piece_data_time
);
3228 /*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 );*/
3229 if( idleTime
> limit
) {
3230 tordbg( t
, "purging peer %s because it's been %d secs since we shared anything",
3231 tr_atomAddrStr( atom
), idleTime
);
3240 getPeersToClose( Torrent
* t
, const time_t now_sec
, int * setmeSize
)
3242 int i
, peerCount
, outsize
;
3243 struct tr_peer
** ret
= NULL
;
3244 tr_peer
** peers
= (tr_peer
**) tr_ptrArrayPeek( &t
->peers
, &peerCount
);
3246 assert( torrentIsLocked( t
) );
3248 for( i
= outsize
= 0; i
< peerCount
; ++i
) {
3249 if( shouldPeerBeClosed( t
, peers
[i
], peerCount
, now_sec
) ) {
3251 ret
= tr_new( tr_peer
*, peerCount
);
3252 ret
[outsize
++] = peers
[i
];
3256 *setmeSize
= outsize
;
3261 getReconnectIntervalSecs( const struct peer_atom
* atom
, const time_t now
)
3265 /* if we were recently connected to this peer and transferring piece
3266 * data, try to reconnect to them sooner rather that later -- we don't
3267 * want network troubles to get in the way of a good peer. */
3268 if( ( now
- atom
->piece_data_time
) <= ( MINIMUM_RECONNECT_INTERVAL_SECS
* 2 ) )
3269 sec
= MINIMUM_RECONNECT_INTERVAL_SECS
;
3271 /* don't allow reconnects more often than our minimum */
3272 else if( ( now
- atom
->time
) < MINIMUM_RECONNECT_INTERVAL_SECS
)
3273 sec
= MINIMUM_RECONNECT_INTERVAL_SECS
;
3275 /* otherwise, the interval depends on how many times we've tried
3276 * and failed to connect to the peer */
3277 else switch( atom
->numFails
) {
3278 case 0: sec
= 0; break;
3279 case 1: sec
= 5; break;
3280 case 2: sec
= 2 * 60; break;
3281 case 3: sec
= 15 * 60; break;
3282 case 4: sec
= 30 * 60; break;
3283 case 5: sec
= 60 * 60; break;
3284 default: sec
= 120 * 60; break;
3287 /* penalize peers that were unreachable the last time we tried */
3288 if( atom
->flags2
& MYFLAG_UNREACHABLE
)
3291 dbgmsg( "reconnect interval for %s is %d seconds", tr_atomAddrStr( atom
), sec
);
3296 removePeer( Torrent
* t
, tr_peer
* peer
)
3299 struct peer_atom
* atom
= peer
->atom
;
3301 assert( torrentIsLocked( t
) );
3304 atom
->time
= tr_time( );
3306 removed
= tr_ptrArrayRemoveSorted( &t
->peers
, peer
, peerCompare
);
3308 if( replicationExists( t
) )
3309 tr_decrReplicationFromBitfield( t
, &peer
->have
);
3311 assert( removed
== peer
);
3312 peerDelete( t
, removed
);
3316 closePeer( Torrent
* t
, tr_peer
* peer
)
3318 struct peer_atom
* atom
;
3320 assert( t
!= NULL
);
3321 assert( peer
!= NULL
);
3325 /* if we transferred piece data, then they might be good peers,
3326 so reset their `numFails' weight to zero. otherwise we connected
3327 to them fruitlessly, so mark it as another fail */
3328 if( atom
->piece_data_time
) {
3329 tordbg( t
, "resetting atom %s numFails to 0", tr_atomAddrStr(atom
) );
3333 tordbg( t
, "incremented atom %s numFails to %d", tr_atomAddrStr(atom
), (int)atom
->numFails
);
3336 tordbg( t
, "removing bad peer %s", tr_peerIoGetAddrStr( peer
->io
) );
3337 removePeer( t
, peer
);
3341 removeAllPeers( Torrent
* t
)
3343 while( !tr_ptrArrayEmpty( &t
->peers
) )
3344 removePeer( t
, tr_ptrArrayNth( &t
->peers
, 0 ) );
3348 closeBadPeers( Torrent
* t
, const time_t now_sec
)
3350 if( !tr_ptrArrayEmpty( &t
->peers
) )
3354 struct tr_peer
** peers
= getPeersToClose( t
, now_sec
, &peerCount
);
3355 for( i
=0; i
<peerCount
; ++i
)
3356 closePeer( t
, peers
[i
] );
3361 struct peer_liveliness
3365 time_t pieceDataTime
;
3372 comparePeerLiveliness( const void * va
, const void * vb
)
3374 const struct peer_liveliness
* a
= va
;
3375 const struct peer_liveliness
* b
= vb
;
3377 if( a
->doPurge
!= b
->doPurge
)
3378 return a
->doPurge
? 1 : -1;
3380 if( a
->speed
!= b
->speed
) /* faster goes first */
3381 return a
->speed
> b
->speed
? -1 : 1;
3383 /* the one to give us data more recently goes first */
3384 if( a
->pieceDataTime
!= b
->pieceDataTime
)
3385 return a
->pieceDataTime
> b
->pieceDataTime
? -1 : 1;
3387 /* the one we connected to most recently goes first */
3388 if( a
->time
!= b
->time
)
3389 return a
->time
> b
->time
? -1 : 1;
3395 sortPeersByLivelinessImpl( tr_peer
** peers
,
3399 int (*compare
) ( const void *va
, const void *vb
) )
3402 struct peer_liveliness
*lives
, *l
;
3404 /* build a sortable array of peer + extra info */
3405 lives
= l
= tr_new0( struct peer_liveliness
, n
);
3406 for( i
=0; i
<n
; ++i
, ++l
)
3408 tr_peer
* p
= peers
[i
];
3410 l
->doPurge
= p
->doPurge
;
3411 l
->pieceDataTime
= p
->atom
->piece_data_time
;
3412 l
->time
= p
->atom
->time
;
3413 l
->speed
= tr_peerGetPieceSpeed_Bps( p
, now
, TR_UP
)
3414 + tr_peerGetPieceSpeed_Bps( p
, now
, TR_DOWN
);
3416 l
->clientData
= clientData
[i
];
3420 assert( n
== ( l
- lives
) );
3421 qsort( lives
, n
, sizeof( struct peer_liveliness
), compare
);
3423 /* build the peer array */
3424 for( i
=0, l
=lives
; i
<n
; ++i
, ++l
) {
3427 clientData
[i
] = l
->clientData
;
3429 assert( n
== ( l
- lives
) );
3436 sortPeersByLiveliness( tr_peer
** peers
, void ** clientData
, int n
, uint64_t now
)
3438 sortPeersByLivelinessImpl( peers
, clientData
, n
, now
, comparePeerLiveliness
);
3443 enforceTorrentPeerLimit( Torrent
* t
, uint64_t now
)
3445 int n
= tr_ptrArraySize( &t
->peers
);
3446 const int max
= tr_torrentGetPeerLimit( t
->tor
);
3449 void * base
= tr_ptrArrayBase( &t
->peers
);
3450 tr_peer
** peers
= tr_memdup( base
, n
*sizeof( tr_peer
* ) );
3451 sortPeersByLiveliness( peers
, NULL
, n
, now
);
3453 closePeer( t
, peers
[--n
] );
3459 enforceSessionPeerLimit( tr_session
* session
, uint64_t now
)
3462 tr_torrent
* tor
= NULL
;
3463 const int max
= tr_sessionGetPeerLimit( session
);
3465 /* count the total number of peers */
3466 while(( tor
= tr_torrentNext( session
, tor
)))
3467 n
+= tr_ptrArraySize( &tor
->torrentPeers
->peers
);
3469 /* if there are too many, prune out the worst */
3472 tr_peer
** peers
= tr_new( tr_peer
*, n
);
3473 Torrent
** torrents
= tr_new( Torrent
*, n
);
3475 /* populate the peer array */
3478 while(( tor
= tr_torrentNext( session
, tor
))) {
3480 Torrent
* t
= tor
->torrentPeers
;
3481 const int tn
= tr_ptrArraySize( &t
->peers
);
3482 for( i
=0; i
<tn
; ++i
, ++n
) {
3483 peers
[n
] = tr_ptrArrayNth( &t
->peers
, i
);
3489 sortPeersByLiveliness( peers
, (void**)torrents
, n
, now
);
3491 /* cull out the crappiest */
3493 closePeer( torrents
[n
], peers
[n
] );
3496 tr_free( torrents
);
3501 static void makeNewPeerConnections( tr_peerMgr
* mgr
, const int max
);
3504 reconnectPulse( int foo UNUSED
, short bar UNUSED
, void * vmgr
)
3507 tr_peerMgr
* mgr
= vmgr
;
3508 const time_t now_sec
= tr_time( );
3509 const uint64_t now_msec
= tr_time_msec( );
3512 *** enforce the per-session and per-torrent peer limits
3515 /* if we're over the per-torrent peer limits, cull some peers */
3517 while(( tor
= tr_torrentNext( mgr
->session
, tor
)))
3518 if( tor
->isRunning
)
3519 enforceTorrentPeerLimit( tor
->torrentPeers
, now_msec
);
3521 /* if we're over the per-session peer limits, cull some peers */
3522 enforceSessionPeerLimit( mgr
->session
, now_msec
);
3524 /* remove crappy peers */
3526 while(( tor
= tr_torrentNext( mgr
->session
, tor
)))
3527 if( !tor
->torrentPeers
->isRunning
)
3528 removeAllPeers( tor
->torrentPeers
);
3530 closeBadPeers( tor
->torrentPeers
, now_sec
);
3532 /* try to make new peer connections */
3533 makeNewPeerConnections( mgr
, MAX_CONNECTIONS_PER_PULSE
);
3538 ***** BANDWIDTH ALLOCATION
3543 pumpAllPeers( tr_peerMgr
* mgr
)
3545 tr_torrent
* tor
= NULL
;
3547 while(( tor
= tr_torrentNext( mgr
->session
, tor
)))
3550 Torrent
* t
= tor
->torrentPeers
;
3552 for( j
=0; j
<tr_ptrArraySize( &t
->peers
); ++j
)
3554 tr_peer
* peer
= tr_ptrArrayNth( &t
->peers
, j
);
3555 tr_peerMsgsPulse( peer
->msgs
);
3561 bandwidthPulse( int foo UNUSED
, short bar UNUSED
, void * vmgr
)
3564 tr_peerMgr
* mgr
= vmgr
;
3567 /* FIXME: this next line probably isn't necessary... */
3568 pumpAllPeers( mgr
);
3570 /* allocate bandwidth to the peers */
3571 tr_bandwidthAllocate( &mgr
->session
->bandwidth
, TR_UP
, BANDWIDTH_PERIOD_MSEC
);
3572 tr_bandwidthAllocate( &mgr
->session
->bandwidth
, TR_DOWN
, BANDWIDTH_PERIOD_MSEC
);
3574 /* torrent upkeep */
3576 while(( tor
= tr_torrentNext( mgr
->session
, tor
)))
3578 /* possibly stop torrents that have seeded enough */
3579 tr_torrentCheckSeedLimit( tor
);
3581 /* run the completeness check for any torrents that need it */
3582 if( tor
->torrentPeers
->needsCompletenessCheck
) {
3583 tor
->torrentPeers
->needsCompletenessCheck
= false;
3584 tr_torrentRecheckCompleteness( tor
);
3587 /* stop torrents that are ready to stop, but couldn't be stopped
3588 earlier during the peer-io callback call chain */
3589 if( tor
->isStopping
)
3590 tr_torrentStop( tor
);
3593 reconnectPulse( 0, 0, mgr
);
3595 tr_timerAddMsec( mgr
->bandwidthTimer
, BANDWIDTH_PERIOD_MSEC
);
3596 managerUnlock( mgr
);
3604 compareAtomPtrsByAddress( const void * va
, const void *vb
)
3606 const struct peer_atom
* a
= * (const struct peer_atom
**) va
;
3607 const struct peer_atom
* b
= * (const struct peer_atom
**) vb
;
3609 assert( tr_isAtom( a
) );
3610 assert( tr_isAtom( b
) );
3612 return tr_address_compare( &a
->addr
, &b
->addr
);
3615 /* best come first, worst go last */
3617 compareAtomPtrsByShelfDate( const void * va
, const void *vb
)
3621 const struct peer_atom
* a
= * (const struct peer_atom
**) va
;
3622 const struct peer_atom
* b
= * (const struct peer_atom
**) vb
;
3623 const int data_time_cutoff_secs
= 60 * 60;
3624 const time_t tr_now
= tr_time( );
3626 assert( tr_isAtom( a
) );
3627 assert( tr_isAtom( b
) );
3629 /* primary key: the last piece data time *if* it was within the last hour */
3630 atime
= a
->piece_data_time
; if( atime
+ data_time_cutoff_secs
< tr_now
) atime
= 0;
3631 btime
= b
->piece_data_time
; if( btime
+ data_time_cutoff_secs
< tr_now
) btime
= 0;
3632 if( atime
!= btime
)
3633 return atime
> btime
? -1 : 1;
3635 /* secondary key: shelf date. */
3636 if( a
->shelf_date
!= b
->shelf_date
)
3637 return a
->shelf_date
> b
->shelf_date
? -1 : 1;
3643 getMaxAtomCount( const tr_torrent
* tor
)
3645 const int n
= tor
->maxConnectedPeers
;
3646 /* approximate fit of the old jump discontinuous function */
3647 if( n
>= 55 ) return n
+ 150;
3648 if( n
>= 20 ) return 2 * n
+ 95;
3653 atomPulse( int foo UNUSED
, short bar UNUSED
, void * vmgr
)
3655 tr_torrent
* tor
= NULL
;
3656 tr_peerMgr
* mgr
= vmgr
;
3659 while(( tor
= tr_torrentNext( mgr
->session
, tor
)))
3662 Torrent
* t
= tor
->torrentPeers
;
3663 const int maxAtomCount
= getMaxAtomCount( tor
);
3664 struct peer_atom
** atoms
= (struct peer_atom
**) tr_ptrArrayPeek( &t
->pool
, &atomCount
);
3666 if( atomCount
> maxAtomCount
) /* we've got too many atoms... time to prune */
3671 struct peer_atom
** keep
= tr_new( struct peer_atom
*, atomCount
);
3672 struct peer_atom
** test
= tr_new( struct peer_atom
*, atomCount
);
3674 /* keep the ones that are in use */
3675 for( i
=0; i
<atomCount
; ++i
) {
3676 struct peer_atom
* atom
= atoms
[i
];
3677 if( peerIsInUse( t
, atom
) )
3678 keep
[keepCount
++] = atom
;
3680 test
[testCount
++] = atom
;
3683 /* if there's room, keep the best of what's left */
3685 if( keepCount
< maxAtomCount
) {
3686 qsort( test
, testCount
, sizeof( struct peer_atom
* ), compareAtomPtrsByShelfDate
);
3687 while( i
<testCount
&& keepCount
<maxAtomCount
)
3688 keep
[keepCount
++] = test
[i
++];
3691 /* free the culled atoms */
3692 while( i
<testCount
)
3693 tr_free( test
[i
++] );
3695 /* rebuild Torrent.pool with what's left */
3696 tr_ptrArrayDestruct( &t
->pool
, NULL
);
3697 t
->pool
= TR_PTR_ARRAY_INIT
;
3698 qsort( keep
, keepCount
, sizeof( struct peer_atom
* ), compareAtomPtrsByAddress
);
3699 for( i
=0; i
<keepCount
; ++i
)
3700 tr_ptrArrayAppend( &t
->pool
, keep
[i
] );
3702 tordbg( t
, "max atom count is %d... pruned from %d to %d\n", maxAtomCount
, atomCount
, keepCount
);
3710 tr_timerAddMsec( mgr
->atomTimer
, ATOM_PERIOD_MSEC
);
3711 managerUnlock( mgr
);
3720 /* is this atom someone that we'd want to initiate a connection to? */
3722 isPeerCandidate( const tr_torrent
* tor
, struct peer_atom
* atom
, const time_t now
)
3724 /* not if we're both seeds */
3725 if( tr_torrentIsSeed( tor
) && atomIsSeed( atom
) )
3728 /* not if we've already got a connection to them... */
3729 if( peerIsInUse( tor
->torrentPeers
, atom
) )
3732 /* not if we just tried them already */
3733 if( ( now
- atom
->time
) < getReconnectIntervalSecs( atom
, now
) )
3736 /* not if they're blocklisted */
3737 if( isAtomBlocklisted( tor
->session
, atom
) )
3740 /* not if they're banned... */
3741 if( atom
->flags2
& MYFLAG_BANNED
)
3747 struct peer_candidate
3751 struct peer_atom
* atom
;
3755 torrentWasRecentlyStarted( const tr_torrent
* tor
)
3757 return difftime( tr_time( ), tor
->startDate
) < 120;
3760 static inline uint64_t
3761 addValToKey( uint64_t value
, int width
, uint64_t addme
)
3763 value
= (value
<< (uint64_t)width
);
3768 /* smaller value is better */
3770 getPeerCandidateScore( const tr_torrent
* tor
, const struct peer_atom
* atom
, uint8_t salt
)
3774 const bool failed
= atom
->lastConnectionAt
< atom
->lastConnectionAttemptAt
;
3776 /* prefer peers we've connected to, or never tried, over peers we failed to connect to. */
3778 score
= addValToKey( score
, 1, i
);
3780 /* prefer the one we attempted least recently (to cycle through all peers) */
3781 i
= atom
->lastConnectionAttemptAt
;
3782 score
= addValToKey( score
, 32, i
);
3784 /* prefer peers belonging to a torrent of a higher priority */
3785 switch( tr_torrentGetPriority( tor
) ) {
3786 case TR_PRI_HIGH
: i
= 0; break;
3787 case TR_PRI_NORMAL
: i
= 1; break;
3788 case TR_PRI_LOW
: i
= 2; break;
3790 score
= addValToKey( score
, 4, i
);
3792 /* prefer recently-started torrents */
3793 i
= torrentWasRecentlyStarted( tor
) ? 0 : 1;
3794 score
= addValToKey( score
, 1, i
);
3796 /* prefer torrents we're downloading with */
3797 i
= tr_torrentIsSeed( tor
) ? 1 : 0;
3798 score
= addValToKey( score
, 1, i
);
3800 /* prefer peers that are known to be connectible */
3801 i
= ( atom
->flags
& ADDED_F_CONNECTABLE
) ? 0 : 1;
3802 score
= addValToKey( score
, 1, i
);
3804 /* prefer peers that we might have a chance of uploading to...
3805 so lower seed probability is better */
3806 if( atom
->seedProbability
== 100 ) i
= 101;
3807 else if( atom
->seedProbability
== -1 ) i
= 100;
3808 else i
= atom
->seedProbability
;
3809 score
= addValToKey( score
, 8, i
);
3811 /* Prefer peers that we got from more trusted sources.
3812 * lower `fromBest' values indicate more trusted sources */
3813 score
= addValToKey( score
, 4, atom
->fromBest
);
3816 score
= addValToKey( score
, 8, salt
);
3821 /* sort an array of peer candidates */
3823 comparePeerCandidates( const void * va
, const void * vb
)
3825 const struct peer_candidate
* a
= va
;
3826 const struct peer_candidate
* b
= vb
;
3828 if( a
->score
< b
->score
) return -1;
3829 if( a
->score
> b
->score
) return 1;
3834 /** @return an array of all the atoms we might want to connect to */
3835 static struct peer_candidate
*
3836 getPeerCandidates( tr_session
* session
, int * candidateCount
)
3841 struct peer_candidate
* candidates
;
3842 struct peer_candidate
* walk
;
3843 const time_t now
= tr_time( );
3844 const uint64_t now_msec
= tr_time_msec( );
3845 /* leave 5% of connection slots for incoming connections -- ticket #2609 */
3846 const int maxCandidates
= tr_sessionGetPeerLimit( session
) * 0.95;
3848 /* count how many peers and atoms we've got */
3852 while(( tor
= tr_torrentNext( session
, tor
))) {
3853 atomCount
+= tr_ptrArraySize( &tor
->torrentPeers
->pool
);
3854 peerCount
+= tr_ptrArraySize( &tor
->torrentPeers
->peers
);
3857 /* don't start any new handshakes if we're full up */
3858 if( maxCandidates
<= peerCount
) {
3859 *candidateCount
= 0;
3863 /* allocate an array of candidates */
3864 walk
= candidates
= tr_new( struct peer_candidate
, atomCount
);
3866 /* populate the candidate array */
3868 while(( tor
= tr_torrentNext( session
, tor
)))
3871 struct peer_atom
** atoms
;
3873 if( !tor
->torrentPeers
->isRunning
)
3876 /* if we've already got enough peers in this torrent... */
3877 if( tr_torrentGetPeerLimit( tor
) <= tr_ptrArraySize( &tor
->torrentPeers
->peers
) )
3880 /* if we've already got enough speed in this torrent... */
3881 if( tr_torrentIsSeed( tor
) && isBandwidthMaxedOut( &tor
->bandwidth
, now_msec
, TR_UP
) )
3884 atoms
= (struct peer_atom
**) tr_ptrArrayPeek( &tor
->torrentPeers
->pool
, &nAtoms
);
3885 for( i
=0; i
<nAtoms
; ++i
)
3887 struct peer_atom
* atom
= atoms
[i
];
3889 if( isPeerCandidate( tor
, atom
, now
) )
3891 const uint8_t salt
= tr_cryptoWeakRandInt( 1024 );
3894 walk
->score
= getPeerCandidateScore( tor
, atom
, salt
);
3900 *candidateCount
= walk
- candidates
;
3901 if( *candidateCount
> 1 )
3902 qsort( candidates
, *candidateCount
, sizeof( struct peer_candidate
), comparePeerCandidates
);
3907 initiateConnection( tr_peerMgr
* mgr
, Torrent
* t
, struct peer_atom
* atom
)
3910 const time_t now
= tr_time( );
3911 bool utp
= tr_sessionIsUTPEnabled(mgr
->session
) && !atom
->utp_failed
;
3913 if( atom
->fromFirst
== TR_PEER_FROM_PEX
)
3914 /* PEX has explicit signalling for uTP support. If an atom
3915 originally came from PEX and doesn't have the uTP flag, skip the
3916 uTP connection attempt. Are we being optimistic here? */
3917 utp
= utp
&& (atom
->flags
& ADDED_F_UTP_FLAGS
);
3919 tordbg( t
, "Starting an OUTGOING%s connection with %s",
3921 tr_atomAddrStr( atom
) );
3923 io
= tr_peerIoNewOutgoing( mgr
->session
,
3924 &mgr
->session
->bandwidth
,
3928 t
->tor
->completeness
== TR_SEED
,
3933 tordbg( t
, "peerIo not created; marking peer %s as unreachable",
3934 tr_atomAddrStr( atom
) );
3935 atom
->flags2
|= MYFLAG_UNREACHABLE
;
3940 tr_handshake
* handshake
= tr_handshakeNew( io
,
3941 mgr
->session
->encryptionMode
,
3945 assert( tr_peerIoGetTorrentHash( io
) );
3947 tr_peerIoUnref( io
); /* balanced by the initial ref
3948 in tr_peerIoNewOutgoing() */
3950 tr_ptrArrayInsertSorted( &t
->outgoingHandshakes
, handshake
,
3954 atom
->lastConnectionAttemptAt
= now
;
3959 initiateCandidateConnection( tr_peerMgr
* mgr
, struct peer_candidate
* c
)
3962 fprintf( stderr
, "Starting an OUTGOING connection with %s - [%s] seedProbability==%d; %s, %s\n",
3963 tr_atomAddrStr( c
->atom
),
3964 tr_torrentName( c
->tor
),
3965 (int)c
->atom
->seedProbability
,
3966 tr_torrentIsPrivate( c
->tor
) ? "private" : "public",
3967 tr_torrentIsSeed( c
->tor
) ? "seed" : "downloader" );
3970 initiateConnection( mgr
, c
->tor
->torrentPeers
, c
->atom
);
3974 makeNewPeerConnections( struct tr_peerMgr
* mgr
, const int max
)
3977 struct peer_candidate
* candidates
;
3979 candidates
= getPeerCandidates( mgr
->session
, &n
);
3981 for( i
=0; i
<n
&& i
<max
; ++i
)
3982 initiateCandidateConnection( mgr
, &candidates
[i
] );
3984 tr_free( candidates
);