use of com.biglybt.core.peer.util.PeerIdentityDataID in project BiglyBT by BiglySoftware.
the class PEPeerTransportProtocol method decodeBTHandshake.
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.getTargetHash(), 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, network));
// 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)) {
// make sure we dont do it again
manager.peerVerifiedAsSelf(this);
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;
PEPeerTransport existing = manager.getTransportFromIdentity(peer_id);
if (existing != null) {
String existing_ip = existing.getIp();
if (connection.isLANLocal()) {
if (!existing.isLANLocal() || ((existing_ip.endsWith(".1") || existing_ip.endsWith(".254")) && !existing_ip.equals(ip))) {
// so drop the existing connection if it is an external (non lan-local) one
String msg = "Dropping existing non-lanlocal peer connection [" + existing + "] in favour of [" + this + "]";
Debug.outNoStack(msg);
manager.removePeer(existing, msg);
close = false;
}
} else {
boolean this_ipv6 = ip.contains(":");
boolean existing_ipv6 = existing_ip.contains(":");
if (this_ipv6 != existing_ipv6) {
boolean close_existing;
if (prefer_ipv6) {
close_existing = this_ipv6;
} else {
close_existing = existing_ipv6;
}
if (close_existing) {
String msg = "Dropping existing peer connection [" + existing + "] in favour of [" + this + "]";
manager.removePeer(existing, msg);
close = false;
}
}
}
}
if (close) {
if (Constants.IS_CVS_VERSION) {
try {
List<PEPeer> peers = manager.getPeers();
String dup_str = "?";
boolean dup_ip = false;
for (PEPeer p : peers) {
if (p == this) {
continue;
}
byte[] id = p.getId();
if (Arrays.equals(id, peer_id)) {
dup_ip = p.getIp().equals(getIp());
dup_str = p.getClient() + "/" + p.getClientNameFromExtensionHandshake() + "/" + p.getIp() + "/" + p.getPort();
break;
}
}
String my_str = getClient() + "/" + getIp() + "/" + getPort();
if (!dup_ip) {
Debug.outNoStack("Duplicate peer id detected: id=" + ByteFormatter.encodeString(peer_id) + ": this=" + my_str + ",other=" + dup_str);
}
} catch (Throwable e) {
}
}
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
boolean max_reached = manager.getMaxNewConnectionsAllowed(network) == 0;
if (max_reached && !manager.doOptimisticDisconnect(isLANLocal(), isPriorityConnection(), network)) {
int[] _con_max = manager.getMaxConnections();
int con_max = _con_max[0] + _con_max[1];
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" + con_max + "]";
// 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] & 0x01) == 1;
// disable fast if we have per-torrent upload limit as it is non-trivial to enforce for choked fast-start
// transfers as peer is in the multi-peer upload group (as choked) and in this mode the limit isn't
// enforced
fast_extension_enabled = BTHandshake.FAST_EXTENSION_ENABLED && manager.getUploadRateLimitBytesPerSecond() == 0 && (handshake_reserved_bytes[7] & 0x04) != 0;
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.contains("Azureus") && !client.contains(Constants.BIGLYBT_NAME)) {
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();
int padding_mode;
if (transport.isEncrypted()) {
if (transport.isTCP()) {
padding_mode = AZMessageEncoder.PADDING_MODE_NORMAL;
} else {
padding_mode = AZMessageEncoder.PADDING_MODE_MINIMAL;
}
} else {
padding_mode = AZMessageEncoder.PADDING_MODE_NONE;
}
connection.getIncomingMessageQueue().setDecoder(new AZMessageDecoder());
connection.getOutgoingMessageQueue().setEncoder(new AZMessageEncoder(padding_mode));
// 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();
if (!is_metadata_download) {
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);
}
}
Aggregations