2005-10-19 22:02:37 +00:00
|
|
|
/* 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;
|
|
|
|
|
2005-12-19 13:34:52 +00:00
|
|
|
import net.i2p.util.SimpleTimer;
|
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
// 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;
|
|
|
|
|
2005-12-19 13:34:52 +00:00
|
|
|
SimpleTimer.TimedEvent expireEvent;
|
|
|
|
|
2005-10-19 22:02:37 +00:00
|
|
|
/** 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);
|
|
|
|
}
|
|
|
|
|
|
|
|
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>";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|