forked from I2P_Developers/i2p.i2p
* Increase the tunnel test timeout rapidly if our tunnels are failing.
* Honor message expirations for some tunnel jobs that were prematurely
expired.
* Streamline memory usage with temporary object caches and more efficient
serialization for SHA256 calculation, logging, and both I2CP and I2NP
message handling.
* Fix some situations where we forward messages too eagerly. For a
request at the tunnel endpoint, if the tunnel is inbound and the target
is remote, honor the message by tunnel routing the data rather than
sending it directly to the requested location.
159 lines
6.0 KiB
Java
159 lines
6.0 KiB
Java
package net.i2p.data.i2np;
|
|
/*
|
|
* 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.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
|
|
import net.i2p.I2PAppContext;
|
|
import net.i2p.data.DataFormatException;
|
|
import net.i2p.data.DataHelper;
|
|
import net.i2p.util.Log;
|
|
|
|
/**
|
|
* Handle messages from router to router. This class is NOT threadsafe
|
|
*
|
|
*/
|
|
public class I2NPMessageHandler {
|
|
private Log _log;
|
|
private I2PAppContext _context;
|
|
private long _lastReadBegin;
|
|
private long _lastReadEnd;
|
|
private int _lastSize;
|
|
private byte _messageBuffer[];
|
|
private I2NPMessage _lastRead;
|
|
|
|
public I2NPMessageHandler(I2PAppContext context) {
|
|
_context = context;
|
|
_log = context.logManager().getLog(I2NPMessageHandler.class);
|
|
_messageBuffer = null;
|
|
_lastSize = -1;
|
|
}
|
|
|
|
/**
|
|
* Read an I2NPMessage from the stream and return the fully populated object.
|
|
*
|
|
* @throws IOException if there is an IO problem reading from the stream
|
|
* @throws I2NPMessageException if there is a problem handling the particular
|
|
* message - if it is an unknown type or has improper formatting, etc.
|
|
*/
|
|
public I2NPMessage readMessage(InputStream in) throws IOException, I2NPMessageException {
|
|
if (_messageBuffer == null) _messageBuffer = new byte[38*1024]; // more than necessary
|
|
try {
|
|
int type = (int)DataHelper.readLong(in, 1);
|
|
_lastReadBegin = System.currentTimeMillis();
|
|
I2NPMessage msg = createMessage(type);
|
|
if (msg == null)
|
|
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
|
|
try {
|
|
_lastSize = msg.readBytes(in, type, _messageBuffer);
|
|
} catch (IOException ioe) {
|
|
throw ioe;
|
|
} catch (I2NPMessageException ime) {
|
|
throw ime;
|
|
} catch (Exception e) {
|
|
if (_log.shouldLog(Log.WARN))
|
|
_log.warn("Error reading the stream", e);
|
|
throw new IOException("Unknown error reading the " + msg.getClass().getName()
|
|
+ ": " + e.getMessage());
|
|
}
|
|
_lastReadEnd = System.currentTimeMillis();
|
|
return msg;
|
|
} catch (DataFormatException dfe) {
|
|
throw new I2NPMessageException("Error reading the message", dfe);
|
|
}
|
|
}
|
|
|
|
/** clear the last message read from a byte array with an offset */
|
|
public I2NPMessage lastRead() {
|
|
I2NPMessage rv = _lastRead;
|
|
_lastRead = null;
|
|
return rv;
|
|
}
|
|
|
|
/**
|
|
* Read an I2NPMessage from the stream and return the fully populated object.
|
|
*
|
|
* @throws IOException if there is an IO problem reading from the stream
|
|
* @throws I2NPMessageException if there is a problem handling the particular
|
|
* message - if it is an unknown type or has improper formatting, etc.
|
|
*/
|
|
public I2NPMessage readMessage(byte data[]) throws IOException, I2NPMessageException {
|
|
int offset = readMessage(data, 0);
|
|
return lastRead();
|
|
}
|
|
public int readMessage(byte data[], int offset) throws IOException, I2NPMessageException {
|
|
int cur = offset;
|
|
int type = (int)DataHelper.fromLong(data, cur, 1);
|
|
cur++;
|
|
_lastReadBegin = System.currentTimeMillis();
|
|
I2NPMessage msg = createMessage(type);
|
|
if (msg == null)
|
|
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
|
|
try {
|
|
_lastSize = msg.readBytes(data, type, cur);
|
|
cur += _lastSize;
|
|
} catch (IOException ioe) {
|
|
throw ioe;
|
|
} catch (I2NPMessageException ime) {
|
|
throw ime;
|
|
} catch (Exception e) {
|
|
if (_log.shouldLog(Log.WARN))
|
|
_log.warn("Error reading the stream", e);
|
|
throw new IOException("Unknown error reading the " + msg.getClass().getName()
|
|
+ ": " + e.getMessage());
|
|
}
|
|
_lastReadEnd = System.currentTimeMillis();
|
|
_lastRead = msg;
|
|
return cur - offset;
|
|
}
|
|
|
|
public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; }
|
|
public int getLastSize() { return _lastSize; }
|
|
|
|
/**
|
|
* Yes, this is fairly ugly, but its the only place it ever happens.
|
|
*
|
|
*/
|
|
private I2NPMessage createMessage(int type) throws I2NPMessageException {
|
|
switch (type) {
|
|
case DatabaseStoreMessage.MESSAGE_TYPE:
|
|
return new DatabaseStoreMessage(_context);
|
|
case DatabaseLookupMessage.MESSAGE_TYPE:
|
|
return new DatabaseLookupMessage(_context);
|
|
case DatabaseSearchReplyMessage.MESSAGE_TYPE:
|
|
return new DatabaseSearchReplyMessage(_context);
|
|
case DeliveryStatusMessage.MESSAGE_TYPE:
|
|
return new DeliveryStatusMessage(_context);
|
|
case GarlicMessage.MESSAGE_TYPE:
|
|
return new GarlicMessage(_context);
|
|
case TunnelMessage.MESSAGE_TYPE:
|
|
return new TunnelMessage(_context);
|
|
case DataMessage.MESSAGE_TYPE:
|
|
return new DataMessage(_context);
|
|
case TunnelCreateMessage.MESSAGE_TYPE:
|
|
return new TunnelCreateMessage(_context);
|
|
case TunnelCreateStatusMessage.MESSAGE_TYPE:
|
|
return new TunnelCreateStatusMessage(_context);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public static void main(String args[]) {
|
|
try {
|
|
I2NPMessage msg = new I2NPMessageHandler(I2PAppContext.getGlobalContext()).readMessage(new FileInputStream(args[0]));
|
|
System.out.println(msg);
|
|
} catch (Exception e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|