/* * BitTorrentHandshakeMessage.java * * Created on Feb 9, 2010, 10:39:41 PM * * Description: Provides a bit torrent handshake message. * * Copyright (C) Feb 9, 2010 reed. * * 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 3 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ package org.texai.torrent.message; import java.io.UnsupportedEncodingException; import net.jcip.annotations.NotThreadSafe; import org.texai.torrent.support.BitTorrentConstants; import org.texai.util.ByteUtils; import org.texai.util.TexaiException; /** Provides a bit torrent handshake message. See http://wiki.theory.org/BitTorrentSpecification. * * @author reed */ @NotThreadSafe public class BitTorrentHandshakeMessage implements BitTorrentMessage { /** the torrent info hash */ private final byte[] infoHash; /** the peer id bytes */ private final byte[] peerIdBytes; /** Constructs a new BitTorrentHandshakeMessage instance. * * @param infoHash the torrent info hash * @param peerIdBytes the peer id bytes */ public BitTorrentHandshakeMessage( final byte[] infoHash, final byte[] peerIdBytes) { //Preconditions assert infoHash != null : "infoHash must not be null"; assert infoHash.length == 20 : "infoHash must be length 20"; assert peerIdBytes != null : "peerIdBytes must not be null"; assert peerIdBytes.length == 20 : "peerIdBytes must be length 20"; this.infoHash = infoHash; this.peerIdBytes = peerIdBytes; } /** Gets the torrent info hash. * * @return the torrent info hash */ public byte[] getInfoHash() { return infoHash; } /** Gets the peer identification bytes. * * @return the peer identification bytes */ @Override public byte[] getPeerIdBytes() { return peerIdBytes; } /** Returns a string representation of this object. * * @return a string representation of this object */ @Override public String toString() { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("[handshake, peer id: "); try { stringBuilder.append(new String(peerIdBytes, "US-ASCII")); } catch (UnsupportedEncodingException ex) { throw new TexaiException(ex); } stringBuilder.append(", info-hash: "); stringBuilder.append(ByteUtils.toHex(infoHash)); stringBuilder.append(']'); return stringBuilder.toString(); } /** Encodes the bit torrent message into a byte array. * * @return the byte array */ @Override public byte[] encode() { final byte[] bytes = new byte[68]; bytes[0] = BitTorrentConstants.BIT_TORRENT_HANDSHAKE_PROTOCOL; bytes[1] = 'B'; bytes[2] = 'i'; bytes[3] = 't'; bytes[4] = 'T'; bytes[5] = 'o'; bytes[6] = 'r'; bytes[7] = 'r'; bytes[8] = 'e'; bytes[9] = 'n'; bytes[10] = 't'; bytes[11] = ' '; bytes[12] = 'p'; bytes[13] = 'r'; bytes[14] = 'o'; bytes[15] = 't'; bytes[16] = 'o'; bytes[17] = 'c'; bytes[18] = 'o'; bytes[19] = 'l'; bytes[20] = 0; bytes[21] = 0; bytes[22] = 0; bytes[23] = 0; bytes[24] = 0; bytes[25] = 0; bytes[26] = 0; bytes[27] = 0; System.arraycopy( infoHash, // source 0, // source offset bytes, // destination 28, // destination offset 20); // length System.arraycopy( peerIdBytes, // source 0, // source offset bytes, // destination 48, // destination offset 20); // length return bytes; } /** Decodes the given bytes into a new BitTorrentHandshakeMessage instance. * * @param bytes the given bytes * @return a new instance */ public static BitTorrentHandshakeMessage decode(final byte[] bytes) { //Preconditions assert bytes != null : "bytes must not be null"; assert bytes.length == 68 : "bytes must be length 68"; final byte[] infoHash = new byte[20]; System.arraycopy( bytes, // source 28, // source offset infoHash, // destination 0, // destination offset 20); // length final byte[] peerIdBytes = new byte[20]; System.arraycopy( bytes, // source 48, // source offset peerIdBytes, // destination 0, // destination offset 20); // length return new BitTorrentHandshakeMessage(infoHash, peerIdBytes); } }