From aa620f5ed3d0dade34b1fd53cc4038dfb5579c6b Mon Sep 17 00:00:00 2001
From: zzz <zzz@i2pmail.org>
Date: Sat, 12 Mar 2022 11:08:20 -0500
Subject: [PATCH] SSU2: Fixes part 8

Fix packet length for retransmitted handshake messages
Expire pending acks
---
 .../transport/udp/InboundEstablishState2.java |  1 +
 .../udp/OutboundEstablishState2.java          |  1 +
 .../i2p/router/transport/udp/PeerState.java   |  2 +-
 .../i2p/router/transport/udp/PeerState2.java  | 37 ++++++++++++++++++-
 4 files changed, 39 insertions(+), 2 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 6e70e92413..ead02c0ae9 100644
--- a/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
+++ b/router/java/src/net/i2p/router/transport/udp/InboundEstablishState2.java
@@ -615,6 +615,7 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
         byte data[] = pkt.getData();
         int off = pkt.getOffset();
         System.arraycopy(_sessCrForReTX, 0, data, off, _sessCrForReTX.length);
+        pkt.setLength(_sessCrForReTX.length);
         pkt.setSocketAddress(_aliceSocketAddress);
         packet.setMessageType(PacketBuilder2.TYPE_CONF);
         packet.setPriority(PacketBuilder2.PRIORITY_HIGH);
diff --git a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java
index 3d4896a6b0..45d9cfb0cb 100644
--- a/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java
+++ b/router/java/src/net/i2p/router/transport/udp/OutboundEstablishState2.java
@@ -514,6 +514,7 @@ class OutboundEstablishState2 extends OutboundEstablishState implements SSU2Payl
         byte data[] = pkt.getData();
         int off = pkt.getOffset();
         System.arraycopy(_sessReqForReTX, 0, data, off, _sessReqForReTX.length);
+        pkt.setLength(_sessReqForReTX.length);
         pkt.setSocketAddress(_bobSocketAddress);
         packet.setMessageType(PacketBuilder2.TYPE_SREQ);
         packet.setPriority(PacketBuilder2.PRIORITY_HIGH);
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 11f6573691..9920602804 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerState.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerState.java
@@ -70,7 +70,7 @@ public class PeerState {
     private SessionKey _nextCipherKey;
 
     /** when were the current cipher and MAC keys established/rekeyed? */
-    private final long _keyEstablishedTime;
+    protected final long _keyEstablishedTime;
 
     /**
      *  How far off is the remote peer from our clock, in milliseconds?
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 439226083e..4d9b1a1d57 100644
--- a/router/java/src/net/i2p/router/transport/udp/PeerState2.java
+++ b/router/java/src/net/i2p/router/transport/udp/PeerState2.java
@@ -5,6 +5,7 @@ import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.security.GeneralSecurityException;
+import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.ConcurrentHashMap;
@@ -55,6 +56,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
      */
     private final SSU2Bitfield _ackedMessages;
     private final ConcurrentHashMap<Long, List<PacketBuilder.Fragment>> _sentMessages;
+    private long _sentMessagesLastExpired;
 
     // Session Confirmed retransmit
     private byte[] _sessConfForReTX;
@@ -76,7 +78,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
     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;
-
+    private static final long SENT_MESSAGES_CLEAN_TIME = 60*1000;
 
 
     /**
@@ -98,6 +100,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
         _receivedMessages = new SSU2Bitfield(BITFIELD_SIZE, 0);
         _ackedMessages = new SSU2Bitfield(BITFIELD_SIZE, 0);
         _sentMessages = new ConcurrentHashMap<Long, List<PacketBuilder.Fragment>>(32);
+        _sentMessagesLastExpired = _keyEstablishedTime;
         if (isInbound) {
             // Send immediate ack of Session Confirmed
             _receivedMessages.set(0);
@@ -168,6 +171,37 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
         }
     }
 
+    /**
+     * Overridden to expire unacked packets in _sentMessages.
+     * These will remain unacked if lost; fragments will be retransmitted
+     * in a new packet.
+     *
+     * @return number of active outbound messages remaining
+     */
+    @Override
+    int finishMessages(long now) {
+        if (now >= _sentMessagesLastExpired + SENT_MESSAGES_CLEAN_TIME) {
+            _sentMessagesLastExpired = now;
+            if (!_sentMessages.isEmpty()) {
+                if (_log.shouldDebug())
+                    _log.debug("finishMessages() over " + _sentMessages.size() + " pending acks");
+                loop:
+                for (Iterator<List<PacketBuilder.Fragment>> iter = _sentMessages.values().iterator(); iter.hasNext(); ) {
+                    List<PacketBuilder.Fragment> frags = iter.next();
+                    for (PacketBuilder.Fragment f : frags) {
+                        OutboundMessageState state = f.state;
+                        if (!state.isComplete() && !state.isExpired(now))
+                            continue loop;
+                    }
+                    iter.remove();
+                    if (_log.shouldWarn())
+                        _log.warn("Cleaned from sentMessages: " + frags);
+                }
+            }
+        }
+        return super.finishMessages(now);
+    }
+
     /**
      *  Overridden to retransmit SessionConfirmed also
      */
@@ -570,6 +604,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
         byte data[] = pkt.getData();
         int off = pkt.getOffset();
         System.arraycopy(_sessConfForReTX, 0, data, off, _sessConfForReTX.length);
+        pkt.setLength(_sessConfForReTX.length);
         pkt.setAddress(_remoteIPAddress);
         pkt.setPort(_remotePort);
         packet.setMessageType(PacketBuilder2.TYPE_CONF);
-- 
GitLab