/* * Message - A protocol message which can be send through a DataOutputStream. * Copyright (C) 2003 Mark J. Wielaard * * This file is part of Snark. * * 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, 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., 59 Temple * Place - Suite 330, Boston, MA 02111-1307, USA. */ package org.klomp.snark; import java.io.DataOutputStream; import java.io.IOException; // Used to queue outgoing connections // sendMessage() should be used to translate them to wire format. class Message { final static byte KEEP_ALIVE = -1; final static byte CHOKE = 0; final static byte UNCHOKE = 1; final static byte INTERESTED = 2; final static byte UNINTERESTED = 3; final static byte HAVE = 4; final static byte BITFIELD = 5; final static byte REQUEST = 6; final static byte PIECE = 7; final static byte CANCEL = 8; // Not all fields are used for every message. // KEEP_ALIVE doesn't have a real wire representation byte type; // Used for HAVE, REQUEST, PIECE and CANCEL messages. int piece; // Used for REQUEST, PIECE and CANCEL messages. int begin; int length; // Used for PIECE and BITFIELD messages byte[] data; int off; int len; /** Utility method for sending a message through a DataStream. */ void sendMessage (DataOutputStream dos) throws IOException { // KEEP_ALIVE is special. if (type == KEEP_ALIVE) { dos.writeInt(0); return; } // Calculate the total length in bytes // Type is one byte. int datalen = 1; // piece is 4 bytes. if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL) { datalen += 4; } // begin/offset is 4 bytes if (type == REQUEST || type == PIECE || type == CANCEL) { datalen += 4; } // length is 4 bytes if (type == REQUEST || type == CANCEL) { datalen += 4; } // add length of data for piece or bitfield array. if (type == BITFIELD || type == PIECE) { datalen += len; } // Send length dos.writeInt(datalen); dos.writeByte(type & 0xFF); // Send additional info (piece number) if (type == HAVE || type == REQUEST || type == PIECE || type == CANCEL) { dos.writeInt(piece); } // Send additional info (begin/offset) if (type == REQUEST || type == PIECE || type == CANCEL) { dos.writeInt(begin); } // Send additional info (length); for PIECE this is implicit. if (type == REQUEST || type == CANCEL) { dos.writeInt(length); } // Send actual data if (type == BITFIELD || type == PIECE) { dos.write(data, off, len); } } @Override public String toString () { switch (type) { case KEEP_ALIVE: return "KEEP_ALIVE"; case CHOKE: return "CHOKE"; case UNCHOKE: return "UNCHOKE"; case INTERESTED: return "INTERESTED"; case UNINTERESTED: return "UNINTERESTED"; case HAVE: return "HAVE(" + piece + ")"; case BITFIELD: return "BITFIELD"; case REQUEST: return "REQUEST(" + piece + "," + begin + "," + length + ")"; case PIECE: return "PIECE(" + piece + "," + begin + "," + length + ")"; case CANCEL: return "CANCEL(" + piece + "," + begin + "," + length + ")"; default: return "<UNKNOWN>"; } } }