From b9094307257fa9881f089d9448afcda856c0bf99 Mon Sep 17 00:00:00 2001 From: zzz Date: Fri, 18 Dec 2020 11:52:18 -0500 Subject: [PATCH] SSU: Account for packet overhead in window calculations --- .../transport/udp/OutboundMessageState.java | 35 +++++++++++++------ .../i2p/router/transport/udp/PeerState.java | 14 +++++++- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java index a1c3b2e54c..9b6c7aeb2e 100644 --- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java +++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java @@ -131,6 +131,9 @@ class OutboundMessageState implements CDPQEntry { return _fragmentAcks == 0; } + /** + * As of 0.9.49, includes packet overhead + */ public synchronized int getUnackedSize() { int rv = 0; if (isComplete()) @@ -138,12 +141,14 @@ class OutboundMessageState implements CDPQEntry { int lastSize = _messageBuf.length % _fragmentSize; if (lastSize == 0) lastSize = _fragmentSize; + int overhead = _peer.fragmentOverhead(); for (int i = 0; i < _numFragments; i++) { if (needsSending(i)) { if (i + 1 == _numFragments) rv += lastSize; else rv += _fragmentSize; + rv += overhead; } } return rv; @@ -187,6 +192,7 @@ class OutboundMessageState implements CDPQEntry { /** * The minimum number of bytes we can send, which is the smallest unacked fragment we will send next. + * Includes packet overhead. * * @return 0 to total size * @since 0.9.49 @@ -194,15 +200,16 @@ class OutboundMessageState implements CDPQEntry { public synchronized int getMinSendSize() { if (isComplete()) return 0; + int overhead = _peer.fragmentOverhead(); if (_numFragments == 1) - return _messageBuf.length; + return _messageBuf.length + overhead; if (_pushCount == 0) - return fragmentSize(_numFragments - 1); + return fragmentSize(_numFragments - 1) + overhead; int minSendCount = getMinSendCount(); int rv = _fragmentSize; for (int i = 0; i < _numFragments; i++) { if (needsSending(i) && _fragmentSends[i] == minSendCount) { - int sz = fragmentSize(i); + int sz = fragmentSize(i) + overhead; if (sz < rv) { rv = sz; } @@ -217,23 +224,27 @@ class OutboundMessageState implements CDPQEntry { * Note: With multiple fragments, this will allocate only the fragments with the lowest push count. * Example: If push counts are 1 1 1 0 0, this will only return the size of the last two fragments, * even if any of the first three need to be retransmitted. + * Includes packet overhead. * - * @param max the maximum number of bytes we can send + * @param max the maximum number of bytes we can send, including packet overhead * @return 0 to max bytes * @since 0.9.49 */ public synchronized int getSendSize(int max) { if (isComplete()) return 0; - if (_numFragments == 1) - return _messageBuf.length <= max ? _messageBuf.length : 0; + int overhead = _peer.fragmentOverhead(); + if (_numFragments == 1) { + int rv = _messageBuf.length + overhead; + return rv <= max ? rv : 0; + } // find the fragments we've sent the least int minSendCount = getMinSendCount(); // Allow only the fragments we've sent the least int rv = 0; for (int i = 0; i < _numFragments; i++) { if (needsSending(i) && _fragmentSends[i] == minSendCount) { - int sz = fragmentSize(i); + int sz = fragmentSize(i) + overhead; int tot = rv + sz; if (tot <= max) { rv = tot; @@ -315,11 +326,12 @@ class OutboundMessageState implements CDPQEntry { // send the fragments we've sent the least, up to the max size int minSendCount = getMinSendCount(); int sent = 0; + int overhead = _peer.fragmentOverhead(); for (int i = 0; i < _numFragments; i++) { if (needsSending(i)) { int count = _fragmentSends[i]; if (count == minSendCount) { - int sz = fragmentSize(i); + int sz = fragmentSize(i) + overhead; if (sz <= _allowedSendBytes - sent) { sent += sz; toSend.add(new Fragment(this, i)); @@ -327,7 +339,7 @@ class OutboundMessageState implements CDPQEntry { _fragmentSends[i]++; if (_fragmentSends[i] > _maxSends) _maxSends = _fragmentSends[i]; - if (sent >= _allowedSendBytes) + if (_allowedSendBytes - sent <= overhead) break; } } @@ -359,7 +371,8 @@ class OutboundMessageState implements CDPQEntry { public int getMessageSize() { return _messageBuf.length; } /** - * The size in bytes of the fragment + * The size in bytes of the fragment. + * Does NOT include any SSU overhead. * * @param fragmentNum the number of the fragment * @return the size of the fragment specified by the number @@ -383,7 +396,7 @@ class OutboundMessageState implements CDPQEntry { * @param out target to write * @param outOffset into outOffset to begin writing * @param fragmentNum fragment to write (0 indexed) - * @return bytesWritten + * @return bytesWritten, NOT including packet overhead */ public int writeFragment(byte out[], int outOffset, int fragmentNum) { int start = _fragmentSize * fragmentNum; 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 9ca1191599..5cb751ba0d 100644 --- a/router/java/src/net/i2p/router/transport/udp/PeerState.java +++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java @@ -625,7 +625,7 @@ public class PeerState { _context.statManager().addRateData("udp.rejectConcurrentActive", _outboundMessages.size(), _consecutiveRejections); return false; } - if (_sendWindowBytesRemaining <= 0) + if (_sendWindowBytesRemaining <= fragmentOverhead()) return false; int size = state.getSendSize(_sendWindowBytesRemaining); @@ -1660,6 +1660,18 @@ public class PeerState { (_remoteIP.length == 4 ? PacketBuilder.MIN_DATA_PACKET_OVERHEAD : PacketBuilder.MIN_IPV6_DATA_PACKET_OVERHEAD) - MIN_ACK_SIZE; } + + /** + * Packet overhead plus room for acks + * @return 87 (IPv4), 107 (IPv6) + * @since 0.9.49 + */ + int fragmentOverhead() { + // 46 + 20 + 8 + 13 = 74 + 13 = 87 (IPv4) + // 46 + 40 + 8 + 13 = 94 + 13 = 107 (IPv6) + return (_remoteIP.length == 4 ? PacketBuilder.MIN_DATA_PACKET_OVERHEAD : PacketBuilder.MIN_IPV6_DATA_PACKET_OVERHEAD) + + MIN_ACK_SIZE; + } /** * Locks this.