/*
* 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>";
}
}
}