Search in sources :

Example 1 with PeerIdentityDataID

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);
    }
}
Also used : PeerIdentityDataID(com.biglybt.core.peer.util.PeerIdentityDataID) PEPeerTransport(com.biglybt.core.peer.impl.PEPeerTransport) PEPeerTransport(com.biglybt.core.peer.impl.PEPeerTransport)

Aggregations

PEPeerTransport (com.biglybt.core.peer.impl.PEPeerTransport)1 PeerIdentityDataID (com.biglybt.core.peer.util.PeerIdentityDataID)1