- Earlier detection and better logging of
      truncated TunnelGatewayMessage and DatabaseStoreMessage
    - Fix and enhance UnknownI2NPMessage implementation
    - Don't deserialize or verify the checksum of the
      embeddedI2NP message in the TunnelGatewayMessage
      at the IBGW, just use UnknownI2NPMessage and pass it along,
      except if zero hop; Still to do: similar thing at OBEP
    - Round expiration times when converting to/from seconds for SSU
    - Cleanups and javadoc
This commit is contained in:
zzz
2011-12-09 17:36:49 +00:00
parent 937ae8ad60
commit 25b0603fde
13 changed files with 274 additions and 88 deletions

View File

@@ -24,6 +24,9 @@ import net.i2p.data.TunnelId;
* Defines the message a router sends to another router to test the network
* database reachability, as well as the reply message sent back.
*
* TODO: Don't decompress and recompress RouterInfos at the OBEP and IBGW.
* Could this even change the message length or corrupt things?
*
* @author jrandom
*/
public class DatabaseStoreMessage extends I2NPMessageImpl {
@@ -128,14 +131,22 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
_dbEntry = new RouterInfo();
int compressedSize = (int)DataHelper.fromLong(data, curIndex, 2);
curIndex += 2;
if (compressedSize <= 0 || curIndex + compressedSize > data.length || (curIndex - offset) + compressedSize > dataSize)
throw new I2NPMessageException("Compressed RI length: " + compressedSize +
" but remaining bytes: " + Math.min(data.length - curIndex, dataSize - (curIndex - offset)));
try {
// TODO we could delay decompression, just copy to a new byte array and store in _byteCache
// May not be necessary since the IBGW now uses UnknownI2NPMessage.
// DSMs at the OBEP are generally garlic wrapped, so the OBEP won't see it.
// If we do delay it, getEntry() will have to check if _dbEntry is null and _byteCache
// is non-null, and then decompress.
byte decompressed[] = DataHelper.decompress(data, curIndex, compressedSize);
_dbEntry.readBytes(new ByteArrayInputStream(decompressed));
} catch (DataFormatException dfe) {
throw new I2NPMessageException("Error reading the routerInfo", dfe);
} catch (IOException ioe) {
throw new I2NPMessageException("Compressed routerInfo was corrupt", ioe);
throw new I2NPMessageException("Corrupt compressed routerInfo size = " + compressedSize, ioe);
}
} else {
throw new I2NPMessageException("Invalid type of key read from the structure - " + type);
@@ -145,17 +156,29 @@ public class DatabaseStoreMessage extends I2NPMessageImpl {
}
/** calculate the message body's length (not including the header and footer */
/**
* calculate the message body's length (not including the header and footer)
*
* @throws IllegalStateException
*/
protected int calculateWrittenLength() {
// TODO if _byteCache is non-null, don't check _dbEntry
if (_dbEntry == null)
throw new IllegalStateException("Missing entry");
int len = Hash.HASH_LENGTH + 1 + 4; // key+type+replyToken
if (_replyToken > 0)
len += 4 + Hash.HASH_LENGTH; // replyTunnel+replyGateway
int type = _dbEntry.getType();
if (type == DatabaseEntry.KEY_TYPE_LEASESET) {
_byteCache = _dbEntry.toByteArray();
if (_byteCache == null) {
_byteCache = _dbEntry.toByteArray();
}
} else if (type == DatabaseEntry.KEY_TYPE_ROUTERINFO) {
byte uncompressed[] = _dbEntry.toByteArray();
_byteCache = DataHelper.compress(uncompressed);
// only decompress once
if (_byteCache == null) {
byte uncompressed[] = _dbEntry.toByteArray();
_byteCache = DataHelper.compress(uncompressed);
}
len += 2;
} else {
throw new IllegalStateException("Invalid key type " + type);

View File

@@ -12,7 +12,6 @@ import java.io.IOException;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.util.Log;
/**
* Defines the wrapped garlic message
@@ -20,7 +19,6 @@ import net.i2p.util.Log;
* @author jrandom
*/
public class GarlicMessage extends I2NPMessageImpl {
private final static Log _log = new Log(GarlicMessage.class);
public final static int MESSAGE_TYPE = 11;
private byte[] _data;

View File

@@ -49,8 +49,9 @@ public class I2NPMessageHandler {
int type = (int)DataHelper.readLong(in, 1);
_lastReadBegin = System.currentTimeMillis();
I2NPMessage msg = I2NPMessageImpl.createMessage(_context, type);
if (msg == null)
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
// can't be null
//if (msg == null)
// throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message");
try {
_lastSize = msg.readBytes(in, type, _messageBuffer);
} catch (IOException ioe) {
@@ -88,24 +89,26 @@ public class I2NPMessageHandler {
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 = I2NPMessageImpl.createMessage(_context, type);
if (msg == null) {
int sz = data.length-offset;
boolean allZero = false;
for (int i = offset; i < data.length; i++) {
if (data[i] != 0) {
allZero = false;
break;
}
}
throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message (remaining sz="
+ sz + " all zeros? " + allZero + ")");
}
// can't be null
//if (msg == null) {
// int sz = data.length-offset;
// boolean allZero = false;
// for (int i = offset; i < data.length; i++) {
// if (data[i] != 0) {
// allZero = false;
// break;
// }
// }
// throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message (remaining sz="
// + sz + " all zeros? " + allZero + ")");
//}
try {
_lastSize = msg.readBytes(data, type, cur);
cur += _lastSize;
@@ -127,6 +130,7 @@ public class I2NPMessageHandler {
public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; }
public int getLastSize() { return _lastSize; }
/****
public static void main(String args[]) {
try {
I2NPMessage msg = new I2NPMessageHandler(I2PAppContext.getGlobalContext()).readMessage(new FileInputStream(args[0]));
@@ -135,4 +139,5 @@ public class I2NPMessageHandler {
e.printStackTrace();
}
}
****/
}

View File

@@ -28,7 +28,7 @@ import net.i2p.util.SimpleByteCache;
* @author jrandom
*/
public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPMessage {
private final Log _log;
protected final Log _log;
protected final I2PAppContext _context;
private long _expiration;
private long _uniqueId;
@@ -36,12 +36,16 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
public final static long DEFAULT_EXPIRATION_MS = 1*60*1000; // 1 minute by default
public final static int CHECKSUM_LENGTH = 1; //Hash.HASH_LENGTH;
private static final boolean RAW_FULL_SIZE = false;
// Whether SSU used the full header or a truncated header.
// We are stuck with the short header, can't change it now.
//private static final boolean RAW_FULL_SIZE = false;
/** unused */
private static final Map<Integer, Builder> _builders = new ConcurrentHashMap(1);
/** @deprecated unused */
public static final void registerBuilder(Builder builder, int type) { _builders.put(Integer.valueOf(type), builder); }
/** interface for extending the types of messages handled - unused */
public interface Builder {
/** instantiate a new I2NPMessage to be populated shortly */
@@ -120,7 +124,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
boolean eq = DataHelper.eq(checksum, 0, calc, 0, CHECKSUM_LENGTH);
SimpleByteCache.release(calc);
if (!eq)
throw new I2NPMessageException("Hash does not match for " + getClass().getName());
throw new I2NPMessageException("Bad checksum on " + size + " byte I2NP " + getClass().getSimpleName());
//long start = _context.clock().now();
if (_log.shouldLog(Log.DEBUG))
@@ -182,7 +186,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
boolean eq = DataHelper.eq(hdata, 0, calc, 0, CHECKSUM_LENGTH);
SimpleByteCache.release(calc);
if (!eq)
throw new I2NPMessageException("Hash does not match for " + getClass().getName());
throw new I2NPMessageException("Bad checksum on " + size + " byte I2NP " + getClass().getSimpleName());
//long start = _context.clock().now();
if (_log.shouldLog(Log.DEBUG))
@@ -220,10 +224,15 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
public synchronized int getMessageSize() {
return calculateWrittenLength()+15 + CHECKSUM_LENGTH; // 16 bytes in the header
}
/**
* The raw header consists of a one-byte type and a 4-byte expiration in seconds only.
* Used by SSU only!
*/
public synchronized int getRawMessageSize() {
if (RAW_FULL_SIZE)
return getMessageSize();
else
//if (RAW_FULL_SIZE)
// return getMessageSize();
//else
return calculateWrittenLength()+5;
}
@@ -310,15 +319,21 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
*/
/** used by SSU only */
/**
* Write the message with a short 5-byte header.
* THe header consists of a one-byte type and a 4-byte expiration in seconds only.
* Used by SSU only!
*/
public int toRawByteArray(byte buffer[]) {
if (RAW_FULL_SIZE)
return toByteArray(buffer);
//if (RAW_FULL_SIZE)
// return toByteArray(buffer);
try {
int off = 0;
DataHelper.toLong(buffer, off, 1, getType());
off += 1;
DataHelper.toLong(buffer, off, 4, _expiration/1000); // seconds
// January 19 2038? No, unsigned, good until Feb. 7 2106
// in seconds, round up so we don't lose time every hop
DataHelper.toLong(buffer, off, 4, (_expiration + 500) / 1000);
off += 4;
return writeMessageBody(buffer, off);
} catch (I2NPMessageException ime) {
@@ -344,24 +359,30 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
}
*****/
/** used by SSU only */
/**
* Read the message with a short 5-byte header.
* THe header consists of a one-byte type and a 4-byte expiration in seconds only.
* Used by SSU only!
*/
public static I2NPMessage fromRawByteArray(I2PAppContext ctx, byte buffer[], int offset, int len, I2NPMessageHandler handler) throws I2NPMessageException {
int type = (int)DataHelper.fromLong(buffer, offset, 1);
offset++;
I2NPMessageImpl msg = (I2NPMessageImpl)createMessage(ctx, type);
if (msg == null)
throw new I2NPMessageException("Unknown message type: " + type);
if (RAW_FULL_SIZE) {
try {
msg.readBytes(buffer, type, offset);
} catch (IOException ioe) {
throw new I2NPMessageException("Error reading the " + msg, ioe);
}
return msg;
}
//if (RAW_FULL_SIZE) {
// try {
// msg.readBytes(buffer, type, offset);
// } catch (IOException ioe) {
// throw new I2NPMessageException("Error reading the " + msg, ioe);
// }
// return msg;
//}
try {
long expiration = DataHelper.fromLong(buffer, offset, 4) * 1000; // seconds
// January 19 2038? No, unsigned, good until Feb. 7 2106
// in seconds, round up so we don't lose time every hop
long expiration = (DataHelper.fromLong(buffer, offset, 4) * 1000) + 500;
offset += 4;
int dataSize = len - 1 - 4;
msg.readMessage(buffer, offset, dataSize, type, handler);
@@ -377,6 +398,7 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM
/**
* Yes, this is fairly ugly, but its the only place it ever happens.
*
* @return non-null, returns an UnknownI2NPMessage if unknown type
*/
public static I2NPMessage createMessage(I2PAppContext context, int type) throws I2NPMessageException {
switch (type) {

View File

@@ -22,7 +22,6 @@ import net.i2p.util.Log;
*
*/
public class TunnelDataMessage extends I2NPMessageImpl {
private Log _log;
private long _tunnelId;
private TunnelId _tunnelIdObj;
private byte[] _data;
@@ -101,7 +100,6 @@ public class TunnelDataMessage extends I2NPMessageImpl {
public TunnelDataMessage(I2PAppContext context) {
super(context);
_log = context.logManager().getLog(TunnelDataMessage.class);
setMessageExpiration(context.clock().now() + EXPIRATION_PERIOD);
}

View File

@@ -21,11 +21,10 @@ import net.i2p.util.Log;
*
*/
public class TunnelGatewayMessage extends I2NPMessageImpl {
private Log _log;
private TunnelId _tunnelId;
private I2NPMessage _msg;
private byte _msgData[];
private Exception _creator;
//private Exception _creator;
public final static int MESSAGE_TYPE = 19;
/** if we can't deliver a tunnel message in 10s, fuck it */
@@ -33,7 +32,6 @@ public class TunnelGatewayMessage extends I2NPMessageImpl {
public TunnelGatewayMessage(I2PAppContext context) {
super(context);
_log = context.logManager().getLog(TunnelGatewayMessage.class);
setMessageExpiration(context.clock().now() + EXPIRATION_PERIOD);
//_creator = new Exception("i made this");
}
@@ -41,7 +39,13 @@ public class TunnelGatewayMessage extends I2NPMessageImpl {
public TunnelId getTunnelId() { return _tunnelId; }
public void setTunnelId(TunnelId id) { _tunnelId = id; }
/**
* Warning, at the IBGW, where the message was read in,
* this will be an UnknownI2NPMessage.
* If you need a real message class, use UnknownI2NPMessage.convert().
*/
public I2NPMessage getMessage() { return _msg; }
public void setMessage(I2NPMessage msg) {
if (msg == null)
throw new IllegalArgumentException("wtf, dont set me to null");
@@ -61,7 +65,7 @@ public class TunnelGatewayMessage extends I2NPMessageImpl {
/** write the message body to the output array, starting at the given index */
protected int writeMessageBody(byte out[], int curIndex) throws I2NPMessageException {
if ( (_tunnelId == null) || ( (_msg == null) && (_msgData == null) ) ) {
_log.log(Log.CRIT, "failing to write out gateway message, created by: ", _creator);
_log.log(Log.CRIT, "failing to write out gateway message");
throw new I2NPMessageException("Not enough data to write out (id=" + _tunnelId + " data=" + _msg + ")");
}
@@ -87,9 +91,17 @@ public class TunnelGatewayMessage extends I2NPMessageImpl {
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
I2NPMessageHandler h = new I2NPMessageHandler(_context);
readMessage(data, offset, dataSize, type, h);
//I2NPMessageHandler h = new I2NPMessageHandler(_context);
//readMessage(data, offset, dataSize, type, h);
readMessage(data, offset, dataSize, type, null);
}
/**
* Note that for efficiency at the IBGW, this does not fully deserialize the included
* I2NP Message. It just puts it in an UnknownI2NPMessage.
*
* @param handler unused, may be null
*/
@Override
public void readMessage(byte data[], int offset, int dataSize, int type, I2NPMessageHandler handler) throws I2NPMessageException, IOException {
if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message");
@@ -101,12 +113,32 @@ public class TunnelGatewayMessage extends I2NPMessageImpl {
if (_tunnelId.getTunnelId() <= 0)
throw new I2NPMessageException("Invalid tunnel Id " + _tunnelId);
DataHelper.fromLong(data, curIndex, 2);
int len = (int) DataHelper.fromLong(data, curIndex, 2);
curIndex += 2;
curIndex = handler.readMessage(data, curIndex);
_msg = handler.lastRead();
if (_msg == null)
throw new I2NPMessageException("wtf, message read has no payload?");
if (len <= 1 || curIndex + len > data.length || len > dataSize - 6)
throw new I2NPMessageException("I2NP length in TGM: " + len +
" but remaining bytes: " + Math.min(data.length - curIndex, dataSize - 6));
// OLD WAY full message parsing and instantiation
//handler.readMessage(data, curIndex);
//_msg = handler.lastRead();
//if (_msg == null)
// throw new I2NPMessageException("wtf, message read has no payload?");
// NEW WAY save lots of effort at the IBGW by reading as an UnknownI2NPMessage instead
// This will save a lot of object churn and processing,
// primarily for unencrypted msgs (V)TBRM, DatabaseStoreMessage, and DSRMs.
// DatabaseStoreMessages in particluar are intensive for readBytes()
// since the RI is decompressed.
// For a zero-hop IB tunnel, where we do need the real thing,
// it is converted to a real message class in TunnelGatewayZeroHop
// using UnknownI2NPMessage.convert() in TunnelGatewayZeroHop.
// We also skip processing the checksum as it's covered by the TGM checksum.
// If a zero-hop, the checksum will be verified in convert().
int utype = data[curIndex++] & 0xff;
UnknownI2NPMessage umsg = new UnknownI2NPMessage(_context, utype);
umsg.readBytesIgnoreChecksum(data, curIndex);
_msg = umsg;
}
public int getType() { return MESSAGE_TYPE; }

View File

@@ -12,6 +12,8 @@ import java.io.IOException;
import net.i2p.I2PAppContext;
import net.i2p.data.DataHelper;
import net.i2p.data.Hash;
import net.i2p.util.SimpleByteCache;
/**
* This is the same as DataMessage but with a variable message type.
@@ -23,11 +25,13 @@ import net.i2p.data.DataHelper;
* There is no setData() method, the only way to create one of these is to
* read it with readMessage() (i.e., it came from some other router)
*
* @since 0.7.12
* @since 0.7.12 but broken before 0.8.12
*/
public class UnknownI2NPMessage extends I2NPMessageImpl {
private byte _data[];
private int _type;
private final int _type;
// we assume CHECKSUM_LENGTH = 1
private byte _checksum;
/** @param type 0-255 */
public UnknownI2NPMessage(I2PAppContext context, int type) {
@@ -35,41 +39,25 @@ public class UnknownI2NPMessage extends I2NPMessageImpl {
_type = type;
}
/** warning - only public for equals() */
public byte[] getData() {
return _data;
}
public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException {
if (type != _type) throw new I2NPMessageException("Message type is incorrect for this message");
int curIndex = offset;
long size = DataHelper.fromLong(data, curIndex, 4);
curIndex += 4;
if (size > MAX_SIZE)
throw new I2NPMessageException("wtf, size=" + size);
_data = new byte[(int)size];
System.arraycopy(data, curIndex, _data, 0, (int)size);
if (dataSize > MAX_SIZE)
throw new I2NPMessageException("wtf, size=" + dataSize);
_data = new byte[dataSize];
System.arraycopy(data, offset, _data, 0, dataSize);
}
/** calculate the message body's length (not including the header and footer */
protected int calculateWrittenLength() {
if (_data == null)
return 4;
return 0;
else
return 4 + _data.length;
return _data.length;
}
/** write the message body to the output array, starting at the given index */
protected int writeMessageBody(byte out[], int curIndex) {
if (_data == null) {
out[curIndex++] = 0x0;
out[curIndex++] = 0x0;
out[curIndex++] = 0x0;
out[curIndex++] = 0x0;
} else {
byte len[] = DataHelper.toLong(4, _data.length);
System.arraycopy(len, 0, out, curIndex, 4);
curIndex += 4;
if (_data != null) {
System.arraycopy(_data, 0, out, curIndex, _data.length);
curIndex += _data.length;
}
@@ -79,16 +67,88 @@ public class UnknownI2NPMessage extends I2NPMessageImpl {
/** @return 0-255 */
public int getType() { return _type; }
/**
* Read the full message including the header.
* This is the same as I2NPMessageImpl.readBytes(), except
* start after the type field, and
* do NOT verify the checksum, but simply save it for later
* so it can be verified in convert() if required.
*
*<pre>
* Standard message format AFTER the type field
* 4 byte ID
* 8 byte expiration
* 2 byte size
* 1 byte checksum (saved in case we need to check later)
* size bytes of payload, read by readMessage()
*</pre>
*
* @param offset starting at the ID (must skip the type)
* @return total length of the message
* @since 0.8.12
*/
public void readBytesIgnoreChecksum(byte data[], int offset) throws I2NPMessageException, IOException {
int cur = offset;
setUniqueId(DataHelper.fromLong(data, cur, 4));
cur += 4;
setMessageExpiration(DataHelper.fromLong(data, cur, DataHelper.DATE_LENGTH));
cur += DataHelper.DATE_LENGTH;
int size = (int)DataHelper.fromLong(data, cur, 2);
cur += 2;
_checksum = data[cur];
cur++;
if (cur + size > data.length)
throw new I2NPMessageException("Payload is too short ["
+ "data.len=" + data.length
+ " offset=" + offset
+ " cur=" + cur
+ " wanted=" + size + ']');
readMessage(data, cur, size, _type);
}
/**
* Attempt to convert this message to a known message class.
* Must have been created with readBytesIgnoreChecksum previously,
* as this does the delayed verification using the saved checksum.
*
* Used by TunnelGatewayZeroHop.
*
* @throws I2NPMessageException if the conversion fails
* @since 0.8.12
*/
public I2NPMessage convert() throws I2NPMessageException {
I2NPMessage msg = I2NPMessageImpl.createMessage(_context, _type);
if (msg instanceof UnknownI2NPMessage)
throw new I2NPMessageException("Unable to convert unknown type " + _type);
byte[] calc = SimpleByteCache.acquire(Hash.HASH_LENGTH);
_context.sha().calculateHash(_data, 0, _data.length, calc, 0);
boolean eq = _checksum == calc[0];
SimpleByteCache.release(calc);
if (!eq)
throw new I2NPMessageException("Bad checksum on " + _data.length + " byte msg type " + _type);
try {
msg.readMessage(_data, 0, _data.length, _type);
} catch (IOException ioe) {
throw new I2NPMessageException("Unable to convert type " + _type, ioe);
}
msg.setUniqueId(getUniqueId());
msg.setMessageExpiration(getMessageExpiration());
return msg;
}
@Override
public int hashCode() {
return _type + DataHelper.hashCode(getData());
return _type + DataHelper.hashCode(_data);
}
@Override
public boolean equals(Object object) {
if ( (object != null) && (object instanceof UnknownI2NPMessage) ) {
UnknownI2NPMessage msg = (UnknownI2NPMessage)object;
return _type == msg.getType() && DataHelper.eq(getData(), msg.getData());
return _type == msg.getType() && DataHelper.eq(_data, msg._data);
} else {
return false;
}
@@ -99,7 +159,7 @@ public class UnknownI2NPMessage extends I2NPMessageImpl {
StringBuilder buf = new StringBuilder();
buf.append("[UnknownI2NPMessage: ");
buf.append("\n\tType: ").append(_type);
buf.append("\n\tLength: ").append(calculateWrittenLength() - 4);
buf.append("\n\tLength: ").append(calculateWrittenLength());
buf.append("]");
return buf.toString();
}

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Monotone";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 17;
public final static long BUILD = 18;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -477,6 +477,13 @@ class FragmentHandler {
if (_log.shouldLog(Log.DEBUG))
_log.debug("RECV(" + data.length + "): "); // + Base64.encode(data)
//+ " " + _context.sha().calculateHash(data).toBase64());
// TODO read in as unknown message for outbound tunnels,
// since this will just be packaged in a TunnelGatewayMessage.
// Not a big savings since most everything is a GarlicMessage
// and so the readMessage() call is fast.
// The unencrypted messages at the OBEP are (V)TBMs
// and perhaps an occasional DatabaseLookupMessage
I2NPMessage m = new I2NPMessageHandler(_context).readMessage(data);
noteReception(m.getUniqueId(), fragmentCount-1, "complete: ");// + msg.toString());
noteCompletion(m.getUniqueId());

View File

@@ -61,6 +61,8 @@ class OutboundMessageDistributor {
if (_context.routerHash().equals(target.getIdentity().calculateHash())) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("queueing inbound message to ourselves: " + m);
// TODO if UnknownI2NPMessage, convert it.
// See FragmentHandler.receiveComplete()
_context.inNetMessagePool().add(m, null, null);
return;
} else {

View File

@@ -452,7 +452,7 @@ public class TunnelDispatcher implements Service {
+ " as the wrapper's expiration is in " + DataHelper.formatDuration(msg.getMessageExpiration()-before)
+ " and/or the content's expiration is in " + DataHelper.formatDuration(msg.getMessage().getMessageExpiration()-before)
+ " with messageId " + msg.getUniqueId() + "/" + msg.getMessage().getUniqueId() + " and message type "
+ msg.getMessage().getClass().getName());
+ msg.getMessage().getClass().getSimpleName());
return;
}
//_context.messageHistory().tunnelDispatched("message " + msg.getUniqueId() + "/" + msg.getMessage().getUniqueId() + " on tunnel "
@@ -471,7 +471,7 @@ public class TunnelDispatcher implements Service {
+ DataHelper.formatDuration(msg.getMessage().getMessageExpiration()-_context.clock().now())
+ " messageId " + msg.getUniqueId()
+ "/" + msg.getMessage().getUniqueId()
+ " messageType: " + msg.getMessage().getClass().getName()
+ " messageType: " + msg.getMessage().getClass().getSimpleName()
+ " existing = " + _inboundGateways.size(), new Exception("source"));
}

View File

@@ -3,7 +3,9 @@ package net.i2p.router.tunnel;
import net.i2p.data.Hash;
import net.i2p.data.TunnelId;
import net.i2p.data.i2np.I2NPMessage;
import net.i2p.data.i2np.I2NPMessageException;
import net.i2p.data.i2np.TunnelGatewayMessage;
import net.i2p.data.i2np.UnknownI2NPMessage;
import net.i2p.router.RouterContext;
import net.i2p.util.Log;
@@ -30,12 +32,29 @@ class TunnelGatewayZeroHop extends TunnelGateway {
/**
* Add a message to be sent down the tunnel, where we are the inbound gateway.
* This requires converting the message included in the TGM from an
* UnknownI2NPMessage to the correct message class.
* See TunnelGatewayMessage for details.
*
* @param msg message received to be sent through the tunnel
*/
@Override
public void add(TunnelGatewayMessage msg) {
add(msg.getMessage(), null, null);
I2NPMessage imsg = msg.getMessage();
if (_config.isInbound()) {
if (imsg instanceof UnknownI2NPMessage) {
// Do the delayed deserializing - convert to a standard message class
try {
UnknownI2NPMessage umsg = (UnknownI2NPMessage) imsg;
imsg = umsg.convert();
} catch (I2NPMessageException ime) {
if (_log.shouldLog(Log.WARN))
_log.warn("Unable to convert to std. msg. class at zero-hop IBGW", ime);
return;
}
}
}
add(imsg, null, null);
}
/**
@@ -50,7 +69,7 @@ class TunnelGatewayZeroHop extends TunnelGateway {
@Override
public void add(I2NPMessage msg, Hash toRouter, TunnelId toTunnel) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("zero hop gateway: distribute " + (_config.isInbound() ? "inbound " : " outbound ")
_log.debug("zero hop gateway: distribute " + (_config.isInbound() ? "inbound" : " outbound")
+ " to " + (toRouter != null ? toRouter.toBase64().substring(0,4) : "" )
+ "." + (toTunnel != null ? toTunnel.getTunnelId() + "" : "")
+ ": " + msg);