package edu.washington.cs.oneswarm.f2f.messaging;
import java.util.HashMap;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.core3.util.DirectByteBuffer;
import org.gudy.azureus2.core3.util.DirectByteBufferPool;
import com.aelitis.azureus.core.networkmanager.RawMessage;
import com.aelitis.azureus.core.networkmanager.impl.RawMessageImpl;
import com.aelitis.azureus.core.peermanager.messaging.Message;
import com.aelitis.azureus.core.peermanager.messaging.MessageException;
import com.aelitis.azureus.core.peermanager.messaging.MessageManager;
public class OSF2FMessageFactory {
private final static boolean NO_DELAY = true;
private final static boolean DELAY_OK = false;
private static final String[] id_to_name = new String[OSF2FMessage.LAST_ID + 1];
private static final HashMap<String, LegacyData> legacy_data = new HashMap<String, LegacyData>();
static {
legacy_data.put(OSF2FMessage.ID_OS_TEXT_SEARCH, new LegacyData(RawMessage.PRIORITY_HIGH,
NO_DELAY, null, OSF2FMessage.SUBID_OS_TEXT_SEARCH));
id_to_name[OSF2FMessage.SUBID_OS_TEXT_SEARCH] = OSF2FMessage.ID_OS_TEXT_SEARCH;
legacy_data.put(OSF2FMessage.ID_OS_TEXT_SEARCH_RESP, new LegacyData(
RawMessage.PRIORITY_HIGH, NO_DELAY, null, OSF2FMessage.SUBID_OS_TEXT_SEARCH_RESP));
id_to_name[OSF2FMessage.SUBID_OS_TEXT_SEARCH_RESP] = OSF2FMessage.ID_OS_TEXT_SEARCH_RESP;
legacy_data.put(OSF2FMessage.ID_OS_METAINFO_REQ, new LegacyData(RawMessage.PRIORITY_HIGH,
NO_DELAY, null, OSF2FMessage.SUBID_OS_METAINFO_REQ));
id_to_name[OSF2FMessage.SUBID_OS_METAINFO_REQ] = OSF2FMessage.ID_OS_METAINFO_REQ;
legacy_data.put(OSF2FMessage.ID_OS_METAINFO_RESP, new LegacyData(RawMessage.PRIORITY_HIGH,
NO_DELAY, null, OSF2FMessage.SUBID_OS_METAINFO_RESP));
id_to_name[OSF2FMessage.SUBID_OS_METAINFO_RESP] = OSF2FMessage.ID_OS_METAINFO_RESP;
legacy_data.put(OSF2FMessage.ID_OS_CHANNEL_SETUP, new LegacyData(RawMessage.PRIORITY_HIGH,
NO_DELAY, null, OSF2FMessage.SUBID_OS_CHANNEL_SETUP));
id_to_name[OSF2FMessage.SUBID_OS_CHANNEL_SETUP] = OSF2FMessage.ID_OS_CHANNEL_SETUP;
legacy_data
.put(OSF2FMessage.ID_OS_CHANNEL_DATA_MSG, new LegacyData(
RawMessage.PRIORITY_NORMAL, NO_DELAY, null,
OSF2FMessage.SUBID_OS_CHANNEL_DATA_MSG));
id_to_name[OSF2FMessage.SUBID_OS_CHANNEL_DATA_MSG] = OSF2FMessage.ID_OS_CHANNEL_DATA_MSG;
legacy_data.put(OSF2FMessage.ID_OS_CHANNEL_RST, new LegacyData(RawMessage.PRIORITY_LOW,
NO_DELAY, null, OSF2FMessage.SUBID_OS_CHANNEL_RST));
id_to_name[OSF2FMessage.SUBID_OS_CHANNEL_RST] = OSF2FMessage.ID_OS_CHANNEL_RST;
legacy_data.put(OSF2FMessage.ID_OS_HASH_SEARCH, new LegacyData(RawMessage.PRIORITY_NORMAL,
NO_DELAY, null, OSF2FMessage.SUBID_OS_HASH_SEARCH));
id_to_name[OSF2FMessage.SUBID_OS_HASH_SEARCH] = OSF2FMessage.ID_OS_HASH_SEARCH;
legacy_data.put(OSF2FMessage.ID_OS_SEARCH_CANCEL, new LegacyData(
RawMessage.PRIORITY_NORMAL, NO_DELAY, null, OSF2FMessage.SUBID_OS_SEARCH_CANCEL));
id_to_name[OSF2FMessage.SUBID_OS_SEARCH_CANCEL] = OSF2FMessage.ID_OS_SEARCH_CANCEL;
legacy_data.put(OSF2FMessage.ID_OS_CHAT, new LegacyData(RawMessage.PRIORITY_NORMAL,
NO_DELAY, null, OSF2FMessage.SUBID_OS_CHAT));
id_to_name[OSF2FMessage.SUBID_OS_CHAT] = OSF2FMessage.ID_OS_CHAT;
legacy_data.put(OSF2FMessage.ID_OS_DHT_LOCATION, new LegacyData(RawMessage.PRIORITY_NORMAL,
NO_DELAY, null, OSF2FMessage.SUBID_OS_DHT_LOCATION));
id_to_name[OSF2FMessage.SUBID_OS_DHT_LOCATION] = OSF2FMessage.ID_OS_DHT_LOCATION;
legacy_data.put(OSF2FMessage.ID_OS_DATAGRAM_INIT, new LegacyData(RawMessage.PRIORITY_HIGH,
NO_DELAY, null, OSF2FMessage.SUBID_OS_DATAGRAM_INIT));
id_to_name[OSF2FMessage.SUBID_OS_DATAGRAM_INIT] = OSF2FMessage.ID_OS_DATAGRAM_INIT;
legacy_data.put(OSF2FMessage.ID_OS_DATAGRAM_OK, new LegacyData(RawMessage.PRIORITY_HIGH,
NO_DELAY, null, OSF2FMessage.SUBID_OS_DATAGRAM_OK));
id_to_name[OSF2FMessage.SUBID_OS_DATAGRAM_OK] = OSF2FMessage.ID_OS_DATAGRAM_OK;
}
/**
* Initialize the factory, i.e. register the messages with the message
* manager.
*/
public static void init() {
try {
MessageManager.getSingleton().registerMessageType(
new OSF2FHandshake(OSF2FMessage.CURRENT_VERSION, new byte[0]));
MessageManager.getSingleton().registerMessageType(
new OSF2FHashSearch(OSF2FMessage.CURRENT_VERSION, 0, 0));
MessageManager.getSingleton().registerMessageType(
new OSF2FHashSearchResp(OSF2FMessage.CURRENT_VERSION, 0, 0, 0));
MessageManager.getSingleton().registerMessageType(
new OSF2FChannelDataMsg(OSF2FMessage.CURRENT_VERSION, 0, null));
MessageManager.getSingleton().registerMessageType(
new OSF2FChannelReset(OSF2FMessage.CURRENT_VERSION, 0));
MessageManager.getSingleton().registerMessageType(
new OSF2FTextSearch(OSF2FMessage.CURRENT_VERSION, (byte) 0, 0, ""));
MessageManager.getSingleton().registerMessageType(
new OSF2FTextSearchResp(OSF2FMessage.CURRENT_VERSION, (byte) 0, 0, 0,
new byte[0]));
MessageManager.getSingleton().registerMessageType(
new OSF2FMetaInfoReq(OSF2FMessage.CURRENT_VERSION, 0,
OSF2FMessage.METAINFO_TYPE_BITTORRENT, 0, new byte[0]));
MessageManager.getSingleton().registerMessageType(
new OSF2FMetaInfoResp(OSF2FMessage.CURRENT_VERSION, 0,
OSF2FMessage.METAINFO_TYPE_BITTORRENT, 0, 0, 0, new byte[0]));
MessageManager.getSingleton().registerMessageType(
new OSF2FSearchCancel(OSF2FMessage.CURRENT_VERSION, 0));
MessageManager.getSingleton().registerMessageType(
new OSF2FChat(OSF2FChat.CURRENT_VERSION, null));
MessageManager.getSingleton().registerMessageType(
new OSF2FDhtLocation(OSF2FDhtLocation.CURRENT_VERSION, null, null));
MessageManager.getSingleton()
.registerMessageType(
new OSF2FDatagramInit(OSF2FDatagramInit.CURRENT_VERSION, 0, null, null,
null, 0));
MessageManager.getSingleton().registerMessageType(new OSF2FDatagramOk(0));
} catch (MessageException me) {
me.printStackTrace();
}
}
public static int getMessageType(DirectByteBuffer stream_payload) {
byte id = stream_payload.get(DirectByteBuffer.SS_MSG, 0);
if (id == 101)
return Message.TYPE_PROTOCOL_PAYLOAD; // handshake
// message byte
// in position 4
// ("e" in
// OneSwarm)
if (id >= 0 && id < id_to_name.length) {
return MessageManager.getSingleton().lookupMessage(id_to_name[id]).getType();
}
// invalid, return whatever
return Message.TYPE_PROTOCOL_PAYLOAD;
}
/**
* Construct a new OSF2F message instance from the given message raw byte
* stream.
*
* @param stream_payload
* data
* @return decoded/deserialized BT message
* @throws MessageException
* if message creation failed NOTE: Does not auto-return given
* direct buffer on thrown exception.
*/
public static Message createOSF2FMessage(DirectByteBuffer stream_payload)
throws MessageException {
byte id = stream_payload.get(DirectByteBuffer.SS_MSG);
switch (id) {
case OSF2FMessage.SUBID_OS_CHANNEL_SETUP:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_CHANNEL_SETUP_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_HASH_SEARCH:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_HASH_SEARCH_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_CHANNEL_DATA_MSG:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_CHANNEL_DATA_MSG_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_CHANNEL_RST:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_CHANNEL_RST_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_TEXT_SEARCH:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_TEXT_SEARCH_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_TEXT_SEARCH_RESP:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_TEXT_SEARCH_RESP_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_METAINFO_REQ:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_METAINFO_REQ_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_METAINFO_RESP:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_METAINFO_RESP_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_SEARCH_CANCEL:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_SEARCH_CANCEL_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_CHAT:
return MessageManager.getSingleton().createMessage(OSF2FMessage.ID_OS_CHAT_BYTES,
stream_payload, OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_DHT_LOCATION:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_DHT_LOCATION_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_DATAGRAM_INIT:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_DATAGRAM_INIT_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
case OSF2FMessage.SUBID_OS_DATAGRAM_OK:
return MessageManager.getSingleton().createMessage(
OSF2FMessage.ID_OS_DATAGRAM_OK_BYTES, stream_payload,
OSF2FMessage.CURRENT_VERSION);
default: {
System.out.println("Unknown OSF2F message id [" + id + "]");
throw new MessageException("Unknown OSF2F message id [" + id + "]");
}
}
}
/**
* Create the proper OSF2F raw message from the given base message.
*
* @param base_message
* to create from
* @return BT raw message
*/
public static RawMessage createOSF2FRawMessage(Message base_message) {
if (base_message instanceof RawMessage) { // used for handshake and
// keep-alive messages
return (RawMessage) base_message;
}
LegacyData ld = legacy_data.get(base_message.getID());
if (ld == null) {
Debug.out("legacy message type id not found for [" + base_message.getID() + "]");
return null; // message id type not found
}
DirectByteBuffer[] payload = base_message.getData();
int payload_size = 0;
for (int i = 0; i < payload.length; i++) {
payload_size += payload[i].remaining(DirectByteBuffer.SS_MSG);
}
DirectByteBuffer header = DirectByteBufferPool.getBuffer(DirectByteBuffer.AL_MSG_BT_HEADER,
5);
header.putInt(DirectByteBuffer.SS_MSG, 1 + payload_size);
header.put(DirectByteBuffer.SS_MSG, ld.bt_id);
header.flip(DirectByteBuffer.SS_MSG);
DirectByteBuffer[] raw_buffs = new DirectByteBuffer[payload.length + 1];
raw_buffs[0] = header;
for (int i = 0; i < payload.length; i++) {
raw_buffs[i + 1] = payload[i];
}
return new RawMessageImpl(base_message, raw_buffs, ld.priority, ld.is_no_delay,
ld.to_remove);
}
protected static class LegacyData {
protected final int priority;
protected final boolean is_no_delay;
protected final Message[] to_remove;
protected final byte bt_id;
protected LegacyData(int prio, boolean no_delay, Message[] remove, byte btid) {
this.priority = prio;
this.is_no_delay = no_delay;
this.to_remove = remove;
this.bt_id = btid;
}
}
}