diff --git a/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java b/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java index 0c5fe9359a..6bc349862b 100644 --- a/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java +++ b/router/java/src/net/i2p/router/transport/udp/InboundMessageState.java @@ -33,7 +33,8 @@ class InboundMessageState { private static final long MAX_RECEIVE_TIME = 10*1000; public static final int MAX_FRAGMENTS = 64; - private static final ByteCache _fragmentCache = ByteCache.getInstance(64, 2048); + private static final int MAX_FRAGMENT_SIZE = UDPPacket.MAX_PACKET_SIZE; + private static final ByteCache _fragmentCache = ByteCache.getInstance(64, MAX_FRAGMENT_SIZE); public InboundMessageState(RouterContext ctx, long messageId, Hash from) { _context = ctx; diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState.java b/router/java/src/net/i2p/router/transport/udp/PeerState.java index 438162e6d1..dbfa8263cf 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -157,7 +157,7 @@ class PeerState { /* how many consecutive packets at or under the min MTU have been received */ private long _consecutiveSmall; /** when did we last check the MTU? */ - private long _mtuLastChecked; + //private long _mtuLastChecked; private long _mtuIncreases; private long _mtuDecreases; /** current round trip time estimate */ @@ -224,7 +224,7 @@ class PeerState { * of 608 * * Well, we really need to count the acks as well, especially - * 4 * MAX_RESEND_ACKS which can take up a significant amount of space. + * 1 + (4 * MAX_RESEND_ACKS_SMALL) which can take up a significant amount of space. * We reduce the max acks when using the small MTU but it may not be enough... * */ @@ -234,6 +234,12 @@ class PeerState { * based on measurements, 1350 fits nearly all reasonably small I2NP messages * (larger I2NP messages may be up to 1900B-4500B, which isn't going to fit * into a live network MTU anyway) + * + * TODO + * VTBM is 2646, it would be nice to fit in two large + * 2646 / 2 = 1323 + * 1323 + 74 + 46 + 1 + (4 * 9) = 1480 + * So why not make it 1492 (old ethernet is 1492, new is 1500) */ private static final int LARGE_MTU = 1350; @@ -261,7 +267,7 @@ class PeerState { _remotePort = -1; _mtu = getDefaultMTU(); _mtuReceive = _mtu; - _mtuLastChecked = -1; + //_mtuLastChecked = -1; _lastACKSend = -1; _rto = MIN_RTO; _rtt = _rto/2; @@ -370,13 +376,20 @@ class PeerState { public long getTheyRelayToUsAs() { return _theyRelayToUsAs; } /** what is the largest packet we can send to the peer? */ public int getMTU() { return _mtu; } - /** estimate how large the other side is sending packets */ + + /** + * Estimate how large the other side's MTU is. + * This could be wrong. + * It is used only for the HTML status. + */ public int getReceiveMTU() { return _mtuReceive; } + /** when did we last check the MTU? */ + /**** public long getMTULastChecked() { return _mtuLastChecked; } public long getMTUIncreases() { return _mtuIncreases; } public long getMTUDecreases() { return _mtuDecreases; } - + ****/ /** * The peer are we talking to. This should be set as soon as this @@ -537,11 +550,15 @@ class PeerState { * we can use to publish that fact. */ public void setTheyRelayToUsAs(long tag) { _theyRelayToUsAs = tag; } + /** what is the largest packet we can send to the peer? */ + /**** public void setMTU(int mtu) { _mtu = mtu; _mtuLastChecked = _context.clock().now(); } + ****/ + public int getSlowStartThreshold() { return _slowStartThreshold; } public int getConcurrentSends() { return _concurrentMessagesActive; } public int getConcurrentSendWindow() { return _concurrentMessagesAllowed; } @@ -979,15 +996,21 @@ class PeerState { public long getPacketRetransmissionRate() { return _packetRetransmissionRate; } public long getPacketsReceived() { return _packetsReceived; } public long getPacketsReceivedDuplicate() { return _packetsReceivedDuplicate; } + + private static final int MTU_RCV_DISPLAY_THRESHOLD = 20; + public void packetReceived(int size) { _packetsReceived++; - if (size <= MIN_MTU) + if (size <= MIN_MTU) { _consecutiveSmall++; - else + } else { _consecutiveSmall = 0; + _mtuReceive = LARGE_MTU; + return; + } - if (_packetsReceived > 50) { - if (_consecutiveSmall < 50) + if (_packetsReceived > MTU_RCV_DISPLAY_THRESHOLD) { + if (_consecutiveSmall < MTU_RCV_DISPLAY_THRESHOLD) _mtuReceive = LARGE_MTU; else _mtuReceive = MIN_MTU; @@ -1287,7 +1310,11 @@ class PeerState { private static final int SSU_HEADER_SIZE = 46; static final int UDP_HEADER_SIZE = 8; static final int IP_HEADER_SIZE = 20; - /** how much payload data can we shove in there? */ + + /** + * how much payload data can we shove in there? + * @return MTU - 74 + */ private static final int fragmentSize(int mtu) { return mtu - SSU_HEADER_SIZE - UDP_HEADER_SIZE - IP_HEADER_SIZE; } @@ -1296,7 +1323,7 @@ class PeerState { long now = _context.clock().now(); if (state.getNextSendTime() <= now) { if (!state.isFragmented()) { - state.fragment(fragmentSize(getMTU())); + state.fragment(fragmentSize(_mtu)); if (state.getMessage() != null) state.getMessage().timestamp("fragment into " + state.getFragmentCount()); diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java index 1d8bad7a2c..3dd97a7040 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacket.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacket.java @@ -51,7 +51,13 @@ class UDPPacket { _log = I2PAppContext.getGlobalContext().logManager().getLog(UDPPacket.class); } - static final int MAX_PACKET_SIZE = 2048; + /** + * Actually it is one less than this, we assume + * if a received packet is this big it is truncated. + * This is bigger than PeerState.LARGE_MTU, as the far-end's + * LARGE_MTU may be larger than ours. + */ + static final int MAX_PACKET_SIZE = 1536; public static final int IV_SIZE = 16; public static final int MAC_SIZE = 16; @@ -96,7 +102,12 @@ class UDPPacket { //_dataBuf = _dataCache.acquire(); Arrays.fill(_data, (byte)0); //_packet = new DatagramPacket(_data, MAX_PACKET_SIZE); - //_packet.setData(_data); + // + // WARNING - + // Doesn't seem like we should have to do this every time, + // from reading the DatagramPacket javadocs, + // but we get massive corruption without it. + _packet.setData(_data); // _isInbound = inbound; _initializeTime = _context.clock().now(); _markedType = -1; diff --git a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java index 946191e4c9..6421ed93ef 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPPacketReader.java @@ -354,7 +354,9 @@ class UDPPacketReader { off++; // fragment info return ((int)DataHelper.fromLong(_message, off, 2)) & 0x3FFF; } - public void readMessageFragment(int fragmentNum, byte target[], int targetOffset) { + + public void readMessageFragment(int fragmentNum, byte target[], int targetOffset) + throws ArrayIndexOutOfBoundsException { int off = getFragmentBegin(fragmentNum); off += 4; // messageId off++; // fragment info diff --git a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java index 647a5639f2..bdf5b1e694 100644 --- a/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java +++ b/router/java/src/net/i2p/router/transport/udp/UDPReceiver.java @@ -243,6 +243,10 @@ class UDPReceiver { // and block after we know how much we read but before // we release the packet to the inbound queue + if (size >= UDPPacket.MAX_PACKET_SIZE) { + // DatagramSocket javadocs: If the message is longer than the packet's length, the message is truncated. + throw new IOException("packet too large! truncated and dropped"); + } if (size > 0) { //FIFOBandwidthLimiter.Request req = _context.bandwidthLimiter().requestInbound(size, "UDP receiver"); //_context.bandwidthLimiter().requestInbound(req, size, "UDP receiver");