diff --git a/core/java/src/net/i2p/data/DataHelper.java b/core/java/src/net/i2p/data/DataHelper.java index 98414a4d23..22e18a8222 100644 --- a/core/java/src/net/i2p/data/DataHelper.java +++ b/core/java/src/net/i2p/data/DataHelper.java @@ -270,6 +270,22 @@ public class DataHelper { val[numBytes-i-1] = (byte)(value >>> (i*8)); return val; } + + public static long fromLong(byte src[], int offset, int numBytes) { + if ( (src == null) || (src.length == 0) ) + return 0; + + long rv = 0; + for (int i = 0; i < numBytes; i++) { + long cur = src[offset+i] & 0xFF; + if (cur < 0) cur = cur+256; + cur = (cur << (8*(numBytes-i-1))); + rv += cur; + } + if (rv < 0) + throw new IllegalArgumentException("wtf, fromLong got a negative? " + rv + ": offset="+ offset +" numBytes="+numBytes); + return rv; + } public static void main(String args[]) { for (int i = 0; i <= 0xFF; i++) @@ -296,6 +312,10 @@ public class DataHelper { byte extract[] = toLong(numBytes, value); if (!eq(written, extract)) throw new RuntimeException("testLong("+numBytes+","+value+") FAILED"); + + long read = fromLong(extract, 0, extract.length); + if (read != value) + throw new RuntimeException("testLong("+numBytes+","+value+") FAILED on read (" + read + ")"); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } @@ -336,6 +356,13 @@ public class DataHelper { else return toLong(DATE_LENGTH, date.getTime()); } + public static Date fromDate(byte src[], int offset) throws IllegalArgumentException { + long when = fromLong(src, offset, DATE_LENGTH); + if (when <= 0) + return null; + else + return new Date(when); + } public static final int DATE_LENGTH = 8; @@ -671,9 +698,12 @@ public class DataHelper { /** decompress the GZIP compressed data (returning null on error) */ public static byte[] decompress(byte orig[]) throws IOException { + return decompress(orig, 0, orig.length); + } + public static byte[] decompress(byte orig[], int offset, int length) throws IOException { if ((orig == null) || (orig.length <= 0)) return orig; - GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(orig), orig.length); - ByteArrayOutputStream baos = new ByteArrayOutputStream(orig.length * 2); + GZIPInputStream in = new GZIPInputStream(new ByteArrayInputStream(orig, offset, length), length); + ByteArrayOutputStream baos = new ByteArrayOutputStream(length * 2); byte buf[] = new byte[4 * 1024]; while (true) { int read = in.read(buf); diff --git a/core/java/src/net/i2p/data/Signature.java b/core/java/src/net/i2p/data/Signature.java index b0a2a95238..39e2c4dcc5 100644 --- a/core/java/src/net/i2p/data/Signature.java +++ b/core/java/src/net/i2p/data/Signature.java @@ -33,9 +33,8 @@ public class Signature extends DataStructureImpl { FAKE_SIGNATURE[i] = 0x00; } - public Signature() { - setData(null); - } + public Signature() { this(null); } + public Signature(byte data[]) { setData(data); } public byte[] getData() { return _data; diff --git a/core/java/src/net/i2p/data/SigningPrivateKey.java b/core/java/src/net/i2p/data/SigningPrivateKey.java index 8e58f146df..ccd7f946f8 100644 --- a/core/java/src/net/i2p/data/SigningPrivateKey.java +++ b/core/java/src/net/i2p/data/SigningPrivateKey.java @@ -29,9 +29,8 @@ public class SigningPrivateKey extends DataStructureImpl { public final static int KEYSIZE_BYTES = 20; - public SigningPrivateKey() { - setData(null); - } + public SigningPrivateKey() { this(null); } + public SigningPrivateKey(byte data[]) { setData(data); } public byte[] getData() { return _data; diff --git a/core/java/src/net/i2p/data/SigningPublicKey.java b/core/java/src/net/i2p/data/SigningPublicKey.java index 2af8e5a474..9e6c78c1a3 100644 --- a/core/java/src/net/i2p/data/SigningPublicKey.java +++ b/core/java/src/net/i2p/data/SigningPublicKey.java @@ -29,9 +29,8 @@ public class SigningPublicKey extends DataStructureImpl { public final static int KEYSIZE_BYTES = 128; - public SigningPublicKey() { - setData(null); - } + public SigningPublicKey() { this(null); } + public SigningPublicKey(byte data[]) { setData(data); } public byte[] getData() { return _data; diff --git a/core/java/src/net/i2p/data/TunnelId.java b/core/java/src/net/i2p/data/TunnelId.java index 973e69eb5d..133069360a 100644 --- a/core/java/src/net/i2p/data/TunnelId.java +++ b/core/java/src/net/i2p/data/TunnelId.java @@ -35,12 +35,25 @@ public class TunnelId extends DataStructureImpl { public final static int TYPE_PARTICIPANT = 3; public TunnelId() { - setTunnelId(-1); - setType(TYPE_UNSPECIFIED); + _tunnelId = -1; + _type = TYPE_UNSPECIFIED; + } + public TunnelId(long id) { + if (id <= 0) throw new IllegalArgumentException("wtf, tunnelId " + id); + _tunnelId = id; + _type = TYPE_UNSPECIFIED; + } + public TunnelId(long id, int type) { + if (id <= 0) throw new IllegalArgumentException("wtf, tunnelId " + id); + _tunnelId = id; + _type = type; } public long getTunnelId() { return _tunnelId; } - public void setTunnelId(long id) { _tunnelId = id; } + public void setTunnelId(long id) { + _tunnelId = id; + if (id <= 0) throw new IllegalArgumentException("wtf, tunnelId " + id); + } /** * is this tunnel inbound, outbound, or a participant (kept in memory only and used only for the router).s diff --git a/history.txt b/history.txt index c5d894765d..6b313ba17a 100644 --- a/history.txt +++ b/history.txt @@ -1,4 +1,11 @@ -$Id: history.txt,v 1.37 2004/10/06 16:03:52 jrandom Exp $ +$Id: history.txt,v 1.38 2004/10/07 14:19:52 jrandom Exp $ + +2004-10-07 jrandom + * Reimplement the I2NP reading with less temporary memory allocation. + There is still significant GC churn, especially under load, but this + should help. + * Catch some oddball errors in the transport (message timeout while + establishing). 2004-10-07 jrandom * Expire queued messages even when the writer is blocked. diff --git a/router/java/src/net/i2p/data/i2np/DataMessage.java b/router/java/src/net/i2p/data/i2np/DataMessage.java index 99a9d45e7f..cc98392dab 100644 --- a/router/java/src/net/i2p/data/i2np/DataMessage.java +++ b/router/java/src/net/i2p/data/i2np/DataMessage.java @@ -39,19 +39,15 @@ public class DataMessage extends I2NPMessageImpl { public int getSize() { return _data.length; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - int size = (int)DataHelper.readLong(in, 4); - if ( (size <= 0) || (size > MAX_SIZE) ) - throw new I2NPMessageException("wtf, size out of range? " + size); - _data = new byte[size]; - int read = read(in, _data); - if (read != size) - throw new DataFormatException("Not enough bytes to read (read = " + read + ", expected = " + size + ")"); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); - } + int curIndex = offset; + long size = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + if (size > 64*1024) + throw new I2NPMessageException("wtf, size=" + size); + _data = new byte[(int)size]; + System.arraycopy(data, curIndex, _data, 0, (int)size); } /** calculate the message body's length (not including the header and footer */ diff --git a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java index f1e1805c9d..581d790474 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseLookupMessage.java @@ -124,35 +124,53 @@ public class DatabaseLookupMessage extends I2NPMessageImpl { _dontIncludePeers = null; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _key = new Hash(); - _key.readBytes(in); - _fromHash = new Hash(); - _fromHash.readBytes(in); - Boolean val = DataHelper.readBoolean(in); - if (val == null) + int curIndex = offset; + + byte keyData[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _key = new Hash(keyData); + + byte fromData[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, fromData, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _fromHash = new Hash(fromData); + + boolean tunnelSpecified = false; + switch (data[curIndex]) { + case DataHelper.BOOLEAN_TRUE: + tunnelSpecified = true; + break; + case DataHelper.BOOLEAN_FALSE: + tunnelSpecified = false; + break; + default: throw new I2NPMessageException("Tunnel must be explicitly specified (or not)"); - boolean tunnelSpecified = val.booleanValue(); - if (tunnelSpecified) { - _replyTunnel = new TunnelId(); - _replyTunnel.readBytes(in); - } - int numPeers = (int)DataHelper.readLong(in, 2); - if ( (numPeers < 0) || (numPeers >= (1<<16) ) ) - throw new DataFormatException("Invalid number of peers - " + numPeers); - Set peers = new HashSet(numPeers); - for (int i = 0; i < numPeers; i++) { - Hash peer = new Hash(); - peer.readBytes(in); - peers.add(peer); - } - _dontIncludePeers = peers; - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); } + curIndex++; + + if (tunnelSpecified) { + _replyTunnel = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + curIndex += 4; + } + + int numPeers = (int)DataHelper.fromLong(data, curIndex, 2); + curIndex += 2; + + if ( (numPeers < 0) || (numPeers >= (1<<16) ) ) + throw new I2NPMessageException("Invalid number of peers - " + numPeers); + Set peers = new HashSet(numPeers); + for (int i = 0; i < numPeers; i++) { + byte peer[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + peers.add(new Hash(peer)); + } + _dontIncludePeers = peers; } + protected int calculateWrittenLength() { int totalLength = 0; diff --git a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java index c842c8f5dc..a3c976545f 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseSearchReplyMessage.java @@ -57,27 +57,32 @@ public class DatabaseSearchReplyMessage extends I2NPMessageImpl { public Hash getFromHash() { return _from; } public void setFromHash(Hash from) { _from = from; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _key = new Hash(); - _key.readBytes(in); - - int num = (int)DataHelper.readLong(in, 1); - _peerHashes.clear(); - for (int i = 0; i < num; i++) { - Hash peer = new Hash(); - peer.readBytes(in); - addReply(peer); - } - - _from = new Hash(); - _from.readBytes(in); - - _context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); + int curIndex = offset; + + byte keyData[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _key = new Hash(keyData); + + int num = (int)DataHelper.fromLong(data, curIndex, 1); + curIndex++; + + _peerHashes.clear(); + for (int i = 0; i < num; i++) { + byte peer[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + addReply(new Hash(peer)); } + + byte from[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, from, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _from = new Hash(from); + + _context.statManager().addRateData("netDb.searchReplyMessageReceive", num*32 + 64, 1); } /** calculate the message body's length (not including the header and footer */ diff --git a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java index 5398447c85..9a18ee1ac2 100644 --- a/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java +++ b/router/java/src/net/i2p/data/i2np/DatabaseStoreMessage.java @@ -119,45 +119,58 @@ public class DatabaseStoreMessage extends I2NPMessageImpl { public Hash getReplyGateway() { return _replyGateway; } public void setReplyGateway(Hash peer) { _replyGateway = peer; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _key = new Hash(); - _key.readBytes(in); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Hash read: " + _key.toBase64()); - _type = (int)DataHelper.readLong(in, 1); - _replyToken = DataHelper.readLong(in, 4); - if (_replyToken > 0) { - _replyTunnel = new TunnelId(); - _replyTunnel.readBytes(in); - _replyGateway = new Hash(); - _replyGateway.readBytes(in); - } else { - _replyTunnel = null; - _replyGateway = null; + int curIndex = offset; + + byte keyData[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, keyData, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _key = new Hash(keyData); + + _type = (int)DataHelper.fromLong(data, curIndex, 1); + curIndex++; + + _replyToken = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + + if (_replyToken > 0) { + _replyTunnel = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + curIndex += 4; + + byte gw[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, gw, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _replyGateway = new Hash(gw); + } else { + _replyTunnel = null; + _replyGateway = null; + } + + if (_type == KEY_TYPE_LEASESET) { + _leaseSet = new LeaseSet(); + try { + _leaseSet.readBytes(new ByteArrayInputStream(data, curIndex, data.length-curIndex)); + } catch (DataFormatException dfe) { + throw new I2NPMessageException("Error reading the leaseSet", dfe); } - if (_type == KEY_TYPE_LEASESET) { - _leaseSet = new LeaseSet(); - _leaseSet.readBytes(in); - } else if (_type == KEY_TYPE_ROUTERINFO) { - _info = new RouterInfo(); - int compressedSize = (int)DataHelper.readLong(in, 2); - byte compressed[] = new byte[compressedSize]; - int read = DataHelper.read(in, compressed); - if (read != compressedSize) - throw new I2NPMessageException("Invalid compressed data size (expected " - + compressedSize + " read " + read + ")"); - ByteArrayInputStream bais = new ByteArrayInputStream(DataHelper.decompress(compressed)); - _info.readBytes(bais); - } else { - throw new I2NPMessageException("Invalid type of key read from the structure - " + _type); + } else if (_type == KEY_TYPE_ROUTERINFO) { + _info = new RouterInfo(); + int compressedSize = (int)DataHelper.fromLong(data, curIndex, 2); + curIndex += 2; + + byte decompressed[] = DataHelper.decompress(data, curIndex, compressedSize); + try { + _info.readBytes(new ByteArrayInputStream(decompressed)); + } catch (DataFormatException dfe) { + throw new I2NPMessageException("Error reading the routerInfo", dfe); } - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); + } else { + throw new I2NPMessageException("Invalid type of key read from the structure - " + _type); } } + /** calculate the message body's length (not including the header and footer */ protected int calculateWrittenLength() { int len = Hash.HASH_LENGTH + 1 + 4; // key+type+replyToken diff --git a/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java b/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java index 4626e449b8..e4cf814a00 100644 --- a/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java +++ b/router/java/src/net/i2p/data/i2np/DeliveryStatusMessage.java @@ -42,14 +42,13 @@ public class DeliveryStatusMessage extends I2NPMessageImpl { public Date getArrival() { return _arrival; } public void setArrival(Date arrival) { _arrival = arrival; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _id = DataHelper.readLong(in, 4); - _arrival = DataHelper.readDate(in); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); - } + int curIndex = offset; + + _id = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + _arrival = DataHelper.fromDate(data, curIndex); } /** calculate the message body's length (not including the header and footer */ diff --git a/router/java/src/net/i2p/data/i2np/GarlicMessage.java b/router/java/src/net/i2p/data/i2np/GarlicMessage.java index 537bf24fd8..36f1e0e09b 100644 --- a/router/java/src/net/i2p/data/i2np/GarlicMessage.java +++ b/router/java/src/net/i2p/data/i2np/GarlicMessage.java @@ -35,17 +35,15 @@ public class GarlicMessage extends I2NPMessageImpl { public byte[] getData() { return _data; } public void setData(byte[] data) { _data = data; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - long len = DataHelper.readLong(in, 4); - _data = new byte[(int)len]; - int read = read(in, _data); - if (read != len) - throw new I2NPMessageException("Incorrect size read [" + read + " read, expected " + len + "]"); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); - } + int curIndex = offset; + + long len = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + if ( (len <= 0) || (len > 64*1024) ) throw new I2NPMessageException("size="+len); + _data = new byte[(int)len]; + System.arraycopy(data, curIndex, _data, 0, (int)len); } /** calculate the message body's length (not including the header and footer */ diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessage.java b/router/java/src/net/i2p/data/i2np/I2NPMessage.java index a581ac9552..94933ad9a4 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessage.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessage.java @@ -28,11 +28,27 @@ public interface I2NPMessage extends DataStructure { * * @param in stream to read from * @param type I2NP message type + * @param buffer scratch buffer to be used when reading and parsing * @throws I2NPMessageException if the stream doesn't contain a valid message * that this class can read. * @throws IOException if there is a problem reading from the stream */ - public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException; + public void readBytes(InputStream in, int type, byte buffer[]) throws I2NPMessageException, IOException; + + /** + * Read the body into the data structures, after the initial type byte and + * the uniqueId / expiration, using the current class's format as defined by + * the I2NP specification + * + * @param data data to read from + * @param offset where to start in the data array + * @param dataSize how long into the data to read + * @param type I2NP message type + * @throws I2NPMessageException if the stream doesn't contain a valid message + * that this class can read. + * @throws IOException if there is a problem reading from the stream + */ + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException; /** * Return the unique identifier for this type of I2NP message, as defined in diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java index 00bc007a4e..176721be81 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageHandler.java @@ -26,9 +26,11 @@ public class I2NPMessageHandler { private I2PAppContext _context; private long _lastReadBegin; private long _lastReadEnd; + private byte _messageBuffer[]; public I2NPMessageHandler(I2PAppContext context) { _context = context; _log = context.logManager().getLog(I2NPMessageHandler.class); + _messageBuffer = null; } /** @@ -39,12 +41,15 @@ public class I2NPMessageHandler { * 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(in, type); + I2NPMessage msg = createMessage(type); + if (msg == null) + throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message"); try { - msg.readBytes(in, type); + msg.readBytes(in, type, _messageBuffer); } catch (IOException ioe) { throw ioe; } catch (I2NPMessageException ime) { @@ -61,14 +66,13 @@ public class I2NPMessageHandler { throw new I2NPMessageException("Error reading the message", dfe); } } - public long getLastReadTime() { return _lastReadEnd - _lastReadBegin; } /** * Yes, this is fairly ugly, but its the only place it ever happens. * */ - private I2NPMessage createMessage(InputStream in, int type) throws IOException, I2NPMessageException { + private I2NPMessage createMessage(int type) throws I2NPMessageException { switch (type) { case DatabaseStoreMessage.MESSAGE_TYPE: return new DatabaseStoreMessage(_context); @@ -89,7 +93,7 @@ public class I2NPMessageHandler { case TunnelCreateStatusMessage.MESSAGE_TYPE: return new TunnelCreateStatusMessage(_context); default: - throw new I2NPMessageException("The type "+ type + " is an unknown I2NP message"); + return null; } } diff --git a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java index 9c182ea1b1..2e8979468a 100644 --- a/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java +++ b/router/java/src/net/i2p/data/i2np/I2NPMessageImpl.java @@ -44,29 +44,15 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM _context.statManager().createRateStat("i2np.readTime", "How long it takes to read an I2NP message", "I2NP", new long[] { 10*60*1000, 60*60*1000 }); } - /** - * Read the body into the data structures, after the initial type byte and - * the uniqueId / expiration, using the current class's format as defined by - * the I2NP specification - * - * @param in stream to read from - * @param type I2NP message type - * @throws I2NPMessageException if the stream doesn't contain a valid message - * that this class can read. - * @throws IOException if there is a problem reading from the stream - */ - protected abstract void readMessage(InputStream in, int type) throws I2NPMessageException, IOException; - public void readBytes(InputStream in) throws DataFormatException, IOException { try { - readBytes(in, -1); + readBytes(in, -1, new byte[1024]); } catch (I2NPMessageException ime) { throw new DataFormatException("Bad bytes", ime); } } - public void readBytes(InputStream in, int type) throws I2NPMessageException, IOException { + public void readBytes(InputStream in, int type, byte buffer[]) throws I2NPMessageException, IOException { try { - long start = _context.clock().now(); if (type < 0) type = (int)DataHelper.readLong(in, 1); _uniqueId = DataHelper.readLong(in, 4); @@ -74,17 +60,28 @@ public abstract class I2NPMessageImpl extends DataStructureImpl implements I2NPM int size = (int)DataHelper.readLong(in, 2); Hash h = new Hash(); h.readBytes(in); - byte data[] = new byte[size]; - int read = DataHelper.read(in, data); - if (read != size) - throw new I2NPMessageException("Payload is too short [" + read + ", wanted " + size + "]"); - Hash calc = _context.sha().calculateHash(data); + if (buffer.length < size) { + if (size > 64*1024) throw new I2NPMessageException("size=" + size); + buffer = new byte[size]; + } + + int cur = 0; + while (cur < size) { + int numRead = in.read(buffer, cur, size- cur); + if (numRead == -1) { + throw new I2NPMessageException("Payload is too short [" + numRead + ", wanted " + size + "]"); + } + cur += numRead; + } + + Hash calc = _context.sha().calculateHash(buffer, 0, size); if (!calc.equals(h)) throw new I2NPMessageException("Hash does not match"); + long start = _context.clock().now(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Reading bytes: type = " + type + " / uniqueId : " + _uniqueId + " / expiration : " + _expiration); - readMessage(new ByteArrayInputStream(data), type); + readMessage(buffer, 0, size, type); long time = _context.clock().now() - start; if (time > 50) _context.statManager().addRateData("i2np.readTime", time, time); diff --git a/router/java/src/net/i2p/data/i2np/TunnelConfigurationSessionKey.java b/router/java/src/net/i2p/data/i2np/TunnelConfigurationSessionKey.java index 9384033fcd..86aa793284 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelConfigurationSessionKey.java +++ b/router/java/src/net/i2p/data/i2np/TunnelConfigurationSessionKey.java @@ -28,7 +28,8 @@ public class TunnelConfigurationSessionKey extends DataStructureImpl { private final static Log _log = new Log(TunnelConfigurationSessionKey.class); private SessionKey _key; - public TunnelConfigurationSessionKey() { setKey(null); } + public TunnelConfigurationSessionKey() { this(null); } + public TunnelConfigurationSessionKey(SessionKey key) { setKey(key); } public SessionKey getKey() { return _key; } public void setKey(SessionKey key) { _key= key; } diff --git a/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java b/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java index f9afb5969d..d7df15a372 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelCreateMessage.java @@ -128,55 +128,102 @@ public class TunnelCreateMessage extends I2NPMessageImpl { public void setReplyPeer(Hash peer) { _replyPeer = peer; } public Hash getReplyPeer() { return _replyPeer; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _participantType = (int)DataHelper.readLong(in, 1); - if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { - _nextRouter = new Hash(); - _nextRouter.readBytes(in); - _nextTunnelId = new TunnelId(); - _nextTunnelId.readBytes(in); - } - _tunnelId = new TunnelId(); - _tunnelId.readBytes(in); - _tunnelDuration = DataHelper.readLong(in, 4); - _configKey = new TunnelConfigurationSessionKey(); - _configKey.readBytes(in); - _maxPeakMessagesPerMin = DataHelper.readLong(in, 4); - _maxAvgMessagesPerMin = DataHelper.readLong(in, 4); - _maxPeakBytesPerMin = DataHelper.readLong(in, 4); - _maxAvgBytesPerMin = DataHelper.readLong(in, 4); + int curIndex = offset; + + _participantType = (int)DataHelper.fromLong(data, curIndex, 1); + curIndex++; + if (_participantType != PARTICIPANT_TYPE_ENDPOINT) { + byte peer[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _nextRouter = new Hash(peer); - int flags = (int)DataHelper.readLong(in, 1); - _includeDummyTraffic = flagsIncludeDummy(flags); - _reorderMessages = flagsReorder(flags); - - _verificationPubKey = new TunnelSigningPublicKey(); - _verificationPubKey.readBytes(in); - if (_participantType == PARTICIPANT_TYPE_GATEWAY) { - _verificationPrivKey = new TunnelSigningPrivateKey(); - _verificationPrivKey.readBytes(in); - } - if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { - _tunnelKey = new TunnelSessionKey(); - _tunnelKey.readBytes(in); - } - _certificate = new Certificate(); - _certificate.readBytes(in); - _replyTag = new SessionTag(); - _replyTag.readBytes(in); - _replyKey = new SessionKey(); - _replyKey.readBytes(in); - _replyTunnel = new TunnelId(); - _replyTunnel.readBytes(in); - _replyPeer = new Hash(); - _replyPeer.readBytes(in); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); + _nextTunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + curIndex += 4; } + + _tunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + curIndex += 4; + if (_tunnelId.getTunnelId() <= 0) + throw new I2NPMessageException("wtf, tunnelId == " + _tunnelId); + + _tunnelDuration = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + + byte key[] = new byte[SessionKey.KEYSIZE_BYTES]; + System.arraycopy(data, curIndex, key, 0, SessionKey.KEYSIZE_BYTES); + curIndex += SessionKey.KEYSIZE_BYTES; + _configKey = new TunnelConfigurationSessionKey(new SessionKey(key)); + + _maxPeakMessagesPerMin = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + _maxAvgMessagesPerMin = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + _maxPeakBytesPerMin = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + _maxAvgBytesPerMin = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + + int flags = (int)DataHelper.fromLong(data, curIndex, 1); + curIndex++; + _includeDummyTraffic = flagsIncludeDummy(flags); + _reorderMessages = flagsReorder(flags); + + key = new byte[SigningPublicKey.KEYSIZE_BYTES]; + System.arraycopy(data, curIndex, key, 0, SigningPublicKey.KEYSIZE_BYTES); + curIndex += SigningPublicKey.KEYSIZE_BYTES; + _verificationPubKey = new TunnelSigningPublicKey(new SigningPublicKey(key)); + + if (_participantType == PARTICIPANT_TYPE_GATEWAY) { + key = new byte[SigningPrivateKey.KEYSIZE_BYTES]; + System.arraycopy(data, curIndex, key, 0, SigningPrivateKey.KEYSIZE_BYTES); + curIndex += SigningPrivateKey.KEYSIZE_BYTES; + _verificationPrivKey = new TunnelSigningPrivateKey(new SigningPrivateKey(key)); + } + + if ( (_participantType == PARTICIPANT_TYPE_ENDPOINT) || (_participantType == PARTICIPANT_TYPE_GATEWAY) ) { + key = new byte[SessionKey.KEYSIZE_BYTES]; + System.arraycopy(data, curIndex, key, 0, SessionKey.KEYSIZE_BYTES); + curIndex += SessionKey.KEYSIZE_BYTES; + _tunnelKey = new TunnelSessionKey(new SessionKey(key)); + } + + int certType = (int) DataHelper.fromLong(data, curIndex, 1); + curIndex++; + int certLength = (int) DataHelper.fromLong(data, curIndex, 2); + curIndex += 2; + if (certLength <= 0) { + _certificate = new Certificate(certType, null); + } else { + if (certLength > 16*1024) throw new I2NPMessageException("cert size " + certLength); + byte certPayload[] = new byte[certLength]; + System.arraycopy(data, curIndex, certPayload, 0, certLength); + curIndex += certLength; + _certificate = new Certificate(certType, certPayload); + } + + byte tag[] = new byte[SessionTag.BYTE_LENGTH]; + System.arraycopy(data, curIndex, tag, 0, SessionTag.BYTE_LENGTH); + curIndex += SessionTag.BYTE_LENGTH; + _replyTag = new SessionTag(tag); + + key = new byte[SessionKey.KEYSIZE_BYTES]; + System.arraycopy(data, curIndex, key, 0, SessionKey.KEYSIZE_BYTES); + curIndex += SessionKey.KEYSIZE_BYTES; + _replyKey = new SessionKey(key); + + _replyTunnel = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + curIndex += 4; + + byte peer[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _replyPeer = new Hash(peer); } + /** calculate the message body's length (not including the header and footer */ protected int calculateWrittenLength() { int length = 0; diff --git a/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java b/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java index 323b101946..8dd7870d4c 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelCreateStatusMessage.java @@ -46,7 +46,11 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl { } public TunnelId getTunnelId() { return _tunnelId; } - public void setTunnelId(TunnelId id) { _tunnelId = id; } + public void setTunnelId(TunnelId id) { + _tunnelId = id; + if ( (id != null) && (id.getTunnelId() <= 0) ) + throw new IllegalArgumentException("wtf, tunnelId " + id); + } public int getStatus() { return _status; } public void setStatus(int status) { _status = status; } @@ -57,19 +61,25 @@ public class TunnelCreateStatusMessage extends I2NPMessageImpl { public Hash getFromHash() { return _from; } public void setFromHash(Hash from) { _from = from; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _tunnelId = new TunnelId(); - _tunnelId.readBytes(in); - _status = (int)DataHelper.readLong(in, 1); - _from = new Hash(); - _from.readBytes(in); - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); - } + int curIndex = offset; + + _tunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + curIndex += 4; + + if (_tunnelId.getTunnelId() <= 0) + throw new I2NPMessageException("wtf, negative tunnelId? " + _tunnelId); + + _status = (int)DataHelper.fromLong(data, curIndex, 1); + curIndex++; + byte peer[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, peer, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + _from = new Hash(peer); } + /** calculate the message body's length (not including the header and footer */ protected int calculateWrittenLength() { return 4 + 1 + Hash.HASH_LENGTH; // id + status + from @@ -77,6 +87,7 @@ public class TunnelCreateStatusMessage 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) || (_from == null) ) throw new I2NPMessageException("Not enough data to write out"); + if (_tunnelId.getTunnelId() < 0) throw new I2NPMessageException("Negative tunnelId!? " + _tunnelId); byte id[] = DataHelper.toLong(4, _tunnelId.getTunnelId()); System.arraycopy(id, 0, out, curIndex, 4); diff --git a/router/java/src/net/i2p/data/i2np/TunnelMessage.java b/router/java/src/net/i2p/data/i2np/TunnelMessage.java index 92c12d3530..af33d877df 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelMessage.java +++ b/router/java/src/net/i2p/data/i2np/TunnelMessage.java @@ -46,7 +46,9 @@ public class TunnelMessage extends I2NPMessageImpl { } public TunnelId getTunnelId() { return _tunnelId; } - public void setTunnelId(TunnelId id) { _tunnelId = id; } + public void setTunnelId(TunnelId id) { + _tunnelId = id; + } public byte[] getData() { return _data; } public void setData(byte data[]) { @@ -61,33 +63,42 @@ public class TunnelMessage extends I2NPMessageImpl { public byte[] getEncryptedDeliveryInstructions() { return _encryptedInstructions; } public void setEncryptedDeliveryInstructions(byte instructions[]) { _encryptedInstructions = instructions; } - public void readMessage(InputStream in, int type) throws I2NPMessageException, IOException { + public void readMessage(byte data[], int offset, int dataSize, int type) throws I2NPMessageException, IOException { if (type != MESSAGE_TYPE) throw new I2NPMessageException("Message type is incorrect for this message"); - try { - _tunnelId = new TunnelId(); - _tunnelId.readBytes(in); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Read tunnel message for tunnel " + _tunnelId); - _size = DataHelper.readLong(in, 4); - if (_log.shouldLog(Log.DEBUG)) - _log.debug("Read tunnel message size: " + _size); - if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size); - _data = new byte[(int)_size]; - int read = read(in, _data); - if (read != _size) - throw new I2NPMessageException("Incorrect number of bytes read (" + read + ", expected " + _size); - int includeVerification = (int)DataHelper.readLong(in, 1); - if (includeVerification == FLAG_INCLUDESTRUCTURE) { - _verification = new TunnelVerificationStructure(); - _verification.readBytes(in); - int len = (int)DataHelper.readLong(in, 2); - _encryptedInstructions = new byte[len]; - read = read(in, _encryptedInstructions); - if (read != len) - throw new I2NPMessageException("Incorrect number of bytes read for instructions (" + read + ", expected " + len + ")"); - } - } catch (DataFormatException dfe) { - throw new I2NPMessageException("Unable to load the message data", dfe); + int curIndex = offset; + + _tunnelId = new TunnelId(DataHelper.fromLong(data, curIndex, 4)); + curIndex += 4; + + if (_tunnelId.getTunnelId() <= 0) + throw new I2NPMessageException("Invalid tunnel Id " + _tunnelId); + + _size = DataHelper.fromLong(data, curIndex, 4); + curIndex += 4; + + if (_size < 0) throw new I2NPMessageException("Invalid size in the structure: " + _size); + if (_size > 64*1024) throw new I2NPMessageException("Invalid size in the structure: " + _size); + _data = new byte[(int)_size]; + System.arraycopy(data, curIndex, _data, 0, (int)_size); + curIndex += _size; + + int includeVerification = (int)DataHelper.fromLong(data, curIndex, 1); + curIndex++; + if (includeVerification == FLAG_INCLUDESTRUCTURE) { + byte vHash[] = new byte[Hash.HASH_LENGTH]; + System.arraycopy(data, curIndex, vHash, 0, Hash.HASH_LENGTH); + curIndex += Hash.HASH_LENGTH; + byte vSig[] = new byte[Signature.SIGNATURE_BYTES]; + System.arraycopy(data, curIndex, vSig, 0, Signature.SIGNATURE_BYTES); + curIndex += Signature.SIGNATURE_BYTES; + _verification = new TunnelVerificationStructure(new Hash(vHash), new Signature(vSig)); + + int len = (int)DataHelper.fromLong(data, curIndex, 2); + curIndex += 2; + if ( (len <= 0) || (len > 4*1024) ) throw new I2NPMessageException("wtf, size of instructions: " + len); + _encryptedInstructions = new byte[len]; + System.arraycopy(data, curIndex, _encryptedInstructions, 0, len); + curIndex += len; } } diff --git a/router/java/src/net/i2p/data/i2np/TunnelSessionKey.java b/router/java/src/net/i2p/data/i2np/TunnelSessionKey.java index 310341ef8a..b73cbfa792 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelSessionKey.java +++ b/router/java/src/net/i2p/data/i2np/TunnelSessionKey.java @@ -28,7 +28,8 @@ public class TunnelSessionKey extends DataStructureImpl { private final static Log _log = new Log(TunnelSessionKey.class); private SessionKey _key; - public TunnelSessionKey() { setKey(null); } + public TunnelSessionKey() { this(null); } + public TunnelSessionKey(SessionKey key) { setKey(key); } public SessionKey getKey() { return _key; } public void setKey(SessionKey key) { _key= key; } diff --git a/router/java/src/net/i2p/data/i2np/TunnelSigningPrivateKey.java b/router/java/src/net/i2p/data/i2np/TunnelSigningPrivateKey.java index 5b95411e0d..ec1f887465 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelSigningPrivateKey.java +++ b/router/java/src/net/i2p/data/i2np/TunnelSigningPrivateKey.java @@ -29,7 +29,8 @@ public class TunnelSigningPrivateKey extends DataStructureImpl { private final static Log _log = new Log(EndPointPrivateKey.class); private SigningPrivateKey _key; - public TunnelSigningPrivateKey() { setKey(null); } + public TunnelSigningPrivateKey() { this(null); } + public TunnelSigningPrivateKey(SigningPrivateKey key) { setKey(key); } public SigningPrivateKey getKey() { return _key; } public void setKey(SigningPrivateKey key) { _key= key; } diff --git a/router/java/src/net/i2p/data/i2np/TunnelSigningPublicKey.java b/router/java/src/net/i2p/data/i2np/TunnelSigningPublicKey.java index d125e5620f..9ce7e79ade 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelSigningPublicKey.java +++ b/router/java/src/net/i2p/data/i2np/TunnelSigningPublicKey.java @@ -28,7 +28,8 @@ public class TunnelSigningPublicKey extends DataStructureImpl { private final static Log _log = new Log(TunnelSigningPublicKey.class); private SigningPublicKey _key; - public TunnelSigningPublicKey() { setKey(null); } + public TunnelSigningPublicKey() { this(null); } + public TunnelSigningPublicKey(SigningPublicKey key) { setKey(key); } public SigningPublicKey getKey() { return _key; } public void setKey(SigningPublicKey key) { _key= key; } diff --git a/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java b/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java index 2c076d0e2f..aec62c93eb 100644 --- a/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java +++ b/router/java/src/net/i2p/data/i2np/TunnelVerificationStructure.java @@ -29,9 +29,10 @@ public class TunnelVerificationStructure extends DataStructureImpl { private Hash _msgHash; private Signature _authSignature; - public TunnelVerificationStructure() { - setMessageHash(null); - setAuthorizationSignature(null); + public TunnelVerificationStructure() { this(null, null); } + public TunnelVerificationStructure(Hash messageHash, Signature authSig) { + setMessageHash(messageHash); + setAuthorizationSignature(authSig); } public Hash getMessageHash() { return _msgHash; } diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index 5027511d67..0ca2264f57 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -15,9 +15,9 @@ import net.i2p.CoreVersion; * */ public class RouterVersion { - public final static String ID = "$Revision: 1.45 $ $Date: 2004/10/06 16:03:52 $"; + public final static String ID = "$Revision: 1.46 $ $Date: 2004/10/07 14:19:52 $"; public final static String VERSION = "0.4.1.1"; - public final static long BUILD = 11; + public final static long BUILD = 12; public static void main(String args[]) { System.out.println("I2P Router version: " + VERSION); System.out.println("Router ID: " + RouterVersion.ID); diff --git a/router/java/src/net/i2p/router/message/GarlicMessageParser.java b/router/java/src/net/i2p/router/message/GarlicMessageParser.java index d4badfaecd..38ebf60d10 100644 --- a/router/java/src/net/i2p/router/message/GarlicMessageParser.java +++ b/router/java/src/net/i2p/router/message/GarlicMessageParser.java @@ -46,7 +46,8 @@ public class GarlicMessageParser { _log.warn("Error decrypting", dfe); } if (decrData == null) { - _log.debug("Decryption of garlic message failed"); + if (_log.shouldLog(Log.WARN)) + _log.warn("Decryption of garlic message failed (data = " + encData + ")", new Exception("Decrypt fail")); return null; } else { return readCloveSet(decrData); diff --git a/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java b/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java index d4f840e33c..4d2b4d207a 100644 --- a/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java +++ b/router/java/src/net/i2p/router/message/HandleTunnelMessageJob.java @@ -396,8 +396,8 @@ public class HandleTunnelMessageJob extends JobImpl { _log.error("Error parsing the message body", ime); } catch (IOException ioe) { if (_log.shouldLog(Log.ERROR)) - _log.error("Error reading the message body", ioe); - } + _log.error("Error parsing the message body", ioe); + } return null; } diff --git a/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java b/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java index b51e72ef9b..ab27eceecf 100644 --- a/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java +++ b/router/java/src/net/i2p/router/transport/tcp/ConnectionRunner.java @@ -68,6 +68,10 @@ class ConnectionRunner implements Runnable { buf = m.toByteArray(); written = buf.length; } + } catch (Exception e) { + _log.log(Log.CRIT, "getting the message data", e); + _con.closeConnection(); + return; } if (written <= 0) { if (_log.shouldLog(Log.WARN)) diff --git a/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java b/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java index da6ecd4a85..1494f73bca 100644 --- a/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java +++ b/router/java/src/net/i2p/router/transport/tcp/TCPTransport.java @@ -287,6 +287,7 @@ public class TCPTransport extends TransportImpl { con.setTransport(this); con.closeConnection(); } else { + con.setTransport(this); if (waitingMsgs != null) { for (int i = 0; i < waitingMsgs.size(); i++) { @@ -296,7 +297,6 @@ public class TCPTransport extends TransportImpl { _context.shitlist().unshitlistRouter(ident.calculateHash()); - con.setTransport(this); con.runConnection(); if (_log.shouldLog(Log.DEBUG)) _log.debug("Connection set to run");