package com.limegroup.gnutella.messages.vendor;
import java.io.IOException;
import java.io.OutputStream;
import com.limegroup.gnutella.ByteOrder;
import com.limegroup.gnutella.GUID;
import com.limegroup.gnutella.RouterService;
import com.limegroup.gnutella.messages.BadPacketException;
import com.limegroup.gnutella.statistics.SentMessageStatHandler;
/** In Vendor Message parlance, the "message type" of this VMP is "LIME/12".
* This message contains a unsigned byte (1-255) that tells you how many
* results the sending host has for the guid of a query (the guid of this
* message is the same as the original query). The recieving host can ACK
* this message with a LimeACKVendorMessage to actually recieve the replies.
*
* This message must maintain backwards compatibility between successive
* versions. This entails that any new features would grow the message
* outward but shouldn't change the meaning of older fields. This could lead
* to some issues (i.e. abandoning fields does not allow for older fields to
* be reused) but since we don't expect major changes this is probably OK.
*
* Note that this behavior of maintaining backwards compatiblity is really
* only necessary for UDP messages since in the UDP case there is probably no
* MessagesSupportedVM exchange.
*/
public final class ReplyNumberVendorMessage extends VendorMessage {
public static final int VERSION = 2;
/**
* whether we can receive unsolicited udp
*/
private static final byte UNSOLICITED=0x1;
/**
* Constructs a new ReplyNumberVendorMessages with data from the network.
*/
ReplyNumberVendorMessage(byte[] guid, byte ttl, byte hops, int version,
byte[] payload)
throws BadPacketException {
super(guid, ttl, hops, F_LIME_VENDOR_ID, F_REPLY_NUMBER, version,
payload);
if (getPayload().length < 1)
throw new BadPacketException("UNSUPPORTED PAYLOAD LENGTH: " +
getPayload().length);
if ((getVersion() == 1) && (getPayload().length != 1))
throw new BadPacketException("VERSION 1 UNSUPPORTED PAYLOAD LEN: " +
getPayload().length);
if ((getVersion() == 2) && (getPayload().length != 2))
throw new BadPacketException("VERSION 2 UNSUPPORTED PAYLOAD LEN: " +
getPayload().length);
}
/**
* Constructs a new ReplyNumberVendorMessage to be sent out.
* @param numResults The number of results (1-255 inclusive) that you have
* for this query. If you have more than 255 just send 255.
* @param replyGUID The guid of the original query/reply that you want to
* send reply info for.
*/
public ReplyNumberVendorMessage(GUID replyGUID, int numResults) {
super(F_LIME_VENDOR_ID, F_REPLY_NUMBER, VERSION,
derivePayload(numResults));
setGUID(replyGUID);
}
/** @return an int (1-255) representing the amount of results that a host
* for a given query (as specified by the guid of this message).
*/
public int getNumResults() {
return ByteOrder.ubyte2int(getPayload()[0]);
}
public boolean canReceiveUnsolicited() {
if (getVersion() ==1)
return true;
else
return (getPayload()[1] & UNSOLICITED) == UNSOLICITED;
}
/**
* Constructs the payload from the desired number of results.
*/
private static byte[] derivePayload(int numResults) {
if ((numResults < 1) || (numResults > 255))
throw new IllegalArgumentException("Number of results too big: " +
numResults);
byte[] payload = new byte[2];
byte[] bytes = new byte[2];
ByteOrder.short2leb((short) numResults, bytes, 0);
payload[0] = bytes[0];
payload[1] = RouterService.canReceiveUnsolicited() ?
UNSOLICITED : 0x0;
return payload;
}
public boolean equals(Object other) {
if (other instanceof ReplyNumberVendorMessage) {
GUID myGuid = new GUID(getGUID());
GUID otherGuid = new GUID(((VendorMessage) other).getGUID());
int otherResults =
((ReplyNumberVendorMessage) other).getNumResults();
return ((myGuid.equals(otherGuid)) &&
(getNumResults() == otherResults) &&
super.equals(other));
}
return false;
}
/** Overridden purely for stats handling.
*/
protected void writePayload(OutputStream out) throws IOException {
super.writePayload(out);
SentMessageStatHandler.UDP_REPLY_NUMBER.addMessage(this);
}
/** Overridden purely for stats handling.
*/
public void recordDrop() {
super.recordDrop();
}
}