Index: 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; irequested ); - 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; irequested ); + 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; imsgs != NULL ) + ret[connectionCount++] = peers[i]; + } + tr_lockUnlock(t->peerLock); - for( i=connectionCount=0; imsgs != 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; ipeerLock); { - 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; iin_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; jhave, i ) ) - ++tab[i]; + const tr_peer ** peers; + + tr_lockLock(t->peerLock); + { + peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &peerCount ); + for( j=0; jhave, 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; iio != NULL ) - tr_bitfieldAnd( pieces, peers[i]->have ); + tr_lockLock(t->peerLock); + { + peers = (const tr_peer **) tr_ptrArrayPeek( t->peers, &size ); + for( i=0; iio != 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; ipeerLock); { - 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; iio == 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; ipeerLock); { - 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; iio != 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; imsgs != NULL ) - ++liveCount; - - /* destroy and/or disconnect from some peers */ - for( i=0; ipeerLock); { - 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 && (liveCountmanager; - 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; ipeers, &size ); + /* how many connections do we have? */ + for( i=liveCount=0; imsgs != NULL ) + ++liveCount; + + /* destroy and/or disconnect from some peers */ + for( i=0; imsgs == 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; i0; ++i ) + + /* maybe connect to some new peers */ + if( t->isRunning && (liveCountconnectionChangedAt ) < 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; imsgs == 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; i0; ++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; }