rendered paste bodyIndex: libtransmission/peer-mgr.c
===================================================================
--- libtransmission/peer-mgr.c (revision 3208)
+++ libtransmission/peer-mgr.c (working copy)
@@ -28,6 +28,7 @@
#include "ptrarray.h"
#include "trevent.h"
#include "utils.h"
+#include "platform.h"
enum
{
@@ -83,6 +84,7 @@
{
uint8_t hash[SHA_DIGEST_LENGTH];
tr_ptrArray * peers; /* tr_peer */
+ tr_lock * peerLock;
tr_timer * reconnectTimer;
tr_timer * reconnectSoonTimer;
tr_timer * rechokeTimer;
@@ -199,7 +201,11 @@
{
peer = tr_new0( tr_peer, 1 );
memcpy( &peer->in_addr, in_addr, sizeof(struct in_addr) );
- tr_ptrArrayInsertSorted( torrent->peers, peer, peerCompare );
+ tr_lockLock(torrent->peerLock);
+ {
+ tr_ptrArrayInsertSorted( torrent->peers, peer, peerCompare );
+ }
+ tr_lockUnlock(torrent->peerLock);
}
return peer;
@@ -247,6 +253,7 @@
assert( manager != NULL );
assert( t != NULL );
+ assert( t->peerLock != NULL );
assert( t->peers != NULL );
assert( getExistingTorrent( manager, t->hash ) != NULL );
@@ -257,14 +264,19 @@
tr_timerFree( &t->rechokeTimer );
tr_timerFree( &t->rechokeSoonTimer );
tr_timerFree( &t->refillTimer );
-
- peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &size );
- for( i=0; i<size; ++i )
- freePeer( peers[i] );
-
- tr_bitfieldFree( t->requested );
- tr_ptrArrayFree( t->peers );
- tr_ptrArrayRemoveSorted( manager->torrents, t, torrentCompare );
+
+ tr_lockLock(t->peerLock);
+ {
+ peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+ for( i=0; i<size; ++i )
+ freePeer( peers[i] );
+
+ tr_bitfieldFree( t->requested );
+ tr_ptrArrayFree( t->peers );
+ tr_ptrArrayRemoveSorted( manager->torrents, t, torrentCompare );
+ }
+ tr_lockUnlock(t->peerLock);
+ tr_lockFree(t->peerLock);
tr_free( t );
assert( getExistingTorrent( manager, hash ) == NULL );
@@ -302,13 +314,20 @@
getConnectedPeers( Torrent * t, int * setmeCount )
{
int i, peerCount, connectionCount;
- tr_peer **peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
- tr_peer **ret = tr_new( tr_peer*, peerCount );
+ tr_peer **peers;
+ tr_peer **ret;
+
+ tr_lockLock(t->peerLock);
+ {
+ peers = (tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
+ ret = tr_new( tr_peer*, peerCount );
+
+ for( i=connectionCount=0; i<peerCount; ++i )
+ if( peers[i]->msgs != NULL )
+ ret[connectionCount++] = peers[i];
+ }
+ tr_lockUnlock(t->peerLock);
- for( i=connectionCount=0; i<peerCount; ++i )
- if( peers[i]->msgs != NULL )
- ret[connectionCount++] = peers[i];
-
*setmeCount = connectionCount;
return ret;
}
@@ -862,22 +881,30 @@
{
const Torrent * t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
int i, peerCount;
- const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
- tr_pex * pex = tr_new( tr_pex, peerCount );
- tr_pex * walk = pex;
+ const tr_peer ** peers;
+ tr_pex * pex;
+ tr_pex * walk;
- for( i=0; i<peerCount; ++i, ++walk )
+ tr_lockLock(t->peerLock);
{
- const tr_peer * peer = peers[i];
-
- walk->in_addr = peer->in_addr;
-
- walk->port = peer->port;
-
- walk->flags = 0;
- if( peer->peerSupportsEncryption ) walk->flags |= 1;
- if( peer->progress >= 1.0 ) walk->flags |= 2;
+ peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
+ pex = tr_new( tr_pex, peerCount );
+ walk = pex;
+
+ for( i=0; i<peerCount; ++i, ++walk )
+ {
+ const tr_peer * peer = peers[i];
+
+ walk->in_addr = peer->in_addr;
+
+ walk->port = peer->port;
+
+ walk->flags = 0;
+ if( peer->peerSupportsEncryption ) walk->flags |= 1;
+ if( peer->progress >= 1.0 ) walk->flags |= 2;
+ }
}
+ tr_lockUnlock(t->peerLock);
assert( ( walk - pex ) == peerCount );
qsort( pex, peerCount, sizeof(tr_pex), tr_pexCompare );
@@ -918,7 +945,12 @@
t = tr_new0( Torrent, 1 );
t->manager = manager;
t->tor = tor;
- t->peers = tr_ptrArrayNew( );
+ t->peerLock = tr_lockNew();
+ tr_lockLock(t->peerLock);
+ {
+ t->peers = tr_ptrArrayNew( );
+ }
+ tr_lockUnlock(t->peerLock);
t->requested = tr_bitfieldNew( tor->blockCount );
restartChokeTimer( t );
restartReconnectTimer( t );
@@ -960,10 +992,16 @@
tab[i] = -1;
else {
int j, peerCount;
- const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
- for( j=0; j<peerCount; ++j )
- if( tr_bitfieldHas( peers[j]->have, i ) )
- ++tab[i];
+ const tr_peer ** peers;
+
+ tr_lockLock(t->peerLock);
+ {
+ peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount );
+ for( j=0; j<peerCount; ++j )
+ if( tr_bitfieldHas( peers[j]->have, i ) )
+ ++tab[i];
+ }
+ tr_lockUnlock(t->peerLock);
}
}
}
@@ -979,11 +1017,15 @@
tr_bitfield * pieces;
t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
- peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
pieces = tr_bitfieldDup( tr_cpPieceBitfield( t->tor->completion ) );
- for( i=0; i<size; ++i )
- if( peers[i]->io != NULL )
- tr_bitfieldAnd( pieces, peers[i]->have );
+ tr_lockLock(t->peerLock);
+ {
+ peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+ for( i=0; i<size; ++i )
+ if( peers[i]->io != NULL )
+ tr_bitfieldAnd( pieces, peers[i]->have );
+ }
+ tr_lockUnlock(t->peerLock);
return pieces;
}
@@ -999,33 +1041,39 @@
{
int i, size;
const Torrent * t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
- const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+ const tr_peer ** peers;
- *setmePeersTotal = size;
- *setmePeersConnected = 0;
- *setmePeersSendingToUs = 0;
- *setmePeersGettingFromUs = 0;
-
- for( i=0; i<TR_PEER_FROM__MAX; ++i )
- setmePeersFrom[i] = 0;
-
- for( i=0; i<size; ++i )
+ tr_lockLock(t->peerLock);
{
- const tr_peer * peer = peers[i];
-
- if( peer->io == NULL ) /* not connected */
- continue;
-
- ++*setmePeersConnected;
-
- ++setmePeersFrom[peer->from];
-
- if( tr_peerIoGetRateToPeer( peer->io ) > 0.01 )
- ++*setmePeersGettingFromUs;
-
- if( tr_peerIoGetRateToClient( peer->io ) > 0.01 )
- ++*setmePeersSendingToUs;
+ peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+
+ *setmePeersTotal = size;
+ *setmePeersConnected = 0;
+ *setmePeersSendingToUs = 0;
+ *setmePeersGettingFromUs = 0;
+
+ for( i=0; i<TR_PEER_FROM__MAX; ++i )
+ setmePeersFrom[i] = 0;
+
+ for( i=0; i<size; ++i )
+ {
+ const tr_peer * peer = peers[i];
+
+ if( peer->io == NULL ) /* not connected */
+ continue;
+
+ ++*setmePeersConnected;
+
+ ++setmePeersFrom[peer->from];
+
+ if( tr_peerIoGetRateToPeer( peer->io ) > 0.01 )
+ ++*setmePeersGettingFromUs;
+
+ if( tr_peerIoGetRateToClient( peer->io ) > 0.01 )
+ ++*setmePeersSendingToUs;
+ }
}
+ tr_lockUnlock(t->peerLock);
}
struct tr_peer_stat *
@@ -1035,29 +1083,33 @@
{
int i, size;
const Torrent * t = getExistingTorrent( (tr_peerMgr*)manager, torrentHash );
- const tr_peer ** peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+ const tr_peer ** peers;
tr_peer_stat * ret;
- ret = tr_new0( tr_peer_stat, size );
-
- for( i=0; i<size; ++i )
+ tr_lockLock(t->peerLock);
{
- const tr_peer * peer = peers[i];
- const int live = peer->io != NULL;
- tr_peer_stat * stat = ret + i;
-
- tr_netNtop( &peer->in_addr, stat->addr, sizeof(stat->addr) );
- stat->port = peer->port;
- stat->from = peer->from;
- stat->client = peer->client;
- stat->progress = peer->progress;
- stat->isConnected = live ? 1 : 0;
- stat->isEncrypted = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0;
- stat->uploadToRate = tr_peerIoGetRateToPeer( peer->io );
- stat->downloadFromRate = tr_peerIoGetRateToClient( peer->io );
- stat->isDownloading = stat->uploadToRate > 0.01;
- stat->isUploading = stat->downloadFromRate > 0.01;
+ peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size );
+ ret = tr_new0( tr_peer_stat, size );
+ for( i=0; i<size; ++i )
+ {
+ const tr_peer * peer = peers[i];
+ const int live = peer->io != NULL;
+ tr_peer_stat * stat = ret + i;
+
+ tr_netNtop( &peer->in_addr, stat->addr, sizeof(stat->addr) );
+ stat->port = peer->port;
+ stat->from = peer->from;
+ stat->client = peer->client;
+ stat->progress = peer->progress;
+ stat->isConnected = live ? 1 : 0;
+ stat->isEncrypted = tr_peerIoIsEncrypted( peer->io ) ? 1 : 0;
+ stat->uploadToRate = tr_peerIoGetRateToPeer( peer->io );
+ stat->downloadFromRate = tr_peerIoGetRateToClient( peer->io );
+ stat->isDownloading = stat->uploadToRate > 0.01;
+ stat->isUploading = stat->downloadFromRate > 0.01;
+ }
}
+ tr_lockUnlock(t->peerLock);
*setmeCount = size;
return ret;
@@ -1242,79 +1294,84 @@
{
int i, size, liveCount;
Torrent * t = vt;
- tr_peer ** peers = (tr_peer**) tr_ptrArrayPeek( t->peers, &size );
+ tr_peer ** peers;
const int isSeeding = tr_cpGetStatus( t->tor->completion ) != TR_CP_INCOMPLETE;
- /* how many connections do we have? */
- for( i=liveCount=0; i<size; ++i )
- if( peers[i]->msgs != NULL )
- ++liveCount;
-
- /* destroy and/or disconnect from some peers */
- for( i=0; i<size; )
+ tr_lockLock(t->peerLock);
{
- tr_peer * peer = peers[i];
-
- if( peer->doPurge ) {
- tr_ptrArrayErase( t->peers, i, i+1 );
- freePeer( peer );
- --size;
- --liveCount;
- continue;
- }
-
- if( shouldPeerBeDisconnected( t, peer, liveCount, isSeeding ) ) {
- disconnectPeer( peer );
- --liveCount;
- }
-
- ++i;
- }
-
- /* maybe connect to some new peers */
- if( t->isRunning && (liveCount<MAX_CONNECTED_PEERS_PER_TORRENT) )
- {
- int poolSize;
- int left = MAX_CONNECTED_PEERS_PER_TORRENT - liveCount;
- tr_peer ** pool;
- tr_peerMgr * manager = t->manager;
- const time_t now = time( NULL );
-
- /* make a list of peers we know about but aren't connected to */
- poolSize = 0;
- pool = tr_new0( tr_peer*, size );
- for( i=0; i<size; ++i ) {
+ peers = (tr_peer**) tr_ptrArrayPeek( t->peers, &size );
+ /* how many connections do we have? */
+ for( i=liveCount=0; i<size; ++i )
+ if( peers[i]->msgs != NULL )
+ ++liveCount;
+
+ /* destroy and/or disconnect from some peers */
+ for( i=0; i<size; )
+ {
tr_peer * peer = peers[i];
- if( peer->msgs == NULL )
- pool[poolSize++] = peer;
+
+ if( peer->doPurge ) {
+ tr_ptrArrayErase( t->peers, i, i+1 );
+ freePeer( peer );
+ --size;
+ --liveCount;
+ continue;
+ }
+
+ if( shouldPeerBeDisconnected( t, peer, liveCount, isSeeding ) ) {
+ disconnectPeer( peer );
+ --liveCount;
+ }
+
+ ++i;
}
-
- /* sort them s.t. the ones we've already tried are at the last of the list */
- qsort( pool, poolSize, sizeof(tr_peer*), comparePeerByConnectionDate );
-
- /* make some connections */
- for( i=0; i<poolSize && left>0; ++i )
+
+ /* maybe connect to some new peers */
+ if( t->isRunning && (liveCount<MAX_CONNECTED_PEERS_PER_TORRENT) )
{
- tr_peer * peer = pool[i];
- tr_peerIo * io;
-
- if( ( now - peer->connectionChangedAt ) < MIN_HANGUP_PERIOD_SEC )
- break;
-
- /* already have a handshake pending */
- if( getExistingHandshake( manager, &peer->in_addr ) != NULL )
- continue;
-
- /* initiate a connection to the peer */
- io = tr_peerIoNewOutgoing( manager->handle, &peer->in_addr, peer->port, t->hash );
- /*fprintf( stderr, "[%s] connecting to potential peer %s\n", t->tor->info.name, tr_peerIoGetAddrStr(io) );*/
- peer->connectionChangedAt = time( NULL );
- initiateHandshake( manager, io );
- --left;
+ int poolSize;
+ int left = MAX_CONNECTED_PEERS_PER_TORRENT - liveCount;
+ tr_peer ** pool;
+ tr_peerMgr * manager = t->manager;
+ const time_t now = time( NULL );
+
+ /* make a list of peers we know about but aren't connected to */
+ poolSize = 0;
+ pool = tr_new0( tr_peer*, size );
+ for( i=0; i<size; ++i ) {
+ tr_peer * peer = peers[i];
+ if( peer->msgs == NULL )
+ pool[poolSize++] = peer;
+ }
+
+ /* sort them s.t. the ones we've already tried are at the last of the list */
+ qsort( pool, poolSize, sizeof(tr_peer*), comparePeerByConnectionDate );
+
+ /* make some connections */
+ for( i=0; i<poolSize && left>0; ++i )
+ {
+ tr_peer * peer = pool[i];
+ tr_peerIo * io;
+
+ if( ( now - peer->connectionChangedAt ) < MIN_HANGUP_PERIOD_SEC )
+ break;
+
+ /* already have a handshake pending */
+ if( getExistingHandshake( manager, &peer->in_addr ) != NULL )
+ continue;
+
+ /* initiate a connection to the peer */
+ io = tr_peerIoNewOutgoing( manager->handle, &peer->in_addr, peer->port, t->hash );
+ /*fprintf( stderr, "[%s] connecting to potential peer %s\n", t->tor->info.name, tr_peerIoGetAddrStr(io) );*/
+ peer->connectionChangedAt = time( NULL );
+ initiateHandshake( manager, io );
+ --left;
+ }
+
+ tr_free( pool );
}
-
- tr_free( pool );
}
+ tr_lockUnlock(t->peerLock);
return TRUE;
}