Methods Summary |
---|
public void | addDiscoveredPeer(PeerItem peer)Add a potential peer obtained via tracker announce, DHT announce, plugin, etc.
try{ map_mon.enter();
for( Iterator it = peer_connections.values().iterator(); it.hasNext(); ) { //check to make sure we dont already know about this peer
PeerExchangerItem connection = (PeerExchangerItem)it.next();
if( connection.isConnectedToPeer( peer ) ) return; //we already know about this peer via exchange, so ignore discovery
}
if( !discovered_peers.contains( peer ) ) {
discovered_peers.addLast( peer ); //add unknown peer
int max_cache_size = PeerUtils.MAX_CONNECTIONS_PER_TORRENT;
if( max_cache_size < 1 || max_cache_size > MAX_DISCOVERED_PEERS ) max_cache_size = MAX_DISCOVERED_PEERS;
if( discovered_peers.size() > max_cache_size ) {
discovered_peers.removeFirst();
}
}
}
finally{ map_mon.exit(); }
|
protected void | deregisterPeerConnection(PeerItem base_peer_key)
try{ map_mon.enter();
peer_connections.remove( base_peer_key );
//update connection drops
for( Iterator it = peer_connections.values().iterator(); it.hasNext(); ) { //go through all remaining connections
PeerExchangerItem old_connection = (PeerExchangerItem)it.next();
//dont skip seed2seed drop notification, as the dropped peer may not have been seeding initially
old_connection.notifyDropped( base_peer_key ); //notify existing connection of drop
}
}
finally{ map_mon.exit(); }
|
public int | getDiscoveredPeerCount()
try{
map_mon.enter();
return( discovered_peers.size());
}finally{
map_mon.exit();
}
|
public PeerItem[] | getDiscoveredPeers()
try{
map_mon.enter();
return((PeerItem[])discovered_peers.toArray( new PeerItem[discovered_peers.size()] ));
}finally{
map_mon.exit();
}
|
private PeerItem[] | getExchangedPeersSortedByLeastPopularFirst()
HashMap popularity_counts = new HashMap();
try{ map_mon.enter();
//count popularity of all known peers
for( Iterator it = peer_connections.values().iterator(); it.hasNext(); ) {
PeerExchangerItem connection = (PeerExchangerItem)it.next();
PeerItem[] peers = connection.getConnectedPeers();
for( int i=0; i < peers.length; i++ ) {
PeerItem peer = peers[i];
Integer count = (Integer)popularity_counts.get( peer );
if( count == null ) {
count = new Integer( 1 );
}
else {
count = new Integer( count.intValue() + 1 );
}
popularity_counts.put( peer, count );
}
}
}
finally{ map_mon.exit(); }
if( popularity_counts.isEmpty() ) return null;
//now sort by popularity
Map.Entry[] sorted_entries = new Map.Entry[ popularity_counts.size() ];
popularity_counts.entrySet().toArray( sorted_entries );
Arrays.sort( sorted_entries, new Comparator() {
public int compare( Object obj1, Object obj2 ) {
Map.Entry en1 = (Map.Entry)obj1;
Map.Entry en2 = (Map.Entry)obj2;
return ((Integer)en1.getValue()).compareTo( (Integer)en2.getValue() ); //we want least popular in front
}
});
PeerItem[] sorted_peers = new PeerItem[ sorted_entries.length ];
for( int i=0; i < sorted_entries.length; i++ ) {
Map.Entry entry = sorted_entries[i];
sorted_peers[i] = (PeerItem)entry.getKey();
}
return sorted_peers;
|
public PeerItem | getNextOptimisticConnectPeer()Get the next potential peer for optimistic connect.
return(getNextOptimisticConnectPeer(0));
|
protected PeerItem | getNextOptimisticConnectPeer(int recursion_count)
PeerItem peer = null;
boolean discovered_peer = false;
//first see if there are any unknown peers to try
try{ map_mon.enter();
if( !discovered_peers.isEmpty() ) {
peer = (PeerItem)discovered_peers.removeFirst();
discovered_peer = true;
}
}
finally{ map_mon.exit(); }
//pick one from those obtained via peer exchange if needed
if( peer == null ) {
if( cached_peer_popularities == null || popularity_pos == cached_peer_popularities.length ) { //rebuild needed
cached_peer_popularities = null; //clear cache
long time_since_rebuild = SystemTime.getCurrentTime() - last_rebuild_time;
//only allow exchange list rebuild every few min, otherwise we'll spam attempts endlessly
if( time_since_rebuild > MIN_REBUILD_WAIT_TIME || time_since_rebuild < 0 ) {
cached_peer_popularities = getExchangedPeersSortedByLeastPopularFirst();
popularity_pos = 0;
last_rebuild_time = SystemTime.getCurrentTime();
}
}
if( cached_peer_popularities != null && cached_peer_popularities.length > 0 ) {
peer = cached_peer_popularities[ popularity_pos ];
popularity_pos++;
last_rebuild_time = SystemTime.getCurrentTime(); //ensure rebuild waits min rebuild time after the cache is depleted before trying attempts again
}
}
//to reduce the number of wasted outgoing attempts, we limit how frequently we hand out the same optimistic peer in a given time period
if( peer != null ) {
//check if it's time to rotate the bloom filters
long diff = SystemTime.getCurrentTime() - last_rotation_time;
if( diff < 0 || diff > BLOOM_ROTATION_PERIOD ) {
filter_one = filter_two;
filter_two = BloomFilterFactory.createAddOnly( BLOOM_FILTER_SIZE );
last_rotation_time = SystemTime.getCurrentTime();
}
//check to see if we've already given this peer out optimistically in the last 5-10min
boolean already_recorded = false;
byte[] peer_serialisation = peer.getSerialization();
if( filter_one.contains( peer_serialisation ) && recursion_count < 100 ) {
// we've recently given this peer, so recursively find another peer to try
PeerItem next_peer = getNextOptimisticConnectPeer( recursion_count + 1);
if ( next_peer != null ){
// we've found a better peer that this one. If the existing peer was discovered (as opposed to PEX)
// then we'll save it for later as it might come in useful
if ( discovered_peer ){
try{ map_mon.enter();
discovered_peers.addLast( peer );
}finally{
map_mon.exit();
}
}
peer = next_peer;
already_recorded = true; // this peer's already in the bloom filters as it has been returned
// by a recursive call
}
}
if( !already_recorded ) { //we've found a suitable peer
filter_one.add( peer_serialisation );
filter_two.add( peer_serialisation );
}
}
return peer;
|
public PeerItem | getSelfPeer()Get the peer item that represents ourself.
/*
//disabled for now, as getExternalIpAddress() will potential run a full version check every 60s
if( self_peer == null ) {
//determine our 'self' info from config
String ip = VersionCheckClient.getSingleton().getExternalIpAddress();
if( ip != null && ip.length() > 0 ) {
self_peer = PeerItemFactory.createPeerItem( ip, NetworkManager.getSingleton().getTCPListeningPortNumber(), 0 );
}
}
*/
return self_peer;
|
public java.lang.String | getString()
return("pc=" + peer_connections.size() + ",dp=" + discovered_peers.size());
|
public PeerExchangerItem | registerPeerConnection(PeerItem base_peer_item, PeerExchangerItem.Helper helper)Register a new peer connection with the database.
try{ map_mon.enter();
PeerExchangerItem new_connection = new PeerExchangerItem( this, base_peer_item, helper );
//update connection adds
for( Iterator it = peer_connections.entrySet().iterator(); it.hasNext(); ) { //go through all existing connections
Map.Entry entry = (Map.Entry)it.next();
PeerItem old_key = (PeerItem)entry.getKey();
PeerExchangerItem old_connection = (PeerExchangerItem)entry.getValue();
if( old_connection.getHelper().isSeed() && new_connection.getHelper().isSeed() ) {
continue; //dont exchange seed peers to other seeds
}
old_connection.notifyAdded( base_peer_item ); //notify existing connection of new one
new_connection.notifyAdded( old_key ); //notify new connection of existing one for initial exchange
}
peer_connections.put( base_peer_item, new_connection );
return new_connection;
}
finally{ map_mon.exit(); }
|
public void | seedStatusChanged(PeerExchangerItem item)
// only bother with non-seed -> seed transitions, the opposite are too rate to bother with
if ( item.getHelper().isSeed()){
try{
map_mon.enter();
for ( Iterator it = peer_connections.values().iterator(); it.hasNext(); ){
PeerExchangerItem connection = (PeerExchangerItem)it.next();
if ( connection != item && connection.getHelper().isSeed()){
// System.out.println( "seedStatusChanged: dropping: originator= " + item.getBasePeer().getAddressString() + ",target=" + connection.getBasePeer().getAddressString());
connection.notifyDropped( item.getBasePeer() );
item.notifyDropped( connection.getBasePeer() );
}
}
}finally{
map_mon.exit();
}
}
|
public void | setSelfPeer(PeerItem self)Mark the given peer as ourself. self_peer = self;
|