ws.moor.bt.network.packets.HandshakePacket.java Source code

Java tutorial

Introduction

Here is the source code for ws.moor.bt.network.packets.HandshakePacket.java

Source

/*
 * BitThief - A Free Riding BitTorrent Client
 * Copyright (C) 2006 Patrick Moor <patrick@moor.ws>
 *
 * 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, or (at your option) any later version.
 *
 * 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.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
 * USA.
 */

package ws.moor.bt.network.packets;

import org.apache.commons.codec.binary.Hex;
import org.apache.log4j.Logger;
import ws.moor.bt.torrent.Hash;
import ws.moor.bt.torrent.PeerId;
import ws.moor.bt.util.LoggingUtil;

import java.util.Arrays;

/**
 * TODO(pmoor): Javadoc
 */
public class HandshakePacket implements Packet {

    public static final String BITTORRENT_PROTOCOL = "BitTorrent protocol";

    private static final int RESERVED_LENGTH = 8;

    private final String protocol;
    private final byte[] reserved;
    private final Hash infoHash;
    private final PeerId peerId;

    private static final Logger logger = LoggingUtil.getLogger(HandshakePacket.class);

    public HandshakePacket(Hash infoHash, PeerId peerId) {
        this(BITTORRENT_PROTOCOL, new byte[RESERVED_LENGTH], infoHash, peerId);
    }

    private HandshakePacket(String protocol, byte[] reserved, Hash infoHash, PeerId peerId) {
        this.reserved = reserved;
        this.protocol = protocol;
        this.infoHash = infoHash;
        this.peerId = peerId;
    }

    public int writeIntoBuffer(byte[] buffer, int offset) {
        if (buffer.length < offset + getPayloadLength()) {
            throw new IllegalArgumentException("buffer is too small, should be at least " + getPayloadLength());
        }
        byte[] protocolBytes = protocol.getBytes();
        buffer[offset] = (byte) protocolBytes.length;
        System.arraycopy(protocolBytes, 0, buffer, offset + 1, protocolBytes.length);

        System.arraycopy(reserved, 0, buffer, offset + 1 + protocolBytes.length, RESERVED_LENGTH);

        byte[] hash = infoHash.getBytes();
        System.arraycopy(hash, 0, buffer, offset + 1 + protocolBytes.length + RESERVED_LENGTH, hash.length);

        if (hasPeerId()) {
            byte[] id = peerId.getBytes();
            System.arraycopy(id, 0, buffer, offset + 1 + protocolBytes.length + RESERVED_LENGTH + hash.length,
                    id.length);
        }

        return offset + getPayloadLength();
    }

    public int getPayloadLength() {
        return 1 + protocol.getBytes().length + RESERVED_LENGTH + Hash.LENGTH + (hasPeerId() ? PeerId.LENGTH : 0);
    }

    public int getId() {
        throw new UnsupportedOperationException("this packet type does not have an ID");
    }

    public void handle(PacketHandler handler) {
        handler.handleHandshakePacket(this);
    }

    public String getProtocol() {
        return protocol;
    }

    public Hash getInfoHash() {
        return infoHash;
    }

    public PeerId getPeerId() {
        return peerId;
    }

    public boolean hasPeerId() {
        return peerId != null;
    }

    public boolean equals(Object other) {
        if (other == null || getClass() != other.getClass()) {
            return false;
        }
        final HandshakePacket that = (HandshakePacket) other;
        if (!infoHash.equals(that.infoHash)) {
            return false;
        }
        if (hasPeerId() ? !peerId.equals(that.peerId) : that.peerId != null) {
            return false;
        }
        if (!protocol.equals(that.protocol)) {
            return false;
        }
        return Arrays.equals(reserved, that.reserved);
    }

    public int hashCode() {
        int result;
        result = protocol.hashCode();
        result = 29 * result + Arrays.hashCode(reserved);
        result = 29 * result + infoHash.hashCode();
        result = 29 * result + (peerId != null ? peerId.hashCode() : 0);
        return result;
    }

    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("InfoHash: ").append(infoHash.toString()).append("\n");
        builder.append("Reserved: ").append(Hex.encodeHex(reserved));
        if (hasPeerId()) {
            builder.append("\n");
            builder.append("PeerId: ").append(peerId);
        }
        return builder.toString();
    }

    public static PacketConstructor<HandshakePacket> getConstructor() {
        return new Constructor();
    }

    private static class Constructor implements PacketConstructor<HandshakePacket> {

        public int getId() {
            throw new UnsupportedOperationException("this packet type does not have an ID");
        }

        public HandshakePacket constructPacket(byte[] buffer, int offset, int length) {
            if (offset + length > buffer.length) {
                return null;
            }

            int protocolLength = buffer[offset];
            int bytesNeeded = 1 + protocolLength + RESERVED_LENGTH + Hash.LENGTH;
            int bytesNeededFull = bytesNeeded + PeerId.LENGTH;
            if (bytesNeeded != length && bytesNeededFull != length) {
                logger.debug("not the right amount of bytes available in handshake constructor");
                return null;
            }
            byte[] protocol = new byte[protocolLength];
            System.arraycopy(buffer, offset + 1, protocol, 0, protocolLength);
            byte[] reserved = new byte[RESERVED_LENGTH];
            System.arraycopy(buffer, offset + 1 + protocolLength, reserved, 0, RESERVED_LENGTH);
            byte[] hash = new byte[Hash.LENGTH];
            System.arraycopy(buffer, offset + 1 + protocolLength + RESERVED_LENGTH, hash, 0, Hash.LENGTH);
            Hash infoHash = new Hash(hash);
            PeerId peerId = null;
            if (length == bytesNeededFull) {
                byte[] id = new byte[PeerId.LENGTH];
                System.arraycopy(buffer, offset + 1 + protocolLength + RESERVED_LENGTH + Hash.LENGTH, id, 0,
                        PeerId.LENGTH);
                peerId = new PeerId(id);
            }
            return new HandshakePacket(new String(protocol), reserved, infoHash, peerId);
        }
    }
}