From eb72e97c0316a7e2803ca177ebb7c43ed646591d Mon Sep 17 00:00:00 2001
From: zzz <zzz@i2pmail.org>
Date: Mon, 7 Mar 2022 10:44:17 -0500
Subject: [PATCH] SSU2: Fixes part 4

Fix deadlock in AckTimer
Enforce token in IES2
Increase bitfield sizes in PS2
Log tweaks
---
 .../transport/udp/InboundEstablishState2.java |  2 +-
 .../transport/udp/OutboundMessageState.java   |  3 ++
 .../i2p/router/transport/udp/PeerState2.java  | 30 +++++++++++--------
 3 files changed, 21 insertions(+), 14 deletions(-)

diff --git a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
index 746d1e94e1..0f262918c5 100644
--- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
+++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
@@ -54,7 +54,7 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
     private PeerState2 _pstate;
     
     // testing
-    private static final boolean ENFORCE_TOKEN = false;
+    private static final boolean ENFORCE_TOKEN = true;
     private static final long MAX_SKEW = 2*60*1000L;
 
 
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 8940f6606e..869af99900 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundMessageState.java
@@ -307,6 +307,9 @@ class OutboundMessageState implements CDPQEntry {
         return rv;
     }
 
+    /**
+     * @return true if the fragment has not been ACKed
+     */
     public synchronized boolean needsSending(int fragment) {
         return (_fragmentAcks & mask(fragment)) != 0;
     }
diff --git a/router/java/src/net/i2p/router/transport/udp/PeerState2.java b/router/java/src/net/i2p/router/transport/udp/PeerState2.java
index 31fffcadf9..3533c98929 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerState2.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerState2.java
@@ -73,6 +73,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
     public static final int MAX_MTU = 1500;
     public static final int DEFAULT_MTU = MAX_MTU;
 
+    private static final int BITFIELD_SIZE = 512;
     private static final int MAX_SESS_CONF_RETX = 6;
     private static final int SESS_CONF_RETX_TIME = 1000;
 
@@ -94,8 +95,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
         _rcvHeaderEncryptKey1 = transport.getSSU2StaticIntroKey();
         _sendHeaderEncryptKey2 = sendHdrKey2;
         _rcvHeaderEncryptKey2 = rcvHdrKey2;
-        _receivedMessages = new SSU2Bitfield(256, 0);
-        _ackedMessages = new SSU2Bitfield(256, 0);
+        _receivedMessages = new SSU2Bitfield(BITFIELD_SIZE, 0);
+        _ackedMessages = new SSU2Bitfield(BITFIELD_SIZE, 0);
         _sentMessages = new ConcurrentHashMap<Long, List<PacketBuilder.Fragment>>(32);
         if (isInbound) {
             // Send immediate ack of Session Confirmed
@@ -404,12 +405,9 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
 
     public void gotACK(long ackThru, int acks, byte[] ranges) {
         SSU2Bitfield ackbf;
-        if (ranges != null)
-            ackbf = SSU2Bitfield.fromACKBlock(ackThru, acks, ranges, ranges.length / 2);
-        else
-            ackbf = SSU2Bitfield.fromACKBlock(ackThru, acks, null, 0);
+        ackbf = SSU2Bitfield.fromACKBlock(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0));
         if (_log.shouldDebug())
-            _log.debug("Got ACK block: " + ackbf);
+            _log.debug("Got ACK block: " + SSU2Bitfield.toString(ackThru, acks, ranges, (ranges != null ? ranges.length / 2 : 0)));
         // calls bitSet() below
         ackbf.forEachAndNot(_ackedMessages, this);
     }
@@ -517,6 +515,12 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
                 continue;
             }
             int num = f.num;
+            if (!state.needsSending(num)) {
+                // will happen with retransmission as a different packet number
+                if (_log.shouldWarn())
+                    _log.warn("New ACK for fragment " + num + " but already acked? " + state);
+                continue;
+            }
             int ackedSize = state.getUnackedSize();
             boolean complete = state.acked(f.num);
             if (complete) {
@@ -596,17 +600,17 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
          */
         public void timeReached() {
             synchronized(PeerState2.this) {
-                long wanted = _wantACKSendSince;
-                if (wanted <= 0) {
+                if (_wantACKSendSince <= 0) {
                     if (_log.shouldDebug())
                         _log.debug("Already acked:" + PeerState2.this);
                     return;
                 }
-                UDPPacket ack = _transport.getBuilder2().buildACK(PeerState2.this);
-                if (_log.shouldDebug())
-                    _log.debug("Sending acks to " + PeerState2.this);
-                _transport.send(ack);
+                _wantACKSendSince = 0;
             }
+            UDPPacket ack = _transport.getBuilder2().buildACK(PeerState2.this);
+            if (_log.shouldDebug())
+                _log.debug("Sending acks to " + PeerState2.this);
+            _transport.send(ack);
         }
     }
 }
-- 
GitLab