SSU2: Implement ack-immediate flag

Use a single ack timer for each session rather than
creating a new one for every ack
Log tweaks
This commit is contained in:
zzz
2022-08-29 16:47:19 -04:00
parent 8df81fc0a1
commit d809d6653d
5 changed files with 72 additions and 5 deletions

View File

@@ -1,3 +1,12 @@
2022-08-29 zzz
* SSU2: Implement ack-immediate flag
2022-08-28 zzz
* Console:
- Add notification and summary bar info on deadlock
- Linkify router hash even if not in netdb
* Util: Add option to gzip router logs
2022-08-25 zzz
* Router: Fix deadlock via rebuildRouterAddress() and UDPTransport
* SSU2:

View File

@@ -18,7 +18,7 @@ public class RouterVersion {
/** deprecated */
public final static String ID = "Git";
public final static String VERSION = CoreVersion.VERSION;
public final static long BUILD = 2;
public final static long BUILD = 3;
/** for example "-test" */
public final static String EXTRA = "";

View File

@@ -275,6 +275,11 @@ class PacketBuilder2 {
//if (_log.shouldDebug())
// _log.debug("Packet " + pktNum + " before encryption:\n" + HexDump.dump(data, 0, off));
// ack immediate flag
if (numFragments > 0) {
data[SHORT_HEADER_FLAGS_OFFSET] = peer.getFlags();
}
encryptDataPacket(packet, peer.getSendCipher(), pktNum, peer.getSendHeaderEncryptKey1(), peer.getSendHeaderEncryptKey2());
setTo(packet, peer.getRemoteIPAddress(), peer.getRemotePort());
//if (_log.shouldDebug())
@@ -351,8 +356,8 @@ class PacketBuilder2 {
* This will also include acks, a new token block, and padding.
*/
public UDPPacket buildSessionDestroyPacket(int reason, PeerState2 peer) {
if (_log.shouldWarn())
_log.warn("Sending termination " + reason + " to : " + peer);
if (_log.shouldDebug())
_log.debug("Sending termination " + reason + " to : " + peer);
List<Block> blocks = new ArrayList<Block>(2);
if (peer.getKeyEstablishedTime() - _context.clock().now() > EstablishmentManager.IB_TOKEN_EXPIRATION / 2 &&
!_context.router().gracefulShutdownInProgress()) {

View File

@@ -2214,6 +2214,17 @@ public class PeerState {
}
}
/**
* SSU 2 only
*
* @since 0.9.56
*/
protected boolean shouldRequestImmediateAck() {
synchronized(_sendWindowBytesRemainingLock) {
return _sendWindowBytesRemaining < _sendWindowBytes / 3;
}
}
/**
* Transfer the basic activity/state from the old peer to the current peer
*

View File

@@ -63,6 +63,8 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
*/
private final SSU2Bitfield _ackedMessages;
private final ConcurrentHashMap<Long, List<PacketBuilder.Fragment>> _sentMessages;
private final ACKTimer _ackTimer;
private long _sentMessagesLastExpired;
private byte[] _ourIP;
private int _ourPort;
@@ -140,6 +142,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
// For outbound, SessionConfirmed is packet 0
_packetNumber.set(1);
}
_ackTimer = new ACKTimer();
}
// SSU 1 overrides
@@ -197,7 +200,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
protected synchronized void messagePartiallyReceived(long now) {
if (_wantACKSendSince <= 0) {
_wantACKSendSince = now;
new ACKTimer();
_ackTimer.schedule();
}
}
@@ -490,6 +493,11 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
ECNReceived();
} //// !_dead
boolean ackImmediate = (header.data[SHORT_HEADER_FLAGS_OFFSET] & 0x01) != 0 && _context.getBooleanProperty("ssu2.ackImmediate");
if (ackImmediate) {
_ackTimer.scheduleImmediate();
}
} catch (Exception e) {
if (_log.shouldWarn())
_log.warn("Bad encrypted packet on: " + this + '\n' + HexDump.dump(data, off, len), e);
@@ -958,16 +966,50 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
return rv;
}
/**
* Flag byte to be sent in header
*
* @since 0.9.56
*/
byte getFlags() {
return shouldRequestImmediateAck() ? (byte) 0x01 : 0;
}
/**
* A timer to send an ack-only packet.
*/
private class ACKTimer extends SimpleTimer2.TimedEvent {
/**
* Caller must schedule
*/
public ACKTimer() {
super(_context.simpleTimer2());
}
/**
* Ack soon, based on the current RTT
*
* @since 0.9.56
*/
public void schedule() {
long delta = Math.max(10, Math.min(_rtt/6, ACK_FREQUENCY));
if (_log.shouldDebug())
_log.debug("Sending delayed ack in " + delta + ": " + PeerState2.this);
schedule(delta);
reschedule(delta, true);
}
/**
* Ack almost immediately
*
* @since 0.9.56
*/
public void scheduleImmediate() {
_wantACKSendSince = _context.clock().now();
long delta = Math.min(_rtt/16, 5);
if (_log.shouldDebug())
_log.debug("Sending immediate ack in " + delta + ": " + PeerState2.this);
reschedule(delta, true);
}
/**