package org.gudy.azureus2.core3.peer.impl.transport; ///* // * File : PEPeerTransportProtocol.java // * Created : 22-Oct-2003 // * By : stuff // * // * Azureus - a Java Bittorrent client // * // * This program is free software; you can redistribute it and/or modify // * it under the terms of the GNU General Public License as published by // * the Free Software Foundation; either version 2 of the License. // * // * This program is distributed in the hope that it will be useful, // * but WITHOUT ANY WARRANTY; without even the implied warranty of // * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // * GNU General Public License for more details ( see the LICENSE file ). // * // * You should have received a copy of the GNU General Public License // * along with this program; if not, write to the Free Software // * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // */ //package org.gudy.azureus2.core3.peer.impl.transport; // // //import java.net.InetAddress; //import java.net.InetSocketAddress; //import java.nio.ByteBuffer; //import java.util.*; // //import org.gudy.azureus2.core3.config.COConfigurationManager; //import org.gudy.azureus2.core3.config.ParameterListener; //import org.gudy.azureus2.core3.disk.DiskManager; //import org.gudy.azureus2.core3.disk.DiskManagerPiece; //import org.gudy.azureus2.core3.disk.DiskManagerReadRequest; //import org.gudy.azureus2.core3.logging.*; //import org.gudy.azureus2.core3.peer.*; //import org.gudy.azureus2.core3.peer.impl.PEPeerControl; //import org.gudy.azureus2.core3.peer.impl.PEPeerTransport; //import org.gudy.azureus2.core3.peer.impl.PEPeerTransportFactory; //import org.gudy.azureus2.core3.peer.util.PeerIdentityDataID; //import org.gudy.azureus2.core3.peer.util.PeerIdentityManager; //import org.gudy.azureus2.core3.peer.util.PeerUtils; //import org.gudy.azureus2.core3.util.*; //import org.gudy.azureus2.plugins.dht.mainline.MainlineDHTProvider; //import org.gudy.azureus2.plugins.network.Connection; //import org.gudy.azureus2.plugins.peers.Peer; //import org.gudy.azureus2.pluginsimpl.local.network.ConnectionImpl; // //import com.aelitis.azureus.core.impl.AzureusCoreImpl; //import com.aelitis.azureus.core.networkmanager.*; //import com.aelitis.azureus.core.networkmanager.admin.NetworkAdmin; //import com.aelitis.azureus.core.networkmanager.impl.tcp.ProtocolEndpointTCP; //import com.aelitis.azureus.core.networkmanager.impl.tcp.TCPNetworkManager; //import com.aelitis.azureus.core.networkmanager.impl.udp.ProtocolEndpointUDP; //import com.aelitis.azureus.core.networkmanager.impl.udp.UDPNetworkManager; //import com.aelitis.azureus.core.peermanager.messaging.Message; //import com.aelitis.azureus.core.peermanager.messaging.MessageManager; //import com.aelitis.azureus.core.peermanager.messaging.azureus.*; //import com.aelitis.azureus.core.peermanager.messaging.bittorrent.*; //import com.aelitis.azureus.core.peermanager.messaging.bittorrent.ltep.*; //import com.aelitis.azureus.core.peermanager.peerdb.PeerExchangerItem; //import com.aelitis.azureus.core.peermanager.peerdb.PeerItem; //import com.aelitis.azureus.core.peermanager.peerdb.PeerItemFactory; //import com.aelitis.azureus.core.peermanager.piecepicker.PiecePicker; //import com.aelitis.azureus.core.peermanager.piecepicker.util.BitFlags; //import com.aelitis.azureus.core.peermanager.utils.*; // // //public class //PEPeerTransportProtocol //extends LogRelation //implements PEPeerTransport //{ // protected final static LogIDs LOGID = LogIDs.PEER; // // private volatile int _lastPiece =-1; //last piece that was requested from this peer (mostly to try to request from same one) // // protected final PEPeerControl manager; // protected final DiskManager diskManager; // protected final PiecePicker piecePicker; // // protected final int nbPieces; // // private final String peer_source; // private byte[] peer_id; // private final String ip; // protected String ip_resolved; // private IPToHostNameResolverRequest ip_resolver_request; // // private int port; // // private PeerItem peer_item_identity; // private int tcp_listen_port = 0; // private int udp_listen_port = 0; // private int udp_non_data_port = 0; // // if the peer announces an ipv6 address // private InetAddress alternativeAddress; // // private byte crypto_level; // // protected PEPeerStats peer_stats; // // private final ArrayList requested = new ArrayList(); // private final AEMonitor requested_mon = new AEMonitor( "PEPeerTransportProtocol:Req" ); // // private Map data; // // private long lastNeededUndonePieceChange; // // protected boolean choked_by_other_peer = true; // /** total time the other peer has unchoked us while not snubbed */ // protected long unchokedTimeTotal; // /** the time at which the other peer last unchoked us when not snubbed */ // protected long unchokedTime; // protected boolean choking_other_peer = true; // private boolean interested_in_other_peer = false; // private boolean other_peer_interested_in_me = false; // private long snubbed =0; // // /** lazy allocation; null until needed */ // private volatile BitFlags peerHavePieces =null; // private volatile boolean availabilityAdded =false; // private volatile boolean received_bitfield; // // private boolean handshake_sent; // // private boolean seeding = false; // // private static final byte RELATIVE_SEEDING_NONE = 0x00; // // indicates that the peer told us that he's uploading only // private static final byte RELATIVE_SEEDING_UPLOAD_ONLY_INDICATED = 0x01; // // peer is not useful to us // private static final byte RELATIVE_SEEDING_UPLOAD_ONLY_SEED = 0x02; // private byte relativeSeeding = RELATIVE_SEEDING_NONE; // // private final boolean incoming; // // protected volatile boolean closing = false; // private volatile int current_peer_state; // // protected NetworkConnection connection; // private OutgoingBTPieceMessageHandler outgoing_piece_message_handler; // private OutgoingBTHaveMessageAggregator outgoing_have_message_aggregator; // private Connection plugin_connection; // // private boolean identityAdded = false; //needed so we don't remove id's in closeAll() on duplicate connection attempts // // protected int connection_state = PEPeerTransport.CONNECTION_PENDING; // // private String client = ""; // Client name to show to user. // private String client_peer_id = ""; // Client name derived from the peer ID. // private String client_handshake = ""; // Client name derived from the handshake. // private String client_handshake_version = ""; // Client version derived from the handshake. // // //When superSeeding, number of unique piece announced // private int uniquePiece = -1; // // //When downloading a piece in exclusivity mode the piece number being downloaded // private int reservedPiece = -1; // // //Spread time (0 secs , fake default) // private int spreadTimeHint = 0 * 1000; // // protected long last_message_sent_time = 0; // protected long last_message_received_time = 0; // protected long last_data_message_received_time = -1; // protected long last_good_data_time =-1; // time data written to disk was recieved // protected long last_data_message_sent_time = -1; // // private long connection_established_time = 0; // // private int consecutive_no_request_count; // // private int messaging_mode = MESSAGING_BT_ONLY; // private Message[] supported_messages = null; // private byte other_peer_bitfield_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_cancel_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_choke_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_handshake_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_bt_have_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_az_have_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_interested_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_keep_alive_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_pex_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_piece_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_unchoke_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_uninterested_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_request_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_bt_lt_ext_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_az_request_hint_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // private byte other_peer_az_bad_piece_version = BTMessageFactory.MESSAGE_VERSION_INITIAL; // // private boolean ut_pex_enabled = false; // private boolean ml_dht_enabled = false; // // private final AEMonitor closing_mon = new AEMonitor( "PEPeerTransportProtocol:closing" ); // private final AEMonitor general_mon = new AEMonitor( "PEPeerTransportProtocol:data" ); // // private byte[] handshake_reserved_bytes = null; // // private LinkedHashMap recent_outgoing_requests; // private AEMonitor recent_outgoing_requests_mon; // // private boolean has_received_initial_pex = false; // // private static final boolean SHOW_DISCARD_RATE_STATS; // static { // final String prop = System.getProperty( "show.discard.rate.stats" ); // SHOW_DISCARD_RATE_STATS = prop != null && prop.equals( "1" ); // } // // private static int requests_discarded = 0; // private static int requests_discarded_endgame = 0; // private static int requests_recovered = 0; // private static int requests_completed = 0; // // private static final int REQUEST_HINT_MAX_LIFE = PiecePicker.REQUEST_HINT_MAX_LIFE + 30*1000; // // private int[] request_hint; // // private List peer_listeners_cow; // private final AEMonitor peer_listeners_mon = new AEMonitor( "PEPeerTransportProtocol:PL" ); // // // //certain Optimum Online networks block peer seeding via "complete" bitfield message filtering // //lazy mode makes sure we never send a complete (seed) bitfield // protected static boolean ENABLE_LAZY_BITFIELD; // // private boolean priority_connection; // // private static final class DisconnectedTransportQueue extends LinkedHashMap // { // public DisconnectedTransportQueue() // { // super(20,0.75F); // } // // private static final long MAX_CACHE_AGE = 2*60*1000; // // // remove all elements older than 2 minutes until we hit the 20 again // // private void performCleaning() { // if(size() > 20) // { // Iterator it = values().iterator(); // // long now = SystemTime.getMonotonousTime(); // // while(it.hasNext() && size() > 20) // { // QueueEntry eldest = (QueueEntry)it.next(); // if( now - eldest.addTime > MAX_CACHE_AGE){ // it.remove(); // }else{ // break; // } // } // } // } // // private static final class QueueEntry { // public QueueEntry(PEPeerTransportProtocol trans) // { // transport = trans; // } // // final PEPeerTransportProtocol transport; // final long addTime = SystemTime.getMonotonousTime(); // } // // // hardcap at 100 // protected boolean removeEldestEntry(Map.Entry eldest) { // return size() > 100; // } // // synchronized public Object put(HashWrapper key, PEPeerTransportProtocol value) { // performCleaning(); // return super.put(key, new QueueEntry(value)); // } // // synchronized public PEPeerTransportProtocol remove(HashWrapper key) { // performCleaning(); // QueueEntry entry = (QueueEntry)super.remove(key); // if(entry != null) // return entry.transport; // else // return null; // } // // } // // private static final DisconnectedTransportQueue recentlyDisconnected = new DisconnectedTransportQueue(); // // private static boolean fast_unchoke_new_peers; // // private static final Random rnd = RandomUtils.SECURE_RANDOM; // // private static final byte[] sessionSecret; // // static { // rnd.setSeed(SystemTime.getHighPrecisionCounter()); // sessionSecret = new byte[20]; // rnd.nextBytes(sessionSecret); // // COConfigurationManager.addAndFireParameterListeners( // new String[]{ // "Use Lazy Bitfield", // "Peer.Fast.Initial.Unchoke.Enabled" }, // new ParameterListener() // { // public final void // parameterChanged( // String ignore ) // { // final String prop = System.getProperty( "azureus.lazy.bitfield" ); // // ENABLE_LAZY_BITFIELD = prop != null && prop.equals( "1" ); // // ENABLE_LAZY_BITFIELD |= COConfigurationManager.getBooleanParameter( "Use Lazy Bitfield" ); // // fast_unchoke_new_peers = COConfigurationManager.getBooleanParameter( "Peer.Fast.Initial.Unchoke.Enabled" ); // } // }); // } // // // // // reconnect stuff // private HashWrapper peerSessionID; // private HashWrapper mySessionID; // // // allow reconnect if we've sent or recieved at least 1 piece over the current connection // private boolean allowReconnect; // // // // private boolean is_optimistic_unchoke = false; // // private PeerExchangerItem peer_exchange_item = null; // private boolean peer_exchange_supported = false; // // protected PeerMessageLimiter message_limiter; // // private boolean request_hint_supported; // private boolean bad_piece_supported; // // private boolean have_aggregation_disabled; // // // //INCOMING // public // PEPeerTransportProtocol( // PEPeerControl _manager, // String _peer_source, // NetworkConnection _connection, // Map _initial_user_data ) // { // manager = _manager; // peer_source = _peer_source; // connection = _connection; // data = _initial_user_data; // // incoming = true; // // diskManager =manager.getDiskManager(); // piecePicker =manager.getPiecePicker(); // nbPieces =diskManager.getNbPieces(); // // // InetSocketAddress notional_address = _connection.getEndpoint().getNotionalAddress(); // // ip = notional_address.getAddress().getHostAddress(); // port = notional_address.getPort(); // // peer_item_identity = PeerItemFactory.createPeerItem( ip, port, PeerItem.convertSourceID( _peer_source ), PeerItemFactory.HANDSHAKE_TYPE_PLAIN, 0, PeerItemFactory.CRYPTO_LEVEL_1, 0 ); //this will be recreated upon az handshake decode // // plugin_connection = new ConnectionImpl(connection, incoming); // // peer_stats = manager.createPeerStats( this ); // // changePeerState( PEPeer.CONNECTING ); // } // // public void // start() // { // // split out connection initiation from constructor so we can get access to the peer transport // // before message processing starts // // if ( incoming ){ // // //"fake" a connect request to register our listener // connection.connect( // ProtocolEndpoint.CONNECT_PRIORITY_MEDIUM, // new NetworkConnection.ConnectionListener() // { // public final void // connectStarted() { // connection_state = PEPeerTransport.CONNECTION_CONNECTING; // } // // public final void connectSuccess( ByteBuffer remaining_initial_data ) { //will be called immediately // if (Logger.isEnabled()) // Logger.log(new LogEvent(PEPeerTransportProtocol.this, LOGID, // "In: Established incoming connection")); // // generateSessionId(); // // initializeConnection(); // // /* // * Waiting until we've received the initiating-end's full handshake, before sending back our own, // * really should be the "proper" behavior. However, classic BT trackers running NAT checking will // * only send the first 48 bytes (up to infohash) of the peer handshake, skipping peerid, which means // * we'll never get their complete handshake, and thus never reply, which causes the NAT check to fail. // * So, we need to send our handshake earlier, after we've verified the infohash. // * NOTE: // * This code makes the assumption that the inbound infohash has already been validated, // * as we don't check their handshake fully before sending our own. // */ // sendBTHandshake(); // } // // public final void // connectFailure( // Throwable failure_msg ) // { //should never happen // Debug.out( "ERROR: incoming connect failure: ", failure_msg ); // closeConnectionInternally( "ERROR: incoming connect failure [" + PEPeerTransportProtocol.this + "] : " + failure_msg.getMessage(), true, true ); // } // // public final void // exceptionThrown( // Throwable error ) // { // if( error.getMessage() == null ) { // Debug.out( error ); // } // // closeConnectionInternally( "connection exception: " + error.getMessage(), false, true ); // } // // public String // getDescription() // { // return( getString()); // } // }); // }else{ // // not pulled out startup from outbound connections yet... // } // } // // // // //OUTGOING // // public // PEPeerTransportProtocol( // PEPeerControl _manager, // String _peer_source, // String _ip, // int _tcp_port, // int _udp_port, // boolean _use_tcp, // boolean _require_crypto_handshake, // byte _crypto_level, // Map _initial_user_data ) // { // // manager = _manager; // diskManager =manager.getDiskManager(); // piecePicker =manager.getPiecePicker(); // nbPieces =diskManager.getNbPieces(); // lastNeededUndonePieceChange =Long.MIN_VALUE; // // peer_source = _peer_source; // ip = _ip; // port = _tcp_port; // tcp_listen_port = _tcp_port; // udp_listen_port = _udp_port; // crypto_level = _crypto_level; // data = _initial_user_data; // // if ( data != null ){ // // Boolean pc = (Boolean)data.get( Peer.PR_PRIORITY_CONNECTION ); // // if ( pc != null && pc.booleanValue()){ // // setPriorityConnection( true ); // } // } // // udp_non_data_port = UDPNetworkManager.getSingleton().getUDPNonDataListeningPortNumber(); // // peer_item_identity = PeerItemFactory.createPeerItem( ip, tcp_listen_port, PeerItem.convertSourceID( _peer_source ), PeerItemFactory.HANDSHAKE_TYPE_PLAIN, _udp_port, crypto_level, 0 ); //this will be recreated upon az handshake decode // // incoming = false; // // peer_stats = manager.createPeerStats( this ); // // if( port < 0 || port > 65535 ) { // closeConnectionInternally( "given remote port is invalid: " + port ); // return; // } // // // either peer specific or global pref plus optional per-download level // // boolean use_crypto = // _require_crypto_handshake || // NetworkManager.getCryptoRequired( manager.getAdapter().getCryptoLevel()); // // if( isLANLocal() ) use_crypto = false; //dont bother with PHE for lan peers // // InetSocketAddress endpoint_address; // ProtocolEndpoint pe; // // if ( _use_tcp ){ // // endpoint_address = new InetSocketAddress( ip, tcp_listen_port ); // // pe = new ProtocolEndpointTCP( endpoint_address ); // // }else{ // // endpoint_address = new InetSocketAddress( ip, udp_listen_port ); // // pe = new ProtocolEndpointUDP( endpoint_address ); // } // // ConnectionEndpoint connection_endpoint = new ConnectionEndpoint( endpoint_address ); // // connection_endpoint.addProtocol( pe ); // // connection = // NetworkManager.getSingleton().createConnection( // connection_endpoint, // new BTMessageEncoder(), // new BTMessageDecoder(), // use_crypto, // !_require_crypto_handshake, // manager.getSecrets( _crypto_level )); // // plugin_connection = new ConnectionImpl(connection, incoming); // // changePeerState( PEPeer.CONNECTING ); // // ByteBuffer initial_outbound_data = null; // // if ( use_crypto ){ // // BTHandshake handshake = new BTHandshake( manager.getHash(), // manager.getPeerId(), // manager.isExtendedMessagingEnabled(), other_peer_handshake_version ); // // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, // "Sending encrypted handshake with reserved bytes: " + // ByteFormatter.nicePrint(handshake.getReserved(), false))); // // DirectByteBuffer[] ddbs = handshake.getRawData(); // // int handshake_len = 0; // // for (int i=0;i<ddbs.length;i++){ // // handshake_len += ddbs[i].remaining( DirectByteBuffer.SS_PEER ); // } // // initial_outbound_data = ByteBuffer.allocate( handshake_len ); // // for (int i=0;i<ddbs.length;i++){ // // DirectByteBuffer ddb = ddbs[i]; // // initial_outbound_data.put( ddb.getBuffer( DirectByteBuffer.SS_PEER )); // // ddb.returnToPool(); // } // // initial_outbound_data.flip(); // // handshake_sent = true; // } // // int priority; // // if ( manager.isSeeding()){ // // priority = ProtocolEndpoint.CONNECT_PRIORITY_LOW; // // }else if ( manager.isRTA()){ // // if ( PeerClassifier.isAzureusIP( ip )){ // // priority = ProtocolEndpoint.CONNECT_PRIORITY_SUPER_HIGHEST; // // }else{ // // priority = ProtocolEndpoint.CONNECT_PRIORITY_HIGHEST; // } // }else if ( PeerClassifier.isAzureusIP( ip )){ // // priority = ProtocolEndpoint.CONNECT_PRIORITY_HIGHEST; // // }else{ // // priority = ProtocolEndpoint.CONNECT_PRIORITY_MEDIUM; // } // // // give plugin peers some priority as they're being injected for a good reason // // if ( peer_source == PEPeerSource.PS_PLUGIN ){ // // if ( priority > ProtocolEndpoint.CONNECT_PRIORITY_HIGH ){ // // priority = ProtocolEndpoint.CONNECT_PRIORITY_HIGH; // } // } // // connection.connect( // initial_outbound_data, // priority, // new NetworkConnection.ConnectionListener() // { // private boolean connect_ok; // // public final void // connectStarted() // { // connection_state = PEPeerTransport.CONNECTION_CONNECTING; // } // // public final void // connectSuccess( // ByteBuffer remaining_initial_data ) // { // connect_ok = true; // // if( closing ) { // //Debug.out( "PEPeerTransportProtocol::connectSuccess() called when closing." ); // return; // } // // generateSessionId(); // // if (Logger.isEnabled()) // Logger.log(new LogEvent(PEPeerTransportProtocol.this, LOGID, // "Out: Established outgoing connection")); // // initializeConnection(); // // if ( remaining_initial_data != null && remaining_initial_data.remaining() > 0){ // // // queue as a *raw* message as already encoded // // connection.getOutgoingMessageQueue().addMessage( // new BTRawMessage( new DirectByteBuffer( remaining_initial_data )), false ); // } // // sendBTHandshake(); // } // // public final void // connectFailure( // Throwable failure_msg ) // { // closeConnectionInternally( "failed to establish outgoing connection: " + failure_msg.getMessage(), true, true ); // } // // public final void // exceptionThrown( // Throwable error ) // { // if( error.getMessage() == null ) { // Debug.out( "error.getMessage() == null", error ); // } // // closeConnectionInternally( "connection exception: " + error.getMessage(), !connect_ok, true ); // } // // public String // getDescription() // { // return( getString()); // } // }); // // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, // "Out: Creating outgoing connection")); // } // // // // // protected void initializeConnection() { // if( closing ) return; // // recent_outgoing_requests = new LinkedHashMap( 16, .75F, true ) { // public final boolean removeEldestEntry(Map.Entry eldest) { // return size() > 16; // } // }; // recent_outgoing_requests_mon = new AEMonitor( "PEPeerTransportProtocol:ROR" ); // // message_limiter = new PeerMessageLimiter(); // // /* // //link in outgoing piece handler // outgoing_piece_message_handler = // new OutgoingBTPieceMessageHandler( // this, // connection.getOutgoingMessageQueue(), // new OutgoingBTPieceMessageHandlerAdapter() // { // public void // diskRequestCompleted( // long bytes) // { // peer_stats.diskReadComplete( bytes ); // } // }, // other_peer_piece_version);*/ // // //link in outgoing have message aggregator // outgoing_have_message_aggregator = new OutgoingBTHaveMessageAggregator( connection.getOutgoingMessageQueue(), other_peer_bt_have_version, other_peer_az_have_version ); // // connection_established_time = SystemTime.getCurrentTime(); // // connection_state = PEPeerTransport.CONNECTION_WAITING_FOR_HANDSHAKE; // changePeerState( PEPeer.HANDSHAKING ); // // registerForMessageHandling(); // } // // // // // // public String // getPeerSource() // { // return( peer_source ); // } // // // // /** // * Close the peer connection from within the PEPeerTransport object. // * @param reason // */ // protected void closeConnectionInternally( String reason, boolean connect_failed, boolean network_failure ) { // performClose( reason, connect_failed, false, network_failure ); // } // // protected void closeConnectionInternally( String reason ) { // performClose( reason, false, false, false ); // } // // // /** // * Close the peer connection from the PEPeerControl manager side. // * NOTE: This method assumes PEPeerControl already knows about the close. // * This method is inteded to be only invoked by select administrative methods. // * You probably should not invoke this directly. // */ // public void closeConnection( String reason ) { // performClose( reason, false, true, false ); // } // // // private void performClose( String reason, boolean connect_failed, boolean externally_closed, boolean network_failure ) // { // try{ // closing_mon.enter(); // // if( closing ) // return; // closing = true; // // // immediatly lose interest in peer // interested_in_other_peer =false; // lastNeededUndonePieceChange =Long.MAX_VALUE; // // if (isSnubbed()) // manager.decNbPeersSnubbed(); // // if( identityAdded ) { //remove identity // if( peer_id != null ) // PeerIdentityManager.removeIdentity( manager.getPeerIdentityDataID(), peer_id, getPort()); // else // Debug.out( "PeerIdentity added but peer_id == null !!!" ); // identityAdded = false; // } // // changePeerState( PEPeer.CLOSING ); // // }finally{ // closing_mon.exit(); // } // // //cancel any pending requests (on the manager side) // cancelRequests(); // // if( outgoing_have_message_aggregator != null ) { // outgoing_have_message_aggregator.destroy(); // } // // if( peer_exchange_item != null ) { // peer_exchange_item.destroy(); // } // // if( outgoing_piece_message_handler != null ) { // outgoing_piece_message_handler.destroy(); // } // // if( connection != null ) { //can be null if close is called within ::<init>::, like when the given port is invalid // connection.close(); // } // // if ( ip_resolver_request != null ){ // ip_resolver_request.cancel(); // } // // removeAvailability(); // // changePeerState( PEPeer.DISCONNECTED ); // // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, "Peer connection closed: " + reason)); // // if( !externally_closed ) { //if closed internally, notify manager, otherwise we assume it already knows // manager.peerConnectionClosed( this, connect_failed, network_failure ); // } // // setPriorityConnection( false ); // /* // * all managed references should have been removed by now // * add to recently disconnected list and null some stuff to make the object lighter // */ // // outgoing_have_message_aggregator = null; // peer_exchange_item = null; // outgoing_piece_message_handler = null; // plugin_connection = null; // // // only save stats if it's worth doing so; ignore rapid connect-disconnects // if (peer_stats.getTotalDataBytesReceived() > 0 || peer_stats.getTotalDataBytesSent() > 0 || SystemTime.getCurrentTime() - connection_established_time > 30 * 1000) // recentlyDisconnected.put(mySessionID, this); // } // // public PEPeerTransport reconnect(boolean tryUDP, boolean tryIPv6) { // // boolean use_tcp = isTCP() && !(tryUDP && getUDPListenPort() > 0); // // if ((use_tcp && getTCPListenPort() > 0) || (!use_tcp && getUDPListenPort() > 0)) // { // boolean use_crypto = getPeerItemIdentity().getHandshakeType() == PeerItemFactory.HANDSHAKE_TYPE_CRYPTO; // // PEPeerTransport new_conn = // PEPeerTransportFactory.createTransport( // manager, // getPeerSource(), // tryIPv6 && alternativeAddress != null ? alternativeAddress.getHostAddress() : getIp(), // getTCPListenPort(), // getUDPListenPort(), // use_tcp, // use_crypto, // crypto_level, // null ); // // // log to both relations // Logger.log(new LogEvent(new Object[] {this, new_conn},LOGID,"attempting to reconnect, creating new connection")); // if (new_conn instanceof PEPeerTransportProtocol) // { // PEPeerTransportProtocol pt = (PEPeerTransportProtocol) new_conn; // pt.checkForReconnect(mySessionID); // // carry over the alt address in case the reconnect fails and we try again with ipv6 // pt.alternativeAddress = alternativeAddress; // // } // // manager.addPeer( new_conn ); // // return (new_conn); // } else // { // return (null); // } // } // // /* (non-Javadoc) // * @see org.gudy.azureus2.core3.peer.impl.PEPeerTransport#isSafeForReconnect() // */ // public boolean isSafeForReconnect() { // return allowReconnect; // } // // // private void checkForReconnect(HashWrapper oldID) // { // PEPeerTransportProtocol oldTransport = recentlyDisconnected.remove(oldID); // // if(oldTransport != null) // { // Logger.log(new LogEvent(this,LOGID,LogAlert.AT_INFORMATION,"reassociating stats from "+oldTransport+" with this connection")); // peerSessionID = oldTransport.peerSessionID; // peer_stats = oldTransport.peer_stats; // peer_stats.setPeer(this); // unchokedTimeTotal += oldTransport.unchokedTimeTotal; // unchokedTime += oldTransport.unchokedTime; // setSnubbed(oldTransport.isSnubbed()); // snubbed = oldTransport.snubbed; // last_good_data_time = oldTransport.last_good_data_time; // } // } // // private void generateSessionId() // { // SHA1Hasher sha1 = new SHA1Hasher(); // sha1.update(sessionSecret); // sha1.update(manager.getHash()); // sha1.update(getIp().getBytes()); // mySessionID = sha1.getHash(); // checkForReconnect(mySessionID); // } // // private void addAvailability() // { // if (!availabilityAdded &&!closing &&peerHavePieces !=null &¤t_peer_state ==PEPeer.TRANSFERING) // { // final List peer_listeners_ref =peer_listeners_cow; // if (peer_listeners_ref !=null) // { // for (int i =0; i <peer_listeners_ref.size(); i++) // { // final PEPeerListener peerListener =(PEPeerListener) peer_listeners_ref.get(i); // peerListener.addAvailability(this, peerHavePieces); // } // availabilityAdded =true; // } // } // } // // private void removeAvailability() // { // if (availabilityAdded &&peerHavePieces !=null) // { // final List peer_listeners_ref =peer_listeners_cow; // if (peer_listeners_ref !=null) // { // for (int i =0; i <peer_listeners_ref.size(); i++) // { // final PEPeerListener peerListener =(PEPeerListener) peer_listeners_ref.get(i); // peerListener.removeAvailability(this, peerHavePieces); // } // } // availabilityAdded =false; // } // peerHavePieces =null; // } // // // // protected void sendBTHandshake() { // if ( !handshake_sent ){ // BTHandshake handshake = new BTHandshake( manager.getHash(), // manager.getPeerId(), // manager.isExtendedMessagingEnabled(), other_peer_handshake_version ); // // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, // "Sending handshake with reserved bytes: " + // ByteFormatter.nicePrint(handshake.getReserved(), false))); // // /** // * AMC's hopefully temporary debug code - some Az clients out there appear to be be // * AZMP neutered and communicating using LTEP instead. Let's bug the user if // * this happens so that I know about it. // */ // if (Constants.isCVSVersion()) { // byte[] reserved = handshake.getReserved(); // boolean supports_azmp = (reserved[0] & 128) == 128; // boolean supports_ltep = (reserved[5] & 16) == 16; // if (supports_ltep && !supports_azmp) { // Logger.log(new LogAlert(this, LogAlert.UNREPEATABLE, LogAlert.AT_ERROR, // "AZMP support has failed in Azureus, please report this in the " + // "<a href=\"http://forum.vuze.com/forum.jspa?forumID=4\">CVS bug report forum</a>.\n" + // "Debug data: " + ByteFormatter.nicePrint(reserved) // )); // } // } // // connection.getOutgoingMessageQueue().addMessage(handshake, false); // } // } // // // We could do this in a more automated way in future, but hardcoded is simple and quick, // // so we'll do that instead. :) // static Map lt_ext_map = UTPeerExchange.ENABLED ? Collections.singletonMap("ut_pex", new Integer(1) ) : Collections.EMPTY_MAP; // // private void sendLTHandshake() { // String client_name = Constants.AZUREUS_NAME + " " + Constants.AZUREUS_VERSION; // int localTcpPort = TCPNetworkManager.getSingleton().getTCPListeningPortNumber(); // String tcpPortOverride = COConfigurationManager.getStringParameter("TCP.Listen.Port.Override"); // try // { // localTcpPort = Integer.parseInt(tcpPortOverride); // } catch (NumberFormatException e) {} // ignore as invalid input // boolean require_crypto = NetworkManager.getCryptoRequired( manager.getAdapter().getCryptoLevel()); // // Map data_dict = new HashMap(); // data_dict.put("m", lt_ext_map); // data_dict.put("v", client_name); // data_dict.put("p", new Integer(localTcpPort)); // data_dict.put("e", new Long(require_crypto ? 1L : 0L)); // data_dict.put("upload_only", new Long(manager.isSeeding() && !ENABLE_LAZY_BITFIELD ? 1L : 0L)); // InetAddress defaultV6 = NetworkAdmin.getSingleton().hasIPV6Potential(true) ? NetworkAdmin.getSingleton().getDefaultPublicAddressV6() : null; // if(defaultV6 != null) // data_dict.put("ipv6",defaultV6.getAddress()); // LTHandshake lt_handshake = new LTHandshake( // data_dict, other_peer_bt_lt_ext_version // ); // connection.getOutgoingMessageQueue().addMessage(lt_handshake, false); // } // // private void sendAZHandshake() { // final Message[] avail_msgs = MessageManager.getSingleton().getRegisteredMessages(); // final String[] avail_ids = new String[avail_msgs.length]; // final byte[] avail_vers = new byte[avail_msgs.length]; // // for (int i = 0; i < avail_msgs.length; i++) // { // avail_ids[i] = avail_msgs[i].getID(); // avail_vers[i] = avail_msgs[i].getVersion(); // } // // int local_tcp_port = TCPNetworkManager.getSingleton().getTCPListeningPortNumber(); // int local_udp_port = UDPNetworkManager.getSingleton().getUDPListeningPortNumber(); // int local_udp2_port = UDPNetworkManager.getSingleton().getUDPNonDataListeningPortNumber(); // String tcpPortOverride = COConfigurationManager.getStringParameter("TCP.Listen.Port.Override"); // // try // { // local_tcp_port = Integer.parseInt(tcpPortOverride); // } catch (NumberFormatException e) // {} // ignore as invalid input // // boolean require_crypto = NetworkManager.getCryptoRequired(manager.getAdapter().getCryptoLevel()); // // /* // * we always send the Az-handshake immediately after the BT-handshake, before decoding the // * other side's Az-handshake, thus there should be no peerSessionID unless this is a // * reconnect // */ // if(peerSessionID != null) // Logger.log(new LogEvent(this, LOGID, LogEvent.LT_INFORMATION,"notifying peer of reconnect attempt")); // // AZHandshake az_handshake = new AZHandshake( // AZPeerIdentityManager.getAZPeerIdentity(), // mySessionID, // peerSessionID, // Constants.AZUREUS_NAME, // Constants.AZUREUS_VERSION, // local_tcp_port, // local_udp_port, // local_udp2_port, // NetworkAdmin.getSingleton().hasIPV6Potential(true) ? NetworkAdmin.getSingleton().getDefaultPublicAddressV6() : null, // avail_ids, // avail_vers, // require_crypto ? AZHandshake.HANDSHAKE_TYPE_CRYPTO : AZHandshake.HANDSHAKE_TYPE_PLAIN, // other_peer_handshake_version, // manager.isSeeding() && !ENABLE_LAZY_BITFIELD); // // connection.getOutgoingMessageQueue().addMessage( az_handshake, false ); // } // // public int getPeerState() { return current_peer_state; } // // public boolean isDownloadPossible() // { // if (!closing &&!choked_by_other_peer) // { // if (lastNeededUndonePieceChange <piecePicker.getNeededUndonePieceChange()) // { // checkInterested(); // lastNeededUndonePieceChange =piecePicker.getNeededUndonePieceChange(); // } // if (interested_in_other_peer &¤t_peer_state ==PEPeer.TRANSFERING) // return true; // } // return false; // } // // // public int getPercentDoneInThousandNotation() // { // long total_done = getBytesDownloaded(); // // return (int)((total_done *1000) /diskManager.getTotalLength()); // } // // public boolean transferAvailable() { // return (!choked_by_other_peer && interested_in_other_peer); // } // // // // private void printRequestStats() { // if( SHOW_DISCARD_RATE_STATS ) { // final float discard_perc = (requests_discarded * 100F) / ((requests_completed + requests_recovered + requests_discarded) * 1F); // final float discard_perc_end = (requests_discarded_endgame * 100F) / ((requests_completed + requests_recovered + requests_discarded_endgame) * 1F); // final float recover_perc = (requests_recovered * 100F) / ((requests_recovered + requests_discarded) * 1F); // System.out.println( "c="+requests_completed+ " d="+requests_discarded+ " de="+requests_discarded_endgame+ " r="+requests_recovered+ " dp="+discard_perc+ "% dpe="+discard_perc_end+ "% rp="+recover_perc+ "%" ); // } // } // // // // // /** // * Checks if this peer is a seed or not by trivially checking if // * thier Have bitflags exisits and shows a number of bits set equal // * to the torrent # of pieces (and the torrent # of pieces is >0) // */ // private void checkSeed() // { // // seed implicitly means *something* to send (right?) // if (peerHavePieces !=null && nbPieces >0) // setSeed((peerHavePieces.nbSet ==nbPieces)); // else // setSeed(false); // // if(manager.isSeeding() && isSeed()) // // peer is a real seed so it's also a relative seed // relativeSeeding |= RELATIVE_SEEDING_UPLOAD_ONLY_SEED; // else if(manager.isSeeding() && (relativeSeeding & RELATIVE_SEEDING_UPLOAD_ONLY_INDICATED) != 0) // // peer indicated upload-only, we're seeding so he's a relative seed // relativeSeeding |= RELATIVE_SEEDING_UPLOAD_ONLY_SEED; // else if(peerHavePieces !=null && nbPieces > 0) // { // int piecesDone = manager.getPiecePicker().getNbPiecesDone(); // DiskManagerPiece[] dmPieces = diskManager.getPieces(); // boolean couldBeSeed = true; // // if(!manager.isSeeding() && (relativeSeeding & RELATIVE_SEEDING_UPLOAD_ONLY_INDICATED) != 0) // { /* // * peer indicated upload-only, check if we can use any of the data, otherwise flag // * as relative seed. Useful to disconnect not-useful pseudo-seeds during downloading // */ // for(int i = peerHavePieces.start;i <= peerHavePieces.end;i++) // { // // relative seed if peer doesn't have the piece, we already have it or we don't need it // couldBeSeed &= !peerHavePieces.flags[i] || dmPieces[i].isDone() || !dmPieces[i].isNeeded(); // if(!couldBeSeed) // break; // } // } else if(manager.isSeeding() && piecesDone <= peerHavePieces.nbSet) // { // we're seeding, check if peer has all the data we have (and more), flag as relative seed if so // for(int i = peerHavePieces.start;i <= peerHavePieces.end;i++) // { // // relative seed if we don't have the piece or we have it and the peer has it too // couldBeSeed &= !(dmPieces[i].isDone()) || peerHavePieces.flags[i]; // if(!couldBeSeed) // break; // } // } else // couldBeSeed = false; // // if(couldBeSeed) // relativeSeeding |= RELATIVE_SEEDING_UPLOAD_ONLY_SEED; // else // relativeSeeding &= ~RELATIVE_SEEDING_UPLOAD_ONLY_SEED; // } else // relativeSeeding &= ~RELATIVE_SEEDING_UPLOAD_ONLY_SEED; // // } // // // public DiskManagerReadRequest request(final int pieceNumber, final int pieceOffset, final int pieceLength) { // final DiskManagerReadRequest request =manager.createDiskManagerRequest(pieceNumber, pieceOffset, pieceLength); // if (current_peer_state != TRANSFERING) { // manager.requestCanceled(request); // return null; // } // boolean added =false; // try{ // requested_mon.enter(); // // if (!requested.contains(request)) // { // requested.add(request); // added =true; // } // }finally{ // // requested_mon.exit(); // } // // if (added) // { // connection.getOutgoingMessageQueue().addMessage( new BTRequest( pieceNumber, pieceOffset, pieceLength, other_peer_request_version ), false ); // _lastPiece =pieceNumber; // // try{ // recent_outgoing_requests_mon.enter(); // // recent_outgoing_requests.put( request, null ); // }finally{ // recent_outgoing_requests_mon.exit(); // } // return request; // } // return null; // } // // public int // getRequestIndex( // DiskManagerReadRequest request ) // { // try{ // requested_mon.enter(); // // return( requested.indexOf( request )); // // }finally{ // // requested_mon.exit(); // } // } // // public void sendCancel( DiskManagerReadRequest request ) { // if ( current_peer_state != TRANSFERING ) return; // if ( hasBeenRequested( request ) ) { // removeRequest( request ); // connection.getOutgoingMessageQueue().addMessage( new BTCancel( request.getPieceNumber(), request.getOffset(), request.getLength(), other_peer_cancel_version ), false ); // } // } // // // public void sendHave( int pieceNumber ) { // if ( current_peer_state != TRANSFERING || pieceNumber == manager.getHiddenPiece()) return; // //only force if the other peer doesn't have this piece and is not yet interested or we;ve disabled // // aggregation // final boolean force =!other_peer_interested_in_me &&peerHavePieces !=null &&!peerHavePieces.flags[pieceNumber]; // // outgoing_have_message_aggregator.queueHaveMessage( pieceNumber, force || have_aggregation_disabled ); // checkInterested(); // } // // // public void sendChoke() { // if ( current_peer_state != TRANSFERING ) return; // // //System.out.println( "["+(System.currentTimeMillis()/1000)+"] " +connection + " choked"); // // connection.getOutgoingMessageQueue().addMessage( new BTChoke( other_peer_choke_version ), false ); // choking_other_peer = true; // is_optimistic_unchoke = false; // // if(outgoing_piece_message_handler != null) // { // outgoing_piece_message_handler.removeAllPieceRequests(); // outgoing_piece_message_handler.destroy(); // outgoing_piece_message_handler = null; // } // } // // // public void sendUnChoke() { // if ( current_peer_state != TRANSFERING ) return; // // //System.out.println( "["+(System.currentTimeMillis()/1000)+"] " +connection + " unchoked"); // if(outgoing_piece_message_handler == null) // { // outgoing_piece_message_handler = new OutgoingBTPieceMessageHandler( // this, // connection.getOutgoingMessageQueue(), // new OutgoingBTPieceMessageHandlerAdapter() // { // public void // diskRequestCompleted( // long bytes) // { // peer_stats.diskReadComplete( bytes ); // } // }, // other_peer_piece_version); // } // // // // choking_other_peer = false; // set this first as with pseudo peers we can effectively synchronously act // // on the unchoke advice and we don't want that borking with choked still set // // connection.getOutgoingMessageQueue().addMessage( new BTUnchoke(other_peer_unchoke_version), false ); // } // // // private void sendKeepAlive() { // if ( current_peer_state != TRANSFERING ) return; // // if( outgoing_have_message_aggregator.hasPending() ) { // outgoing_have_message_aggregator.forceSendOfPending(); // } // else { // connection.getOutgoingMessageQueue().addMessage( new BTKeepAlive(other_peer_keep_alive_version), false ); // } // } // // private void sendMainlineDHTPort() { // if (!this.ml_dht_enabled) {return;} // MainlineDHTProvider provider = getDHTProvider(); // if (provider == null) {return;} // Message message = new BTDHTPort(provider.getDHTPort()); // connection.getOutgoingMessageQueue().addMessage(message, false); // } // // // // /** // * Global checkInterested method. // * Early-out scan of pieces to determine if the peer is interesting or not. // * They're interesting if they have a piece that we Need and isn't Done // */ // public void checkInterested() // { // if (closing ||peerHavePieces ==null ||peerHavePieces.nbSet ==0) // return; // // boolean is_interesting = false; // if (piecePicker.hasDownloadablePiece()) // { // there is a piece worth being interested in // if (!isSeed() && !isRelativeSeed()) // { // check individually if don't have all // for (int i =peerHavePieces.start; i <=peerHavePieces.end; i++ ) // { // if (peerHavePieces.flags[i] && diskManager.isInteresting(i)) // { // is_interesting = true; // break; // } // } // } else // is_interesting =true; // } // // if (is_interesting &&!interested_in_other_peer) // connection.getOutgoingMessageQueue().addMessage(new BTInterested(other_peer_interested_version), false); // else if (!is_interesting &&interested_in_other_peer) // connection.getOutgoingMessageQueue().addMessage(new BTUninterested(other_peer_uninterested_version), false); // // interested_in_other_peer = is_interesting; // } // // /** @deprecated no longer used by CVS code // * Checks if a particular piece makes us interested in the peer // * @param pieceNumber the piece number that has been received // */ // /* // private void checkInterested(int pieceNumber) // { // if (closing) // return; // // // Do we need this piece and it's not Done? // if (!interested_in_other_peer &&diskManager.isInteresting(pieceNumber)) // { // connection.getOutgoingMessageQueue().addMessage( new BTInterested(), false ); // interested_in_other_peer =true; // } // } // */ // // // // // /** // * Private method to send the bitfield. // */ // private void sendBitField() // { // if (closing) // return; // // //In case we're in super seed mode, we don't send our bitfield // if (manager.isSuperSeedMode()) // return; // // //create bitfield // final DirectByteBuffer buffer =DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG, (nbPieces +7) /8); // final DiskManagerPiece[] pieces =diskManager.getPieces(); // // // int num_pieces = pieces.length; // // HashSet lazies = null; // int[] lazy_haves = null; // // if (ENABLE_LAZY_BITFIELD) // { // int bits_in_first_byte = Math.min(num_pieces, 8); // int last_byte_start_bit = (num_pieces / 8) * 8; // int bits_in_last_byte = num_pieces - last_byte_start_bit; // if (bits_in_last_byte == 0) // { // bits_in_last_byte = 8; // last_byte_start_bit -= 8; // } // lazies = new HashSet(); // // one bit from first byte // int first_byte_entry = rnd.nextInt(bits_in_first_byte); // if (pieces[first_byte_entry].isDone()) // { // lazies.add(new MutableInteger(first_byte_entry)); // } // // one bit from last byte // int last_byte_entry = last_byte_start_bit + rnd.nextInt(bits_in_last_byte); // if (pieces[last_byte_entry].isDone()) // { // lazies.add(new MutableInteger(last_byte_entry)); // } // // random others missing // int other_lazies = rnd.nextInt(16) + 4; // for (int i = 0; i < other_lazies; i++) // { // int random_entry = rnd.nextInt(num_pieces); // if (pieces[random_entry].isDone()) // { // lazies.add(new MutableInteger(random_entry)); // } // } // int num_lazy = lazies.size(); // if (num_lazy == 0) // { // lazies = null; // } else // { // lazy_haves = new int[num_lazy]; // Iterator it = lazies.iterator(); // for (int i = 0; i < num_lazy; i++) // { // int lazy_have = ((MutableInteger) it.next()).getValue(); // lazy_haves[i] = lazy_have; // } // if (num_lazy > 1) // { // for (int i = 0; i < num_lazy; i++) // { // int swap = rnd.nextInt(num_lazy); // if (swap != i) // { // int temp = lazy_haves[swap]; // lazy_haves[swap] = lazy_haves[i]; // lazy_haves[i] = temp; // } // } // } // } // } // // int bToSend = 0; // int i = 0; // // MutableInteger mi = new MutableInteger(0); // // int hidden_piece = manager.getHiddenPiece(); // // for (; i <num_pieces; i++ ){ // // if ((i %8) ==0){ // bToSend =0; // } // // bToSend = bToSend << 1; // // if (pieces[i].isDone() && i != hidden_piece ){ // // if ( lazies != null ){ // // mi.setValue(i); // // if ( lazies.contains( mi )){ // // // System.out.println( "LazySet: " + getIp() + " -> " + i ); // // }else{ // bToSend += 1; // } // }else{ // bToSend += 1; // } // } // // if ((i %8) ==7){ // buffer.put(DirectByteBuffer.SS_BT, (byte) bToSend); // } // } // // if ((i %8) !=0){ // // bToSend = bToSend << (8 - (i % 8)); // buffer.put( DirectByteBuffer.SS_BT, (byte)bToSend ); // } // // buffer.flip( DirectByteBuffer.SS_BT ); // // connection.getOutgoingMessageQueue().addMessage(new BTBitfield(buffer, other_peer_bitfield_version ), false); // // if ( lazy_haves != null ){ // // final int[] f_lazy_haves = lazy_haves; // // SimpleTimer.addEvent("LazyHaveSender", SystemTime.getCurrentTime() + 1000 + rnd.nextInt(2000), new TimerEventPerformer() // { // int next_have = 0; // // public void perform(TimerEvent event) { // int lazy_have = f_lazy_haves[next_have++]; // // System.out.println( "LazyDone: " + getIp() + " -> " + // // lazy_have ); // // if ( current_peer_state == TRANSFERING ){ // // connection.getOutgoingMessageQueue().addMessage(new BTHave(lazy_have, other_peer_bt_have_version), false); // // if (next_have < f_lazy_haves.length && current_peer_state == TRANSFERING){ // // SimpleTimer.addEvent("LazyHaveSender", SystemTime.getCurrentTime() + rnd.nextInt(2000), this); // } // } // } // }); // } // // } // // // public byte[] getId() { return peer_id; } // public String getIp() { return ip; } // public InetAddress getAlternativeIPv6() { return alternativeAddress; } // public int getPort() { return port; } // // public int getTCPListenPort() { return tcp_listen_port; } // public int getUDPListenPort() { return udp_listen_port; } // public int getUDPNonDataListenPort() { return( udp_non_data_port ); } // // // public String getClient() { return client; } // // public boolean isIncoming() { return incoming; } // // // public boolean isOptimisticUnchoke() { return is_optimistic_unchoke && !isChokedByMe(); } // public void setOptimisticUnchoke( boolean is_optimistic ) { is_optimistic_unchoke = is_optimistic; } // // // public PEPeerControl getControl() { return manager; } // public PEPeerManager getManager() { return manager; } // public PEPeerStats getStats() { return peer_stats; } // // public int[] // getPriorityOffsets() // { // // normal peer has no special priority requirements // // return( null ); // } // // public boolean // requestAllocationStarts( // int[] base_priorities ) // { // return( false ); // } // // public void // requestAllocationComplete() // { // } // // /** // * @return null if no bitfield has been recieved yet // * else returns BitFlags indicating what pieces the peer has // */ // public BitFlags getAvailable() // { // return peerHavePieces; // } // public boolean isPieceAvailable(int pieceNumber) // { // if (peerHavePieces !=null) // return peerHavePieces.flags[pieceNumber]; // return false; // } // // public boolean isChokingMe() { return choked_by_other_peer; } // public boolean isChokedByMe() { return choking_other_peer; } // /** // * @return true if the peer is interesting to us // */ // public boolean isInteresting() { return interested_in_other_peer; } // /** // * @return true if the peer is interested in what we're offering // */ // public boolean isInterested() { return other_peer_interested_in_me; } // public boolean isSeed() { return seeding; } // public boolean isRelativeSeed() { return (relativeSeeding & RELATIVE_SEEDING_UPLOAD_ONLY_SEED) != 0; } // // private void // setSeed( // boolean s ) // { // if ( seeding != s ){ // // seeding = s; // // if ( peer_exchange_item != null && s){ // // peer_exchange_item.seedStatusChanged(); // } // } // } // // public boolean isSnubbed() { return snubbed !=0; } // // public long getSnubbedTime() // { // if (snubbed ==0) // return 0; // final long now =SystemTime.getCurrentTime(); // if (now <snubbed) // snubbed =now -26; // odds are ... // return now -snubbed; // } // // public void setSnubbed(boolean b) // { // if (!closing) // { // final long now =SystemTime.getCurrentTime(); // if (!b) // { // if (snubbed !=0) // { // snubbed =0; // manager.decNbPeersSnubbed(); // if (!choked_by_other_peer) // unchokedTime =now; // } // } else if (snubbed ==0) // { // snubbed =now; // manager.incNbPeersSnubbed(); // if (!choked_by_other_peer) // { // final long unchoked =now -unchokedTime; // if (unchoked >0) // unchokedTimeTotal +=unchoked; // } // } // } // } // public void setUploadHint(int spreadTime) { spreadTimeHint = spreadTime; } // public int getUploadHint() { return spreadTimeHint; } // public void setUniqueAnnounce(int _uniquePiece) { uniquePiece = _uniquePiece; } // public int getUniqueAnnounce() { return uniquePiece; } // // // // public Object getData(String key) { // // return( getUserData( key )); // } // // public void // setData(String key, Object value) // { // setUserData( key, value ); // } // // /** To retreive arbitrary objects against a peer. */ // public Object getUserData (Object key) { // try{ // general_mon.enter(); // // if (data == null) return null; // return data.get(key); // }finally{ // // general_mon.exit(); // } // } // // /** To store arbitrary objects against a peer. */ // public void setUserData (Object key, Object value) { // try{ // general_mon.enter(); // // if (data == null) { // data = new LightHashMap(); // } // if (value == null) { // if (data.containsKey(key)){ // data.remove(key); // if ( data.size()==0 ){ // data = null; // } // } // } else { // data.put(key, value); // } // }finally{ // // general_mon.exit(); // } // } // // // public String // getIPHostName() // { // if ( ip_resolved == null ){ // // ip_resolved = ip; // // ip_resolver_request = IPToHostNameResolver.addResolverRequest( // ip_resolved, // new IPToHostNameResolverListener() // { // public final void // IPResolutionComplete( // String res, // boolean ok ) // { // ip_resolved = res; // } // }); // } // // return( ip_resolved ); // } // // // // private void cancelRequests() // { // if (!closing) { //cancel any unsent requests in the queue // final Message[] type ={new BTRequest(-1, -1, -1, other_peer_request_version)}; // connection.getOutgoingMessageQueue().removeMessagesOfType(type, false); // } // if (requested !=null &&requested.size() >0) { // try{ // requested_mon.enter(); // // if (!closing) // { // may have unchoked us, gotten a request, then choked without filling it - snub them // // if they actually have data coming in, they'll be unsnubbed as soon as it writes // final long timeSinceGoodData =getTimeSinceGoodDataReceived(); // if (timeSinceGoodData ==-1 ||timeSinceGoodData >60 *1000) // setSnubbed(true); // } // for (int i = requested.size() - 1; i >= 0; i--) { // final DiskManagerReadRequest request =(DiskManagerReadRequest) requested.remove(i); // manager.requestCanceled(request); // } // }finally{ // // requested_mon.exit(); // } // } // } // // public int // getMaxNbRequests() // { // return( -1 ); // } // // public int // getNbRequests() { // return requested.size(); // } // // /** // * // * @return may be null for performance purposes // */ // // public List // getExpiredRequests() { // List result = null; // // // this is frequently called, hence we operate without a monitor and // // take the hit of possible exceptions due to concurrent list // // modification (only out-of-bounds can occur) // // try{ // for (int i =requested.size() -1; i >=0; i--) // { // final DiskManagerReadRequest request = (DiskManagerReadRequest) requested.get(i); // // if (request.isExpired()){ // // if ( result == null ){ // // result = new ArrayList(); // } // // result.add(request); // } // } // // return( result ); // // }catch(Throwable e ){ // // return result; // } // } // // // private boolean hasBeenRequested( DiskManagerReadRequest request ) { // try{ requested_mon.enter(); // // return requested.contains( request ); // } // finally{ requested_mon.exit(); } // } // // /** @deprecated no longer used by CVS code // */ // protected void // addRequest( // DiskManagerReadRequest request ) // { // try{ // requested_mon.enter(); // // requested.add(request); // }finally{ // // requested_mon.exit(); // } // _lastPiece =request.getPieceNumber(); // } // // protected void // removeRequest( // DiskManagerReadRequest request ) // { // try{ // requested_mon.enter(); // // requested.remove(request); // }finally{ // // requested_mon.exit(); // } // final BTRequest msg = new BTRequest( request.getPieceNumber(), request.getOffset(), request.getLength(), other_peer_request_version ); // connection.getOutgoingMessageQueue().removeMessage( msg, false ); // msg.destroy(); // } // // private void // resetRequestsTime(final long now) // { // try{ // requested_mon.enter(); // // final int requestedSize =requested.size(); // for (int i =0; i <requestedSize; i++) // { // final DiskManagerReadRequest request =(DiskManagerReadRequest) requested.get(i); // if (request != null) // request.resetTime(now); // } // }finally{ // // requested_mon.exit(); // } // } // // // public String toString() { // if( connection != null && connection.isConnected() ) { // return connection + (isTCP()?" [":"(UDP) [") + client+ "]"; // } // return (isIncoming() ? "R: " : "L: ")+ ip + ":" + port + (isTCP()?" [":"(UDP) [") + client+ "]"; // } // // public String // getString() // { // return( toString()); // } // // // public void doKeepAliveCheck() { // final long now =SystemTime.getCurrentTime(); // final long wait_time =now -last_message_sent_time; // // if( last_message_sent_time == 0 || wait_time < 0 ) { // last_message_sent_time =now; //don't send if brand new connection // return; // } // // if( wait_time > 2*60*1000 ) { //2min keep-alive timer // sendKeepAlive(); // last_message_sent_time =now; //not quite true, but we don't want to queue multiple keep-alives before the first is actually sent // } // } // // // public boolean doTimeoutChecks() { // //Timeouts for states PEPeerTransport.CONNECTION_PENDING and // //PEPeerTransport.CONNECTION_CONNECTING are handled by the ConnectDisconnectManager // //so we don't need to deal with them here. // // final long now =SystemTime.getCurrentTime(); // //make sure we time out stalled connections // if( connection_state == PEPeerTransport.CONNECTION_FULLY_ESTABLISHED ) { // if (last_message_received_time >now) // last_message_received_time =now; // if (last_data_message_received_time >now) // last_data_message_received_time =now; // if (now -last_message_received_time >5*60*1000 // &&now -last_data_message_received_time >5*60*1000) { //5min timeout // // assume this is due to a network failure // // e.g. something that didn't close the TCP socket properly // // will attempt reconnect // closeConnectionInternally( "timed out while waiting for messages", false, true ); // return true; // } // } // //ensure we dont get stuck in the handshaking phases // else if( connection_state == PEPeerTransport.CONNECTION_WAITING_FOR_HANDSHAKE ) { // if (connection_established_time >now) // connection_established_time =now; // else if (now - connection_established_time > 3*60*1000 ) { //3min timeout // closeConnectionInternally( "timed out while waiting for handshake" ); // return true; // } // } // // return false; // } // // // // public void doPerformanceTuningCheck() { // Transport transport = connection.getTransport(); // // if( transport != null && peer_stats != null && outgoing_piece_message_handler != null ) { // // //send speed -based tuning // final long send_rate = peer_stats.getDataSendRate() + peer_stats.getProtocolSendRate(); // // if( send_rate >= 3125000 ) { // 25 Mbit/s // transport.setTransportMode( Transport.TRANSPORT_MODE_TURBO ); // outgoing_piece_message_handler.setRequestReadAhead( 256 ); // } // else if( send_rate >= 1250000 ) { // 10 Mbit/s // transport.setTransportMode( Transport.TRANSPORT_MODE_TURBO ); // outgoing_piece_message_handler.setRequestReadAhead( 128 ); // } // else if( send_rate >= 125000 ) { // 1 Mbit/s // if( transport.getTransportMode() < Transport.TRANSPORT_MODE_FAST ) { // transport.setTransportMode( Transport.TRANSPORT_MODE_FAST ); // } // outgoing_piece_message_handler.setRequestReadAhead( 32 ); // } // else if( send_rate >= 62500 ) { // 500 Kbit/s // outgoing_piece_message_handler.setRequestReadAhead( 16 ); // } // else if( send_rate >= 31250 ) { // 250 Kbit/s // outgoing_piece_message_handler.setRequestReadAhead( 8 ); // } // else if( send_rate >= 12500 ) { // 100 Kbit/s // outgoing_piece_message_handler.setRequestReadAhead( 4 ); // } // else { // outgoing_piece_message_handler.setRequestReadAhead( 2 ); // } // // // //receive speed -based tuning // final long receive_rate = peer_stats.getDataReceiveRate() + peer_stats.getProtocolReceiveRate(); // // if( receive_rate >= 1250000 ) { // 10 Mbit/s // transport.setTransportMode( Transport.TRANSPORT_MODE_TURBO ); // } // else if( receive_rate >= 125000 ) { // 1 Mbit/s // if( transport.getTransportMode() < Transport.TRANSPORT_MODE_FAST ) { // transport.setTransportMode( Transport.TRANSPORT_MODE_FAST ); // } // } // // } // } // // // // // public int getConnectionState() { return connection_state; } // // // // // public long getTimeSinceLastDataMessageReceived() { // if( last_data_message_received_time == -1 ) { //never received // return -1; // } // // final long now =SystemTime.getCurrentTime(); // // if (last_data_message_received_time >now) // last_data_message_received_time =now; //time went backwards // return now -last_data_message_received_time; // } // // public long getTimeSinceGoodDataReceived() // { // if (last_good_data_time ==-1) // return -1; // never received // final long now =SystemTime.getCurrentTime(); // if (last_good_data_time >now) // last_good_data_time =now; //time went backwards // return now -last_good_data_time; // } // // // public long getTimeSinceLastDataMessageSent() { // if( last_data_message_sent_time == -1 ) { //never sent // return -1; // } // final long now =SystemTime.getCurrentTime(); // if (last_data_message_sent_time >now) // last_data_message_sent_time =now; //time went backwards // return now -last_data_message_sent_time; // } // // // // // // public long getTimeSinceConnectionEstablished() { // if( connection_established_time == 0 ) { //fudge it while the transport is being connected // return 0; // } // final long now =SystemTime.getCurrentTime(); // if (connection_established_time >now) // connection_established_time =now; // return now -connection_established_time; // } // // public int // getConsecutiveNoRequestCount() // { // return( consecutive_no_request_count ); // } // // public void // setConsecutiveNoRequestCount( // int num ) // { // consecutive_no_request_count = num; // } // // protected void decodeBTHandshake( BTHandshake handshake ) { // // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, // "Received handshake with reserved bytes: " + // ByteFormatter.nicePrint(handshake.getReserved(), false))); // // PeerIdentityDataID my_peer_data_id = manager.getPeerIdentityDataID(); // // if(getConnectionState() == CONNECTION_FULLY_ESTABLISHED) // { // handshake.destroy(); // closeConnectionInternally("peer sent another handshake after the initial connect"); // } // // if( !Arrays.equals( manager.getHash(), handshake.getDataHash() ) ) { // closeConnectionInternally( "handshake has wrong infohash" ); // handshake.destroy(); // return; // } // // peer_id = handshake.getPeerId(); // // // Decode a client identification string from the given peerID // this.client_peer_id = this.client = StringInterner.intern(PeerClassifier.getClientDescription( peer_id )); // // //make sure the client type is not banned // if( !PeerClassifier.isClientTypeAllowed( client ) ) { // closeConnectionInternally( client+ " client type not allowed to connect, banned" ); // handshake.destroy(); // return; // } // // //make sure we are not connected to ourselves // if( Arrays.equals( manager.getPeerId(), peer_id ) ) { // manager.peerVerifiedAsSelf( this ); //make sure we dont do it again // closeConnectionInternally( "given peer id matches myself" ); // handshake.destroy(); // return; // } // // //make sure we are not already connected to this peer // boolean sameIdentity = PeerIdentityManager.containsIdentity( my_peer_data_id, peer_id, getPort()); // boolean sameIP = false; // // // //allow loopback connects for co-located proxy-based connections and testing // boolean same_allowed = COConfigurationManager.getBooleanParameter( "Allow Same IP Peers" ) || ip.equals( "127.0.0.1" ); // if( !same_allowed ){ // if( PeerIdentityManager.containsIPAddress( my_peer_data_id, ip )) { // sameIP = true; // } // } // // if( sameIdentity ) { // boolean close = true; // // if( connection.isLANLocal() ) { //this new connection is lan-local // // PEPeerTransport existing = manager.getTransportFromIdentity( peer_id ); // // if( existing != null ){ // // String existing_ip = existing.getIp(); // // // normally we don't allow a lan-local to replace a lan-local connection. There is // // however one exception - where the existing connection comes from the gateway address // // and therefore actually denotes an effectively non-lan-local connection. Unfortunately // // we don't have a good way of finding the default gateway, so just go for ending in .1 // // if ( !existing.isLANLocal() || // ( existing_ip.endsWith( ".1" ) && !existing_ip.equals( ip ))) { //so drop the existing connection if it is an external (non lan-local) one // // Debug.outNoStack( "Dropping existing non-lanlocal peer connection [" +existing+ "] in favour of [" + this + "]" ); // manager.removePeer( existing ); // close = false; // } // } // } // // if( close ) { // closeConnectionInternally( "peer matches already-connected peer id" ); // handshake.destroy(); // return; // } // } // // if( sameIP ) { // closeConnectionInternally( "peer matches already-connected IP address, duplicate connections not allowed" ); // handshake.destroy(); // return; // } // // //make sure we haven't reached our connection limit // final int maxAllowed = manager.getMaxNewConnectionsAllowed(); // if ( maxAllowed ==0 && // !manager.doOptimisticDisconnect( isLANLocal(), isPriorityConnection())) // { // final String msg = "too many existing peer connections [p" + // PeerIdentityManager.getIdentityCount( my_peer_data_id ) // +"/g" +PeerIdentityManager.getTotalIdentityCount() // +", pmx" +PeerUtils.MAX_CONNECTIONS_PER_TORRENT+ "/gmx" // +PeerUtils.MAX_CONNECTIONS_TOTAL+"/dmx" + manager.getMaxConnections()+ "]"; // //System.out.println( msg ); // closeConnectionInternally( msg ); // handshake.destroy(); // return; // } // // try{ // closing_mon.enter(); // // if( closing ){ // // final String msg = "connection already closing"; // // closeConnectionInternally( msg ); // // handshake.destroy(); // // return; // } // // if ( !PeerIdentityManager.addIdentity( my_peer_data_id, peer_id, getPort(), ip )){ // // closeConnectionInternally( "peer matches already-connected peer id" ); // // handshake.destroy(); // // return; // } // // identityAdded = true; // // }finally{ // // closing_mon.exit(); // } // // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, "In: has sent their handshake")); // // // Let's store the reserved bits somewhere so they can be examined later (externally). // handshake_reserved_bytes = handshake.getReserved(); // // /* // * Waiting until we've received the initiating-end's full handshake, before sending back our own, // * really should be the "proper" behavior. However, classic BT trackers running NAT checking will // * only send the first 48 bytes (up to infohash) of the peer handshake, skipping peerid, which means // * we'll never get their complete handshake, and thus never reply, which causes the NAT check to fail. // * So, we need to send our handshake earlier, after we've verified the infohash. // * // if( incoming ) { //wait until we've received their handshake before sending ours // sendBTHandshake(); // } // */ // // this.ml_dht_enabled = (handshake_reserved_bytes[7] & 1) == 1; // messaging_mode = decideExtensionProtocol(handshake); // // //extended protocol processing // if (messaging_mode == MESSAGING_AZMP) { // /** // * We log when a non-Azureus client claims to support extended messaging... // * Obviously other Azureus clients do, so there's no point logging about them! // */ // if (Logger.isEnabled() && client.indexOf("Azureus") == -1) { // Logger.log(new LogEvent(this, LOGID, "Handshake claims extended AZ " // + "messaging support... enabling AZ mode.")); // } // // // Ignore the handshake setting - wait for the AZHandshake to indicate // // support instead. // this.ml_dht_enabled = false; // // Transport transport = connection.getTransport(); // boolean enable_padding = transport.isTCP() && transport.isEncrypted(); // connection.getIncomingMessageQueue().setDecoder(new AZMessageDecoder()); // connection.getOutgoingMessageQueue().setEncoder(new AZMessageEncoder(enable_padding)); // // // We will wait until we get the Az handshake before considering the connection // // initialised. // this.sendAZHandshake(); // handshake.destroy(); // } // else if (messaging_mode == MESSAGING_LTEP) { // if (Logger.isEnabled()) { // Logger.log(new LogEvent(this, LOGID, "Enabling LT extension protocol support...")); // } // // connection.getIncomingMessageQueue().setDecoder(new LTMessageDecoder()); // connection.getOutgoingMessageQueue().setEncoder(new LTMessageEncoder(this)); // // generateSessionId(); // // /** // * We don't need to wait for the LT handshake, nor do we require it, nor // * does it matter if the LT handshake comes later, nor does it matter if // * it we receive it repeatedly. So there - we can initialise the connection // * right now. :P // */ // this.initPostConnection(handshake); // this.sendLTHandshake(); // } // else { // this.client = ClientIdentifier.identifyBTOnly(this.client_peer_id, this.handshake_reserved_bytes); // // connection.getIncomingMessageQueue().getDecoder().resumeDecoding(); // // this.initPostConnection(handshake); // } // // } // // private int decideExtensionProtocol(BTHandshake handshake) { // boolean supports_azmp = (handshake.getReserved()[0] & 128) == 128; // boolean supports_ltep = (handshake.getReserved()[5] & 16) == 16; // // if (!supports_azmp) { // if (supports_ltep) { // if (!manager.isExtendedMessagingEnabled()) { // if (Logger.isEnabled()) { // Logger.log(new LogEvent(this, LOGID, "Ignoring peer's LT extension protocol support," // + " as disabled for this download.")); // } // return MESSAGING_BT_ONLY; // LTEP is supported, but disabled. // } // return MESSAGING_LTEP; // LTEP is supported. // } // return MESSAGING_BT_ONLY; // LTEP isn't supported. // } // // if (!supports_ltep) { // // // Check if it is AZMP enabled. // if(!manager.isExtendedMessagingEnabled()) { // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, "Ignoring peer's extended AZ messaging support," // + " as disabled for this download.")); // return MESSAGING_BT_ONLY; // } // // // Check if the client is misbehaving... // else if( client.indexOf( "Plus!" ) != -1) { // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, "Handshake mistakingly indicates" // + " extended AZ messaging support...ignoring.")); // return MESSAGING_BT_ONLY; // } // // return MESSAGING_AZMP; // } // // boolean enp_major_bit = (handshake.getReserved()[5] & 2) == 2; // boolean enp_minor_bit = (handshake.getReserved()[5] & 1) == 1; // // // Only enable one of the blocks below. // String their_ext_preference = ((enp_major_bit == enp_minor_bit) ? "Force " : "Prefer ") + ((enp_major_bit) ? "AZMP" : "LTEP"); // // // Force AZMP block. // String our_ext_preference = "Force AZMP"; // boolean use_azmp = enp_major_bit || enp_minor_bit; // Anything other than Force LTEP, then we force AZMP to be used. // boolean we_decide = use_azmp; // // // Prefer AZMP block (untested). // /* // String our_ext_preference = "Prefer AZMP"; // boolean use_azmp = enp_major_bit; // Requires other client to prefer or force AZMP. // boolean we_decide = use_azmp && !enp_minor_bit; // We decide only if we are using AZMP and the other client didn't force it. // */ // // // Prefer LTEP block (untested). // /* // String our_ext_preference = "Prefer LTEP"; // boolean use_azmp = enp_major_bit && enp_minor_bit; // Only use it Force AZMP is enabled. // boolean we_decide = enp_minor_bit && !use_azmp; // We decide only if we are using LTEP and the other client didn't force it. // */ // // if (Logger.isEnabled()) { // String msg = "Peer supports both AZMP and LTEP: "; // msg += "\"" + our_ext_preference + "\"" + (we_decide ? ">" : "<") + ((our_ext_preference.equals(their_ext_preference)) ? "= " : " "); // msg += "\"" + their_ext_preference + "\" - using " + (use_azmp ? "AZMP" : "LTEP"); // Logger.log(new LogEvent(this, LOGID, msg)); // } // // return (use_azmp) ? MESSAGING_AZMP : MESSAGING_LTEP; // // } // // // protected void decodeLTHandshake(LTHandshake handshake) { // String lt_handshake_name = handshake.getClientName(); // if (lt_handshake_name != null) { // this.client_handshake = StringInterner.intern(lt_handshake_name); // this.client = StringInterner.intern(ClientIdentifier.identifyLTEP(this.client_peer_id, this.client_handshake, this.peer_id)); // } // if(handshake.getTCPListeningPort() > 0 ) // { // // Only use crypto if it was specifically requested. Not sure what the default // // should be if they haven't indicated... // Boolean crypto_requested = handshake.isCryptoRequested(); // byte handshake_type = (crypto_requested != null && crypto_requested.booleanValue()) ? PeerItemFactory.HANDSHAKE_TYPE_CRYPTO : PeerItemFactory.HANDSHAKE_TYPE_PLAIN; // tcp_listen_port = handshake.getTCPListeningPort(); // peer_item_identity = PeerItemFactory.createPeerItem( // ip, tcp_listen_port, // PeerItem.convertSourceID(peer_source), // handshake_type, // udp_listen_port, // probably none // crypto_level, // 0 // ); // } // // if(handshake.isUploadOnly()) // { // relativeSeeding |= RELATIVE_SEEDING_UPLOAD_ONLY_INDICATED; // checkSeed(); // } // // if(AddressUtils.isGlobalAddressV6(handshake.getIPv6())) // alternativeAddress = handshake.getIPv6(); // // // // LTMessageEncoder encoder = (LTMessageEncoder)connection.getOutgoingMessageQueue().getEncoder(); // encoder.updateSupportedExtensions(handshake.getExtensionMapping()); // this.ut_pex_enabled = UTPeerExchange.ENABLED && encoder.supportsUTPEX(); // // /** // * Grr... this is one thing which I'm sure I had figured out much better than it is here... // * Basically, we "initialise" the connection at the BT handshake stage, because the LT handshake // * is mandatory or required to come first (unlike the AZ one). // * // * But when we receive an LT handshake, we have to "initialise" it like we did previously, because // * we may have to set the internals up to indicate if PEX is supported. // * // * I'm not entirely sure this method is meant to be called more than once, and I'm less convinced // * that it's safe to do it repeatedly over the lifetime of a properly-initialised, actually-doing-stuff // * connection... but I'll worry about that later. // */ // this.doPostHandshakeProcessing(); // // handshake.destroy(); // } // // protected void decodeAZHandshake(AZHandshake handshake) { // if(getConnectionState() == CONNECTION_FULLY_ESTABLISHED) // { // handshake.destroy(); // closeConnectionInternally("peer sent another az-handshake after the intial connect"); // } // // this.client_handshake = StringInterner.intern(handshake.getClient()); // this.client_handshake_version = StringInterner.intern(handshake.getClientVersion()); // this.client = StringInterner.intern(ClientIdentifier.identifyAZMP(this.client_peer_id, client_handshake, client_handshake_version, this.peer_id)); // // if (handshake.getTCPListenPort() > 0) // { // use the ports given in handshake // tcp_listen_port = handshake.getTCPListenPort(); // udp_listen_port = handshake.getUDPListenPort(); // udp_non_data_port = handshake.getUDPNonDataListenPort(); // final byte type = handshake.getHandshakeType() == AZHandshake.HANDSHAKE_TYPE_CRYPTO ? PeerItemFactory.HANDSHAKE_TYPE_CRYPTO : PeerItemFactory.HANDSHAKE_TYPE_PLAIN; // // // remake the id using the peer's remote listen port instead of // // their random local port // peer_item_identity = PeerItemFactory.createPeerItem(ip, tcp_listen_port, PeerItem.convertSourceID(peer_source), type, udp_listen_port, crypto_level, 0); // } // // if(AddressUtils.isGlobalAddressV6(handshake.getIPv6())) // alternativeAddress = handshake.getIPv6(); // // // if(handshake.getReconnectSessionID() != null) // { // if (Logger.isEnabled()) { // Logger.log(new LogEvent(this, LOGID, LogEvent.LT_INFORMATION, "received reconnect request ID: "+handshake.getReconnectSessionID().toBase32String())); // } // checkForReconnect(handshake.getReconnectSessionID()); // } // // if(handshake.getRemoteSessionID() != null) // peerSessionID = handshake.getRemoteSessionID(); // // if (handshake.isUploadOnly()) // { // relativeSeeding |= RELATIVE_SEEDING_UPLOAD_ONLY_INDICATED; // checkSeed(); // } // // // String[] supported_message_ids = handshake.getMessageIDs(); // byte[] supported_message_versions = handshake.getMessageVersions(); // // //find mutually available message types // final ArrayList messages = new ArrayList(); // // for (int i = 0; i < handshake.getMessageIDs().length; i++) // { // Message msg = MessageManager.getSingleton().lookupMessage(supported_message_ids[i]); // if (msg != null) // { // mutual support! // messages.add(msg); // // String id = msg.getID(); // byte supported_version = supported_message_versions[i]; // // // we can use == safely // if (id == BTMessage.ID_BT_BITFIELD) // other_peer_bitfield_version = supported_version; // else if (id == BTMessage.ID_BT_CANCEL) // other_peer_cancel_version = supported_version; // else if (id == BTMessage.ID_BT_CHOKE) // other_peer_choke_version = supported_version; // else if (id == BTMessage.ID_BT_HANDSHAKE) // other_peer_handshake_version = supported_version; // else if (id == BTMessage.ID_BT_HAVE) // other_peer_bt_have_version = supported_version; // else if (id == BTMessage.ID_BT_INTERESTED) // other_peer_interested_version = supported_version; // else if (id == BTMessage.ID_BT_KEEP_ALIVE) // other_peer_keep_alive_version = supported_version; // else if (id == BTMessage.ID_BT_PIECE) // other_peer_piece_version = supported_version; // else if (id == BTMessage.ID_BT_UNCHOKE) // other_peer_unchoke_version = supported_version; // else if (id == BTMessage.ID_BT_UNINTERESTED) // other_peer_uninterested_version = supported_version; // else if (id == BTMessage.ID_BT_REQUEST) // other_peer_request_version = supported_version; // else if (id == AZMessage.ID_AZ_PEER_EXCHANGE) // other_peer_pex_version = supported_version; // else if (id == AZMessage.ID_AZ_REQUEST_HINT) // other_peer_az_request_hint_version = supported_version; // else if (id == AZMessage.ID_AZ_HAVE) // other_peer_az_have_version = supported_version; // else if (id == AZMessage.ID_AZ_BAD_PIECE) // other_peer_az_bad_piece_version = supported_version; // else if (id == BTMessage.ID_BT_DHT_PORT) // this.ml_dht_enabled = true; // else // { // // we expect unmatched ones here at the moment as we're not // // dealing with them yet or they don't make sense. // // for example AZVER // } // } // } // // supported_messages = (Message[]) messages.toArray(new Message[messages.size()]); // // if(outgoing_piece_message_handler != null){ // outgoing_piece_message_handler.setPieceVersion(other_peer_piece_version); // } // // if ( outgoing_have_message_aggregator != null ){ // outgoing_have_message_aggregator.setHaveVersion(other_peer_bt_have_version, other_peer_az_have_version); // } // // this.initPostConnection(handshake); // } // // private void initPostConnection(Message handshake) { // changePeerState(PEPeer.TRANSFERING); // connection_state = PEPeerTransport.CONNECTION_FULLY_ESTABLISHED; // sendBitField(); // handshake.destroy(); // addAvailability(); // sendMainlineDHTPort(); // } // // // protected void decodeBitfield( BTBitfield bitfield ) // { // received_bitfield = true; // // final DirectByteBuffer field =bitfield.getBitfield(); // // final byte[] dataf =new byte[(nbPieces +7) /8]; // // if( field.remaining( DirectByteBuffer.SS_PEER ) < dataf.length ) { // final String error = toString() + " has sent invalid Bitfield: too short [" +field.remaining( DirectByteBuffer.SS_PEER )+ "<" +dataf.length+ "]"; // Debug.out( error ); // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, LogEvent.LT_ERROR, error )); // bitfield.destroy(); // return; // } // // field.get( DirectByteBuffer.SS_PEER, dataf ); // // try{ // closing_mon.enter(); // if (closing) // bitfield.destroy(); // else // { // final BitFlags tempHavePieces; // if (peerHavePieces ==null) // { // tempHavePieces =new BitFlags(nbPieces); // } else // { // tempHavePieces =peerHavePieces; // removeAvailability(); // } // for (int i =0; i <nbPieces; i++) // { // final int index =i /8; // final int bit =7 -(i %8); // final byte bData =dataf[index]; // final byte b =(byte) (bData >>bit); // if ((b &0x01) ==1) // { // tempHavePieces.set(i); // manager.updateSuperSeedPiece(this,i); // } // } // // bitfield.destroy(); // // peerHavePieces =tempHavePieces; // addAvailability(); // // checkSeed(); // checkInterested(); // } // } // finally{ // closing_mon.exit(); // } // } // // protected void decodeMainlineDHTPort(BTDHTPort port) { // int i_port = port.getDHTPort(); // port.destroy(); // // if (!this.ml_dht_enabled) {return;} // MainlineDHTProvider provider = getDHTProvider(); // if (provider == null) {return;} // // try {provider.notifyOfIncomingPort(getIp(), i_port);} // catch (Throwable t) {Debug.printStackTrace(t);} // } // // protected void decodeChoke( BTChoke choke ) { // choke.destroy(); // if (!choked_by_other_peer) // { // choked_by_other_peer = true; // cancelRequests(); // final long unchoked =SystemTime.getCurrentTime() -unchokedTime; // if (unchoked >0 &&!isSnubbed()) // unchokedTimeTotal +=unchoked; // } // } // // // protected void decodeUnchoke( BTUnchoke unchoke ) { // unchoke.destroy(); // if (choked_by_other_peer) // { // choked_by_other_peer = false; // if (!isSnubbed()) // unchokedTime =SystemTime.getCurrentTime(); // } // } // // // protected void // decodeInterested( // BTInterested interested ) // { // interested.destroy(); // // // Don't allow known seeds to be interested in us // // other_peer_interested_in_me = !(isSeed() || isRelativeSeed()); // // if ( other_peer_interested_in_me && // fast_unchoke_new_peers && // isChokedByMe() && // getData( "fast_unchoke_done" ) == null ){ // // setData( "fast_unchoke_done", "" ); // // sendUnChoke(); // } // } // // // protected void decodeUninterested( BTUninterested uninterested ) { // uninterested.destroy(); // other_peer_interested_in_me = false; // // //force send any pending haves in case one of them would make the other peer interested again // if( outgoing_have_message_aggregator != null ) { // outgoing_have_message_aggregator.forceSendOfPending(); // } // // } // // // // // protected void decodeHave( BTHave have ) { // final int pieceNumber =have.getPieceNumber(); // have.destroy(); // // if ((pieceNumber >=nbPieces) ||(pieceNumber <0)) { // closeConnectionInternally("invalid pieceNumber: " +pieceNumber); // return; // } // // if (closing) // return; // // if (peerHavePieces ==null) // peerHavePieces =new BitFlags(nbPieces); // // if (!peerHavePieces.flags[pieceNumber]) // { // if (!interested_in_other_peer &&diskManager.isInteresting(pieceNumber)) // { // connection.getOutgoingMessageQueue().addMessage(new BTInterested(other_peer_interested_version), false); // interested_in_other_peer =true; // } // peerHavePieces.set(pieceNumber); // // final int pieceLength =manager.getPieceLength(pieceNumber); // manager.havePiece(pieceNumber, pieceLength, this); // // checkSeed(); // maybe a seed using lazy bitfield, or suddenly became a seed; // other_peer_interested_in_me &= !(isSeed() || isRelativeSeed()); // never consider seeds interested // // peer_stats.hasNewPiece(pieceLength); // } // } // // protected void // decodeAZHave( // AZHave have ) // { // final int[] pieceNumbers = have.getPieceNumbers(); // // have.destroy(); // // if ( closing ){ // // return; // } // // if ( peerHavePieces == null ){ // // peerHavePieces = new BitFlags( nbPieces ); // } // // boolean send_interested = false; // boolean new_have = false; // // for (int i=0;i<pieceNumbers.length;i++){ // // int pieceNumber = pieceNumbers[i]; // // if ((pieceNumber >= nbPieces) ||(pieceNumber <0)) { // // closeConnectionInternally("invalid pieceNumber: " +pieceNumber); // // return; // } // // if ( !peerHavePieces.flags[pieceNumber]){ // // new_have = true; // // if ( !( send_interested || interested_in_other_peer ) && // diskManager.isInteresting(pieceNumber)){ // // send_interested = true; // } // // peerHavePieces.set(pieceNumber); // // final int pieceLength =manager.getPieceLength(pieceNumber); // // manager.havePiece(pieceNumber, pieceLength, this); // // peer_stats.hasNewPiece(pieceLength); // } // } // // if ( new_have ){ // // checkSeed(); // maybe a seed using lazy bitfield, or suddenly became a seed; // // other_peer_interested_in_me &= !(isSeed() && isRelativeSeed()); // never consider seeds interested // } // // if ( send_interested ){ // // connection.getOutgoingMessageQueue().addMessage(new BTInterested(other_peer_interested_version), false); // // interested_in_other_peer = true; // } // } // // protected long // getBytesDownloaded() // { // if (peerHavePieces ==null ||peerHavePieces.flags.length ==0) // return 0; // // final long total_done; // // if ( peerHavePieces.flags[nbPieces-1] ){ // // total_done = ((long)(peerHavePieces.nbSet -1) *diskManager.getPieceLength()) +diskManager.getPieceLength( nbPieces -1 ); // // }else{ // // total_done =(long)peerHavePieces.nbSet *diskManager.getPieceLength(); // } // // return( Math.min( total_done, diskManager.getTotalLength())); // } // // public long // getBytesRemaining() // { // return( diskManager.getTotalLength() - getBytesDownloaded()); // } // // public void // sendBadPiece( // int piece_number ) // { // if ( bad_piece_supported ){ // // AZBadPiece bp = new AZBadPiece( piece_number, other_peer_az_bad_piece_version ); // // connection.getOutgoingMessageQueue().addMessage( bp, false ); // } // } // protected void // decodeAZBadPiece( // AZBadPiece bad_piece ) // { // final int piece_number = bad_piece.getPieceNumber(); // // bad_piece.destroy(); // // manager.badPieceReported( this, piece_number ); // } // // // protected void decodeRequest( BTRequest request ) { // final int number = request.getPieceNumber(); // final int offset = request.getPieceOffset(); // final int length = request.getLength(); // request.destroy(); // // if( !manager.validateReadRequest( this, number, offset, length ) ) { // closeConnectionInternally( "request for piece #" + number + ":" + offset + "->" + (offset + length -1) + " is an invalid request" ); // return; // } // // if ( manager.getHiddenPiece() == number ){ // closeConnectionInternally( "request for piece #" + number + " is invalid as piece is hidden" ); // return; // } // // if( !choking_other_peer ) { // outgoing_piece_message_handler.addPieceRequest( number, offset, length ); // allowReconnect = true; // } // else { // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, "decodeRequest(): peer request for piece #" // + number + ":" + offset + "->" + (offset + length -1) // + " ignored as peer is currently choked.")); // } // } // // // // protected void decodePiece( BTPiece piece ) { // final int pieceNumber = piece.getPieceNumber(); // final int offset = piece.getPieceOffset(); // final DirectByteBuffer payload = piece.getPieceData(); // final int length = payload.remaining( DirectByteBuffer.SS_PEER ); // // /* // if ( AEDiagnostics.CHECK_DUMMY_FILE_DATA ){ // int pos = payload.position( DirectByteBuffer.SS_PEER ); // long off = ((long)number) * getControl().getPieceLength(0) + offset; // for (int i=0;i<length;i++){ // byte v = payload.get( DirectByteBuffer.SS_PEER ); // if ((byte)off != v ){ // System.out.println( "piece: read is bad at " + off + ": expected = " + (byte)off + ", actual = " + v ); // break; // } // off++; // } // payload.position( DirectByteBuffer.SS_PEER, pos ); // } // */ // // final Object error_msg = // new Object() // { // public final String // toString() // { // return( "decodePiece(): Peer has sent piece #" + pieceNumber + ":" + offset + "->" + (offset + length -1) + ", " ); // } // }; // // if( !manager.validatePieceReply( this, pieceNumber, offset, payload ) ) { // peer_stats.bytesDiscarded( length ); // manager.discarded( this, length ); // requests_discarded++; // printRequestStats(); // piece.destroy(); // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, LogEvent.LT_ERROR, // error_msg // +"but piece block discarded as invalid.")); // return; // } // // final DiskManagerReadRequest request = manager.createDiskManagerRequest( pieceNumber, offset, length ); // boolean piece_error = true; // // if( hasBeenRequested( request ) ) { //from active request // removeRequest( request ); // final long now =SystemTime.getCurrentTime(); // resetRequestsTime(now); // // if( manager.isWritten( pieceNumber, offset ) ) { //oops, looks like this block has already been written // peer_stats.bytesDiscarded( length ); // manager.discarded( this, length ); // // if( manager.isInEndGameMode() ) { //we're probably in end-game mode then // if (last_good_data_time !=-1 &&now -last_good_data_time <=60 *1000) // setSnubbed(false); // last_good_data_time =now; // requests_discarded_endgame++; // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LogIDs.PIECES, LogEvent.LT_INFORMATION, // error_msg // +"but piece block ignored as already written in end-game mode.")); // } // else { // // if they're not snubbed, then most likely this peer got a re-request after some other peer // // snubbed themselves, and the slow peer finially finished the piece, but before this peer did // // so give credit to this peer anyway for having delivered a block at this time // if (!isSnubbed()) // last_good_data_time =now; // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LogIDs.PIECES, LogEvent.LT_WARNING, // error_msg // +"but piece block discarded as already written.")); // requests_discarded++; // } // // printRequestStats(); // } // else { //successfully received block! // manager.writeBlock( pieceNumber, offset, payload, this, false); // if (last_good_data_time !=-1 &&now -last_good_data_time <=60 *1000) // setSnubbed( false ); // last_good_data_time =now; // requests_completed++; // piece_error = false; //dont destroy message, as we've passed the payload on to the disk manager for writing // } // } // else { //initial request may have already expired, but check if we can use the data anyway // if( !manager.isWritten( pieceNumber, offset ) ) { // final boolean ever_requested; // // try{ recent_outgoing_requests_mon.enter(); // ever_requested = recent_outgoing_requests.containsKey( request ); // } // finally{ recent_outgoing_requests_mon.exit(); } // // if( ever_requested ) { //security-measure: we dont want to be accepting any ol' random block // manager.writeBlock( pieceNumber, offset, payload, this, true); // final long now =SystemTime.getCurrentTime(); // if (last_good_data_time !=-1 &&now -last_good_data_time <=60 *1000) // setSnubbed(false); // resetRequestsTime(now); // last_good_data_time =now; // requests_recovered++; // printRequestStats(); // piece_error = false; //dont destroy message, as we've passed the payload on to the disk manager for writing // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LogIDs.PIECES, LogEvent.LT_INFORMATION, // error_msg // +"expired piece block data recovered as useful.")); // } // else { // // System.out.println( "[" +client+ "]" +error_msg + "but expired piece block discarded as never requested." ); // // peer_stats.bytesDiscarded( length ); // manager.discarded( this, length ); // requests_discarded++; // printRequestStats(); // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LogIDs.PIECES, LogEvent.LT_ERROR, // error_msg // +"but expired piece block discarded as never requested.")); // } // } // else { // peer_stats.bytesDiscarded( length ); // manager.discarded( this, length ); // requests_discarded++; // printRequestStats(); // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LogIDs.PIECES, LogEvent.LT_WARNING, // error_msg // +"but expired piece block discarded as already written.")); // } // } // // if( piece_error ) // piece.destroy(); // else // allowReconnect = true; // } // // // // protected void decodeCancel( BTCancel cancel ) { // int number = cancel.getPieceNumber(); // int offset = cancel.getPieceOffset(); // int length = cancel.getLength(); // cancel.destroy(); // if(outgoing_piece_message_handler != null) // outgoing_piece_message_handler.removePieceRequest( number, offset, length ); // } // // // // private void registerForMessageHandling() { // // //INCOMING MESSAGES // connection.getIncomingMessageQueue().registerQueueListener( new IncomingMessageQueue.MessageQueueListener() { // public final boolean messageReceived( Message message ) { // // if (Logger.isEnabled()) // Logger.log(new LogEvent(PEPeerTransportProtocol.this, LogIDs.NET, // "Received [" + message.getDescription() + "] message")); // final long now =SystemTime.getCurrentTime(); // last_message_received_time =now; // if( message.getType() == Message.TYPE_DATA_PAYLOAD ) { // last_data_message_received_time =now; // } // // String message_id = message.getID(); // // if( message_id.equals( BTMessage.ID_BT_PIECE ) ) { // decodePiece( (BTPiece)message ); // return true; // } // // if( closing ) { // message.destroy(); // return true; // } // // if(message_id.equals( BTMessage.ID_BT_KEEP_ALIVE ) ) { // message.destroy(); // // //make sure they're not spamming us // if( !message_limiter.countIncomingMessage( message.getID(), 6, 60*1000 ) ) { //allow max 6 keep-alives per 60sec // System.out.println( manager.getDisplayName() + ": Incoming keep-alive message flood detected, dropping spamming peer connection." +PEPeerTransportProtocol.this ); // closeConnectionInternally( "Incoming keep-alive message flood detected, dropping spamming peer connection." ); // } // // return true; // } // // // if( message_id.equals( BTMessage.ID_BT_HANDSHAKE ) ) { // decodeBTHandshake( (BTHandshake)message ); // return true; // } // // if( message_id.equals( AZMessage.ID_AZ_HANDSHAKE ) ) { // decodeAZHandshake( (AZHandshake)message ); // return true; // } // // if (message_id.equals(LTMessage.ID_LT_HANDSHAKE)) { // decodeLTHandshake((LTHandshake)message); // return true; // } // // if( message_id.equals( BTMessage.ID_BT_BITFIELD ) ) { // decodeBitfield( (BTBitfield)message ); // return true; // } // // if( message_id.equals( BTMessage.ID_BT_CHOKE ) ) { // decodeChoke( (BTChoke)message ); // if( choking_other_peer ) { // connection.enableEnhancedMessageProcessing( false, manager.getPartitionID()); //downgrade back to normal handler // } // return true; // } // // if( message_id.equals( BTMessage.ID_BT_UNCHOKE ) ) { // decodeUnchoke( (BTUnchoke)message ); // connection.enableEnhancedMessageProcessing( true, manager.getPartitionID() ); //make sure we use a fast handler for the resulting download // return true; // } // // if( message_id.equals( BTMessage.ID_BT_INTERESTED ) ) { // decodeInterested( (BTInterested)message ); // return true; // } // // if( message_id.equals( BTMessage.ID_BT_UNINTERESTED ) ) { // decodeUninterested( (BTUninterested)message ); // return true; // } // // if( message_id.equals( BTMessage.ID_BT_HAVE ) ) { // decodeHave( (BTHave)message ); // return true; // } // // if( message_id.equals( BTMessage.ID_BT_REQUEST ) ) { // decodeRequest( (BTRequest)message ); // return true; // } // // if( message_id.equals( BTMessage.ID_BT_CANCEL ) ) { // decodeCancel( (BTCancel)message ); // return true; // } // // if (message_id.equals(BTMessage.ID_BT_DHT_PORT)) { // decodeMainlineDHTPort((BTDHTPort)message); // return true; // } // // if( message_id.equals( AZMessage.ID_AZ_PEER_EXCHANGE ) ) { // decodePeerExchange( (AZPeerExchange)message ); // return true; // } // // if (message_id.equals(LTMessage.ID_UT_PEX)) { // decodePeerExchange((UTPeerExchange)message); // return true; // } // // if( message_id.equals( AZMessage.ID_AZ_REQUEST_HINT ) ) { // decodeAZRequestHint( (AZRequestHint)message ); // return true; // } // // if( message_id.equals( AZMessage.ID_AZ_HAVE ) ) { // decodeAZHave((AZHave)message ); // return true; // } // // if( message_id.equals( AZMessage.ID_AZ_BAD_PIECE ) ) { // decodeAZBadPiece((AZBadPiece)message ); // return true; // } // return false; // } // // public final void protocolBytesReceived( int byte_count ) { // //update stats // peer_stats.protocolBytesReceived( byte_count ); // manager.protocolBytesReceived( PEPeerTransportProtocol.this, byte_count ); // } // // public final void dataBytesReceived( int byte_count ) { // // Observe that the peer is sending data so that if theyre so slow that the whole // // data block times out, we don't think theyre not sending anything at all // last_data_message_received_time =SystemTime.getCurrentTime(); // // //update stats // peer_stats.dataBytesReceived( byte_count ); // // manager.dataBytesReceived( PEPeerTransportProtocol.this, byte_count ); // } // }); // // // //OUTGOING MESSAGES // connection.getOutgoingMessageQueue().registerQueueListener( new OutgoingMessageQueue.MessageQueueListener() { // public final boolean messageAdded( Message message ) { return true; } // // public final void messageQueued( Message message ) { /* ignore */ } // // public final void messageRemoved( Message message ) { /*ignore*/ } // // public final void messageSent( Message message ) { // //update keep-alive info // final long now =SystemTime.getCurrentTime(); // last_message_sent_time =now; // // if( message.getType() == Message.TYPE_DATA_PAYLOAD ) { // last_data_message_sent_time =now; // } // // if( message.getID().equals( BTMessage.ID_BT_UNCHOKE ) ) { // is about to send piece data // connection.enableEnhancedMessageProcessing( true, manager.getPartitionID() ); //so make sure we use a fast handler // } // else if( message.getID().equals( BTMessage.ID_BT_CHOKE ) ) { // is done sending piece data // if( choked_by_other_peer ) { // connection.enableEnhancedMessageProcessing( false, manager.getPartitionID() ); //so downgrade back to normal handler // } // } // // if (Logger.isEnabled()) // Logger.log(new LogEvent(PEPeerTransportProtocol.this, LogIDs.NET, // "Sent [" + message.getDescription() + "] message")); // } // // public final void protocolBytesSent( int byte_count ) { // //update stats // peer_stats.protocolBytesSent( byte_count ); // manager.protocolBytesSent( PEPeerTransportProtocol.this, byte_count ); // } // // public final void dataBytesSent( int byte_count ) { // //update stats // peer_stats.dataBytesSent( byte_count ); // manager.dataBytesSent( PEPeerTransportProtocol.this, byte_count ); // } // public void flush(){} // }); // // //start message processing // // connection.addRateLimiter( manager.getUploadLimitedRateGroup(), true ); // connection.addRateLimiter( manager.getDownloadLimitedRateGroup(), false ); // // connection.startMessageProcessing(); // } // // public void // addRateLimiter( // LimitedRateGroup limiter, // boolean upload ) // { // connection.addRateLimiter( limiter, upload ); // } // // public void // removeRateLimiter( // LimitedRateGroup limiter, // boolean upload ) // { // connection.removeRateLimiter( limiter, upload ); // } // // public Connection getPluginConnection() { // return plugin_connection; // } // // // public Message[] getSupportedMessages() { // return supported_messages; // } // // // public boolean supportsMessaging() { // return supported_messages != null; // } // // public int getMessagingMode() // { // return messaging_mode; // } // // public byte[] getHandshakeReservedBytes() { // return this.handshake_reserved_bytes; // } // // public void // setHaveAggregationEnabled( // boolean enabled ) // { // have_aggregation_disabled = !enabled; // } // // public boolean // hasReceivedBitField() // { // return( received_bitfield ); // } // // public String // getEncryption() // { // Transport transport = connection.getTransport(); // // if ( transport == null ){ // // return( "" ); // } // // return( transport.getEncryption( false )); // } // // public void // addListener( // PEPeerListener listener ) // { // try{ // peer_listeners_mon.enter(); // // if( peer_listeners_cow == null ){ // // peer_listeners_cow = new ArrayList(); // } // // final List new_listeners = new ArrayList( peer_listeners_cow ); // // new_listeners.add( listener ); // // peer_listeners_cow = new_listeners; // // }finally{ // // peer_listeners_mon.exit(); // } // } // // public void // removeListener( // PEPeerListener listener ) // { // try{ // peer_listeners_mon.enter(); // // if ( peer_listeners_cow != null ){ // // List new_listeners = new ArrayList( peer_listeners_cow ); // // new_listeners.remove( listener ); // // if ( new_listeners.isEmpty()){ // // new_listeners = null; // } // // peer_listeners_cow = new_listeners; // } // }finally{ // // peer_listeners_mon.exit(); // } // } // // // private void changePeerState( int new_state ) { // current_peer_state = new_state; // // if( current_peer_state == PEPeer.TRANSFERING ) { //YUCK! // doPostHandshakeProcessing(); // } // // final List peer_listeners_ref = peer_listeners_cow; // // if ( peer_listeners_ref != null ){ // // for( int i=0; i < peer_listeners_ref.size(); i++ ) { // // final PEPeerListener l = (PEPeerListener)peer_listeners_ref.get( i ); // // l.stateChanged(this, current_peer_state); // } // } // } // // // // // /** // * this method might be called repeatedly since LTEP allows headers to be sent more than once // * make sure that multiple invokations do not have unintended consequences // */ // private void doPostHandshakeProcessing() { // //peer exchange registration // if( manager.isPeerExchangeEnabled()) { // //try and register all connections for their peer exchange info // if(peer_exchange_item == null && canBePeerExchanged()){ // peer_exchange_item = manager.createPeerExchangeConnection( this ); // } // // if( peer_exchange_item != null ) { // //check for peer exchange support // if(ut_pex_enabled || peerSupportsMessageType(AZMessage.ID_AZ_PEER_EXCHANGE)) { // peer_exchange_supported = true; // } // else { //no need to maintain internal states as we wont be sending/receiving peer exchange messages // peer_exchange_item.disableStateMaintenance(); // } // } // } // // request_hint_supported = peerSupportsMessageType( AZMessage.ID_AZ_REQUEST_HINT ); // bad_piece_supported = peerSupportsMessageType( AZMessage.ID_AZ_BAD_PIECE ); // } // // private boolean // canBePeerExchanged() // { // if ( client_peer_id != null ){ // // // disable the exchange of location targetted peers // // boolean ok = !client_peer_id.startsWith( PeerClassifier.CACHE_LOGIC ); // // // System.out.println( "canPEX: " + client_peer_id + " -> " + ok ); // // return( ok ); // // }else{ // // Debug.out( "No client peer id!" ); // // return( false ); // } // } // // private boolean peerSupportsMessageType( String message_id ) { // if( supported_messages != null ) { // for( int i=0; i < supported_messages.length; i++ ) { // if( supported_messages[i].getID().equals( message_id ) ) return true; // } // } // return false; // } // // // // public void updatePeerExchange() { // if ( current_peer_state != TRANSFERING ) return; // if( !peer_exchange_supported ) return; // // if( peer_exchange_item != null && manager.isPeerExchangeEnabled()) { // final PeerItem[] adds = peer_exchange_item.getNewlyAddedPeerConnections(); // final PeerItem[] drops = peer_exchange_item.getNewlyDroppedPeerConnections(); // // if( (adds != null && adds.length > 0) || (drops != null && drops.length > 0) ) { // if (ut_pex_enabled) { // connection.getOutgoingMessageQueue().addMessage( new UTPeerExchange(adds, drops, null, (byte)0), false); // } // else { // connection.getOutgoingMessageQueue().addMessage( new AZPeerExchange( manager.getHash(), adds, drops, other_peer_pex_version ), false ); // } // } // } // } // // // // protected void decodePeerExchange( AZStylePeerExchange exchange ) { // // // if we're seeding ignore µT-PEXed seeds, Az won't send them in the first place // final PeerItem[] added = exchange instanceof UTPeerExchange ? ((UTPeerExchange)exchange).getAddedPeers(!manager.isSeeding()) : exchange.getAddedPeers(); // final PeerItem[] dropped = exchange.getDroppedPeers(); // // //make sure they're not spamming us // if( !message_limiter.countIncomingMessage( exchange.getID(), 7, 120*1000 ) ) { //allow max 7 PEX per 2min //TODO reduce max after 2308 release? // System.out.println( manager.getDisplayName() + ": Incoming PEX message flood detected, dropping spamming peer connection." +PEPeerTransportProtocol.this ); // closeConnectionInternally( "Incoming PEX message flood detected, dropping spamming peer connection." ); // return; // } // // exchange.destroy(); // // if( ( added != null && added.length > exchange.getMaxAllowedPeersPerVolley(!this.has_received_initial_pex, true)) || // ( dropped != null && dropped.length > exchange.getMaxAllowedPeersPerVolley(!this.has_received_initial_pex, false))) { // // //drop these too-large messages as they seem to be used for DOS by swarm poisoners // closeConnectionInternally( "Invalid PEX message received: too large, dropping likely poisoner peer connection." ); // return; // } // // this.has_received_initial_pex = true; // // if( peer_exchange_supported && peer_exchange_item != null && manager.isPeerExchangeEnabled()){ // if( added != null ) { // for( int i=0; i < added.length; i++ ) { // PeerItem pi = added[i]; // manager.peerDiscovered( this, pi ); // peer_exchange_item.addConnectedPeer( pi ); // } // } // // if( dropped != null ) { // for( int i=0; i < dropped.length; i++ ) { // peer_exchange_item.dropConnectedPeer( dropped[i] ); // } // } // } // else { // if (Logger.isEnabled()) // Logger.log(new LogEvent(this, LOGID, // "Peer Exchange disabled for this download, " // + "dropping received exchange message")); // } // } // // public boolean // sendRequestHint( // int piece_number, // int offset, // int length, // int life ) // { // if ( request_hint_supported ){ // // AZRequestHint rh = new AZRequestHint( piece_number, offset, length, life, other_peer_az_request_hint_version ); // // connection.getOutgoingMessageQueue().addMessage( rh, false ); // // return( true ); // // }else{ // // return( false ); // } // } // // protected void // decodeAZRequestHint( // AZRequestHint hint ) // { // int piece_number = hint.getPieceNumber(); // int offset = hint.getOffset(); // int length = hint.getLength(); // int life = hint.getLife(); // // hint.destroy(); // // if ( life > REQUEST_HINT_MAX_LIFE ){ // // life = REQUEST_HINT_MAX_LIFE; // } // // if ( manager.validateHintRequest( this, piece_number, offset, length )){ // // if ( request_hint == null ){ // // // we ignore life time currently as once hinted we don't accept another hint // // until that one is satisfied. This is to prevent too many pieces starting // // request_hint = new int[]{ piece_number, offset, length }; // } // } // } // // public int[] // getRequestHint() // { // return( request_hint ); // } // // public void // clearRequestHint() // { // request_hint = null; // } // // public PeerItem getPeerItemIdentity() { return peer_item_identity; } // // public int getReservedPieceNumber() { // return reservedPiece; // } // // public void setReservedPieceNumber(int pieceNumber) { // reservedPiece = pieceNumber; // } // // public int // getIncomingRequestCount() // { // if ( outgoing_piece_message_handler == null ){ // return( 0 ); // } // // return outgoing_piece_message_handler.getRequestCount(); // } // // public int // getOutgoingRequestCount() // { // return( getNbRequests()); // } // // public int // getOutboundDataQueueSize() // { // return( connection.getOutgoingMessageQueue().getTotalSize()); // } // // public boolean // isStalledPendingLoad() // { // if ( outgoing_piece_message_handler == null ){ // // return( false ); // } // // return outgoing_piece_message_handler.isStalledPendingLoad(); // } // // public int[] getIncomingRequestedPieceNumbers() { // if ( outgoing_piece_message_handler == null ){ // return( new int[0]); // } // return outgoing_piece_message_handler.getRequestedPieceNumbers(); // } // // public int[] getOutgoingRequestedPieceNumbers() { // try{ // requested_mon.enter(); // // /** Cheap hack to reduce (but not remove all) the # of duplicate entries */ // int iLastNumber = -1; // // // allocate max size needed (we'll shrink it later) // final int[] pieceNumbers = new int[requested.size()]; // int pos = 0; // // for (int i = 0; i < requested.size(); i++) { // DiskManagerReadRequest request = null; // try { // request = (DiskManagerReadRequest) requested.get(i); // } catch (Exception e) { // Debug.printStackTrace(e); // } // // if (request != null && iLastNumber != request.getPieceNumber()) { // iLastNumber = request.getPieceNumber(); // pieceNumbers[pos++] = iLastNumber; // } // } // // final int[] trimmed = new int[pos]; // System.arraycopy(pieceNumbers, 0, trimmed, 0, pos); // // return trimmed; // // }finally{ // requested_mon.exit(); // } // } // // public int // getPercentDoneOfCurrentIncomingRequest() // { // return( connection.getIncomingMessageQueue().getPercentDoneOfCurrentMessage()); // } // // public int // getPercentDoneOfCurrentOutgoingRequest() // { // return( connection.getOutgoingMessageQueue().getPercentDoneOfCurrentMessage()); // } // // /* (non-Javadoc) // * @see org.gudy.azureus2.core3.logging.LogRelation#getLogRelationText() // */ // public String getRelationText() { // String text = ""; // if (manager instanceof LogRelation) // text = ((LogRelation)manager).getRelationText() + "; "; // text += "Peer: " + toString(); // return text; // } // // // /* (non-Javadoc) // * @see org.gudy.azureus2.core3.logging.LogRelation#queryForClass(java.lang.Class) // */ // public Object[] getQueryableInterfaces() { // return new Object[] { manager }; // } // // public int getLastPiece() // { // return _lastPiece; // } // // public void setLastPiece(int pieceNumber) // { // _lastPiece =pieceNumber; // } // // // // public boolean isLANLocal() { // if( connection == null ) return( AddressUtils.isLANLocalAddress( ip ) == AddressUtils.LAN_LOCAL_YES ); // return connection.isLANLocal(); // } // // public boolean // isTCP() // { // return( connection.getEndpoint().getProtocols()[0].getType() == ProtocolEndpoint.PROTOCOL_TCP ); // } // // public long getUnchokedTimeTotal() // { // if (choked_by_other_peer) // return unchokedTimeTotal; // return unchokedTimeTotal +(SystemTime.getCurrentTime() -unchokedTime); // } // // public void setUploadRateLimitBytesPerSecond( int bytes ){ connection.setUploadLimit( bytes ); } // public void setDownloadRateLimitBytesPerSecond( int bytes ){ connection.setDownloadLimit( bytes ); } // public int getUploadRateLimitBytesPerSecond(){ return connection.getUploadLimit(); } // public int getDownloadRateLimitBytesPerSecond(){ return connection.getDownloadLimit(); } // // // public String getClientNameFromPeerID() {return this.client_peer_id;} // public String getClientNameFromExtensionHandshake() { // if (!this.client_handshake.equals("") && !this.client_handshake_version.equals("")) { // return this.client_handshake + " " + this.client_handshake_version; // } // return this.client_handshake; // } // // private static MainlineDHTProvider getDHTProvider() { // return AzureusCoreImpl.getSingleton().getGlobalManager().getMainlineDHTProvider(); // } // // public void // setPriorityConnection( // boolean is_priority ) // { // synchronized( this ){ // // if ( priority_connection == is_priority ){ // // return; // } // // priority_connection = is_priority; // } // // manager.getAdapter().priorityConnectionChanged( is_priority ); // } // // public boolean // isPriorityConnection() // { // synchronized( this ){ // // return( priority_connection ); // } // } // // public void // generateEvidence( // IndentWriter writer ) // { // writer.println( // "ip=" + getIp() + ",in=" + isIncoming() + ",port=" + getPort() + ",cli=" + client + ",tcp=" + getTCPListenPort() + ",udp=" + getUDPListenPort() + // ",oudp=" + getUDPNonDataListenPort() + ",p_state=" + getPeerState() + ",c_state=" + getConnectionState() + ",seed=" + isSeed() + "partialSeed=" + isRelativeSeed() + ",pex=" + peer_exchange_supported + ",closing=" + closing ); // writer.println( " choked=" + choked_by_other_peer + ",choking=" + choking_other_peer + ",unchoke_time=" + unchokedTime + ", unchoke_total=" + unchokedTimeTotal + ",is_opt=" + is_optimistic_unchoke ); // writer.println( " interested=" + interested_in_other_peer + ",interesting=" + other_peer_interested_in_me + ",snubbed=" + snubbed ); // writer.println( " lp=" + _lastPiece + ",up=" + uniquePiece + ",rp=" + reservedPiece ); // writer.println( // " last_sent=" + last_message_sent_time + "/" + last_data_message_sent_time + // ",last_recv=" + last_message_received_time + "/" + last_data_message_received_time + "/" + last_good_data_time ); // writer.println( " conn_at=" + connection_established_time + ",cons_no_reqs=" + consecutive_no_request_count + // ",discard=" + requests_discarded + "/" + requests_discarded_endgame + ",recov=" + requests_recovered + ",comp=" + requests_completed ); // // } // // protected static class // MutableInteger // { // private int value; // // protected // MutableInteger( // int v ) // { // value = v; // } // // protected void // setValue( // int v ) // { // value = v; // } // // protected int // getValue() // { // return( value ); // } // // public int // hashCode() // { // return value; // } // // public boolean // equals( // Object obj ) // { // if (obj instanceof MutableInteger) { // return value == ((MutableInteger)obj).value; // } // return false; // } // } //}