package net.i2p.data.i2cp;
/*
* free (adj.): unencumbered; not under the control of others
* Written by jrandom in 2003 and released into the public domain
* with no warranty of any kind, either expressed or implied.
* It probably won't make your computer catch on fire, or eat
* your children, but it might. Use at your own risk.
*
*/
import java.io.IOException;
import java.io.InputStream;
import net.i2p.data.DataFormatException;
import net.i2p.data.DataHelper;
/**
* Handle messages from the server for the client or vice versa
*
*/
public class I2CPMessageHandler {
/**
* This is huge. Mainly to catch a completly bogus response, possibly not an I2CP socket.
* @since 0.9.11
*/
public static final int MAX_LENGTH = 128*1024;
/**
* Read an I2CPMessage from the stream and return the fully populated object.
*
* @param in I2CP input stream
* @return Fully populated I2CPMessage
* @throws IOException if there is an IO problem reading from the stream
* @throws I2CPMessageException if there is a problem handling the particular
* message - if it is an unknown type or has improper formatting, etc.
*/
public static I2CPMessage readMessage(InputStream in) throws IOException, I2CPMessageException {
int length;
try {
length = (int) DataHelper.readLong(in, 4);
} catch (DataFormatException dfe) {
throw new IOException("Connection closed");
}
if (length > MAX_LENGTH)
throw new I2CPMessageException("Invalid message length specified");
try {
int type = (int) DataHelper.readLong(in, 1);
I2CPMessage msg = createMessage(type);
// Note that the readMessage() calls don't, in general, read and discard
// extra data, so we can't add new fields to the end of messages
// in a compatible way. And the readers could read beyond the length too.
// To fix this we'd have to read into a BAOS/BAIS or use a filter input stream
msg.readMessage(in, length, type);
return msg;
} catch (DataFormatException dfe) {
throw new I2CPMessageException("Error reading the message", dfe);
}
}
/**
* Yes, this is fairly ugly, but its the only place it ever happens.
*
*/
private static I2CPMessage createMessage(int type) throws
I2CPMessageException {
switch (type) {
case CreateLeaseSetMessage.MESSAGE_TYPE:
return new CreateLeaseSetMessage();
case CreateSessionMessage.MESSAGE_TYPE:
return new CreateSessionMessage();
case DestroySessionMessage.MESSAGE_TYPE:
return new DestroySessionMessage();
case DisconnectMessage.MESSAGE_TYPE:
return new DisconnectMessage();
case MessageStatusMessage.MESSAGE_TYPE:
return new MessageStatusMessage();
case MessagePayloadMessage.MESSAGE_TYPE:
return new MessagePayloadMessage();
case ReceiveMessageBeginMessage.MESSAGE_TYPE:
return new ReceiveMessageBeginMessage();
case ReceiveMessageEndMessage.MESSAGE_TYPE:
return new ReceiveMessageEndMessage();
case ReconfigureSessionMessage.MESSAGE_TYPE:
return new ReconfigureSessionMessage();
case ReportAbuseMessage.MESSAGE_TYPE:
return new ReportAbuseMessage();
case RequestLeaseSetMessage.MESSAGE_TYPE:
return new RequestLeaseSetMessage();
case RequestVariableLeaseSetMessage.MESSAGE_TYPE:
return new RequestVariableLeaseSetMessage();
case SendMessageMessage.MESSAGE_TYPE:
return new SendMessageMessage();
case SendMessageExpiresMessage.MESSAGE_TYPE:
return new SendMessageExpiresMessage();
case SessionStatusMessage.MESSAGE_TYPE:
return new SessionStatusMessage();
case GetDateMessage.MESSAGE_TYPE:
return new GetDateMessage();
case SetDateMessage.MESSAGE_TYPE:
return new SetDateMessage();
case DestLookupMessage.MESSAGE_TYPE:
return new DestLookupMessage();
case DestReplyMessage.MESSAGE_TYPE:
return new DestReplyMessage();
case GetBandwidthLimitsMessage.MESSAGE_TYPE:
return new GetBandwidthLimitsMessage();
case BandwidthLimitsMessage.MESSAGE_TYPE:
return new BandwidthLimitsMessage();
case HostLookupMessage.MESSAGE_TYPE:
return new HostLookupMessage();
case HostReplyMessage.MESSAGE_TYPE:
return new HostReplyMessage();
default:
throw new I2CPMessageException("The type " + type + " is an unknown I2CP message");
}
}
/***
public static void main(String args[]) {
try {
I2CPMessage msg = readMessage(new FileInputStream(args[0]));
System.out.println(msg);
} catch (Exception e) {
e.printStackTrace();
}
}
***/
}