/** * Validate an expected handshake on a connection. * * <p>Reads an expected handshake message from the given connected socket, parses it and validates * that the torrent hash_info corresponds to the torrent we're sharing, and that the peerId * matches the peer ID we expect to see coming from the remote peer. * * @param socket The connected socket to the remote peer. * @param peerId The peer ID we expect in the handshake. If <em>null</em>, any peer ID is accepted * (this is the case for incoming connections). * @return The validated handshake message object. */ private Handshake validateHandshake(Socket socket, byte[] peerId) throws IOException, ParseException { InputStream is = socket.getInputStream(); // Read the handshake from the wire int pstrlen = is.read(); byte[] data = new byte[Handshake.BASE_HANDSHAKE_LENGTH + pstrlen]; data[0] = (byte) pstrlen; is.read(data, 1, data.length - 1); // Parse and check the handshake Handshake hs = Handshake.parse(ByteBuffer.wrap(data)); if (!Arrays.equals(hs.getInfoHash(), this.torrent.getInfoHash())) { throw new ParseException( "Handshake for unknow torrent " + Torrent.byteArrayToHexString(hs.getInfoHash()) + " from " + this.socketRepr(socket) + ".", pstrlen + 9); } if (peerId != null && !Arrays.equals(hs.getPeerId(), peerId)) { throw new ParseException( "Announced peer ID " + Torrent.byteArrayToHexString(hs.getPeerId()) + " did not match expected peer ID " + Torrent.byteArrayToHexString(peerId) + ".", pstrlen + 29); } return hs; }
@Override public void run() { Socket socket = new Socket(); InetSocketAddress address = new InetSocketAddress(this.peer.getIp(), this.peer.getPort()); try { logger.info("Connecting to {}...", this.peer); socket.connect(address, 3 * 1000); this.handler.sendHandshake(socket); Handshake hs = this.handler.validateHandshake( socket, (this.peer.hasPeerId() ? this.peer.getPeerId().array() : null)); logger.info( "Handshaked with {}, peer ID is {}.", this.peer, Torrent.byteArrayToHexString(hs.getPeerId())); this.handler.fireNewPeerConnection(socket, hs.getPeerId()); } catch (IOException ioe) { try { socket.close(); } catch (IOException e) { } this.handler.fireFailedConnection(this.peer, ioe); } catch (ParseException pe) { try { socket.close(); } catch (IOException e) { } this.handler.fireFailedConnection(this.peer, pe); } }