SSU2: Retransmit session confirmed after receiving apparent retransmitted session created

Retransmit handshake messages faster and expire faster (SSU 1/2)
log tweaks
This commit is contained in:
zzz
2022-07-19 11:17:54 -04:00
parent b7db6ae77c
commit f5ca15c28d
5 changed files with 67 additions and 38 deletions

View File

@@ -103,13 +103,16 @@ class InboundEstablishState {
}
/** basic delay before backoff
* Transmissions at 0, 3, 9 sec
* Previously: 1500 (0, 1.5, 4.5, 10.5)
* Transmissions at 0, 1, 3, 7 sec
* This should be a little shorter than for outbound.
*/
protected static final long RETRANSMIT_DELAY = 3000;
protected static final long RETRANSMIT_DELAY = 1000;
/** max delay including backoff */
protected static final long MAX_DELAY = 15*1000;
/**
* max delay including backoff
* This should be a little shorter than for outbound.
*/
protected static final long MAX_DELAY = 12*1000;
/**
* @param localPort Must be our external port, otherwise the signature of the

View File

@@ -738,6 +738,8 @@ class InboundEstablishState2 extends InboundEstablishState implements SSU2Payloa
public synchronized UDPPacket getRetransmitSessionCreatedPacket() {
if (_sessCrForReTX == null)
return null;
if (_log.shouldInfo())
_log.info("ReTX Sess Created on " + this);
UDPPacket packet = UDPPacket.acquire(_context, false);
DatagramPacket pkt = packet.getPacket();
byte data[] = pkt.getData();

View File

@@ -117,12 +117,15 @@ class OutboundEstablishState {
}
/** basic delay before backoff
* Transmissions at 0, 3, 9 sec
* Previously: 1500 (0, 1.5, 4.5, 10.5)
* Transmissions at 0, 1.25, 3.75, 8.75 sec
* This should be a little longer than for inbound.
*/
protected static final long RETRANSMIT_DELAY = 3000;
protected static final long RETRANSMIT_DELAY = 1250;
/** max delay including backoff */
/**
* max delay including backoff
* This should be a little longer than for inbound.
*/
private static final long MAX_DELAY = 15*1000;
private static final long WAIT_FOR_HOLE_PUNCH_DELAY = 500;

View File

@@ -1729,8 +1729,8 @@ public class PeerState {
// // ignore result, always send?
// locked_shouldSend(dequeuedState);
//}
if (_log.shouldLog(Log.DEBUG))
_log.debug("Allocate sending (NEW) to " + _remotePeer + ": " + dequeuedState.getMessageId());
//if (_log.shouldLog(Log.DEBUG))
// _log.debug("Allocate sending (NEW) to " + _remotePeer + ": " + dequeuedState.getMessageId());
if (rv == null)
rv = new ArrayList<OutboundMessageState>(_concurrentMessagesAllowed);
rv.add(dequeuedState);
@@ -1813,12 +1813,14 @@ public class PeerState {
private boolean locked_shouldSend(OutboundMessageState state, long now) {
synchronized(this) {
if (allocateSendingBytes(state, now)) {
/***
if (_log.shouldLog(Log.DEBUG))
_log.debug(_remotePeer + " Allocation allowed with "
+ getSendWindowBytesRemaining()
+ "/" + getSendWindowBytes()
+ " remaining"
+ " for message " + state.getMessageId() + ": " + state);
***/
if (state.getPushCount() == 0)
_messagesSent++;
return true;

View File

@@ -81,8 +81,7 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
public static final int DEFAULT_MTU = MAX_MTU;
private static final int BITFIELD_SIZE = 512;
private static final int MAX_SESS_CONF_RETX = 4;
private static final int SESS_CONF_RETX_TIME = 1000;
private static final int MAX_SESS_CONF_RETX = 5;
private static final long SENT_MESSAGES_CLEAN_TIME = 60*1000;
@@ -213,38 +212,51 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
@Override
List<OutboundMessageState> allocateSend(long now) {
if (!_isInbound && _ackedMessages.getOffset() == 0 && !_ackedMessages.get(0)) {
UDPPacket[] packets = null;
synchronized(this) {
if (_sessConfForReTX != null) {
// retransmit Session Confirmed when it's time
if (_sessConfSentTime + (SESS_CONF_RETX_TIME << (_sessConfSentCount - 1)) < now) {
if (!checkRetransmitSessionConfirmed(_context.clock().now(), false))
return null;
}
return super.allocateSend(now);
}
/**
* Only call for outbound, if we don't have ack 0 yet.
*
* @param force ignore timer, always send
* @return success, false if total fail
* @since 0.9.55 split out from above
*/
private boolean checkRetransmitSessionConfirmed(long now, boolean force) {
UDPPacket[] packets = null;
synchronized(this) {
if (_sessConfForReTX != null) {
// retransmit Session Confirmed when it's time
if (force || _sessConfSentTime + (OutboundEstablishState.RETRANSMIT_DELAY << (_sessConfSentCount - 1)) < now) {
if (_sessConfSentCount >= MAX_SESS_CONF_RETX) {
// note: we generally won't get here, because the
// first outbound message will timeout before this
// and close the session in super.finishMessages()
if (_sessConfSentCount >= MAX_SESS_CONF_RETX) {
if (_log.shouldWarn())
_log.warn("Fail, no Sess Conf ACK rcvd on " + this);
UDPPacket pkt = _transport.getBuilder2().buildSessionDestroyPacket(SSU2Util.REASON_FRAME_TIMEOUT, this);
_transport.send(pkt);
_transport.dropPeer(this, true, "No Sess Conf ACK rcvd");
_sessConfForReTX = null;
return null;
}
_sessConfSentCount++;
_sessConfSentTime = now;
packets = getRetransmitSessionConfirmedPackets();
if (_log.shouldWarn())
_log.warn("Fail, no Sess Conf ACK rcvd on " + this);
UDPPacket pkt = _transport.getBuilder2().buildSessionDestroyPacket(SSU2Util.REASON_FRAME_TIMEOUT, this);
_transport.send(pkt);
_transport.dropPeer(this, true, "No Sess Conf ACK rcvd");
_sessConfForReTX = null;
return false;
}
}
}
if (packets != null) {
if (_log.shouldInfo())
_log.info("ReTX Sess Conf on " + this);
for (int i = 0; i < packets.length; i++) {
_transport.send(packets[i]);
_sessConfSentCount++;
_sessConfSentTime = now;
packets = getRetransmitSessionConfirmedPackets();
}
}
}
return super.allocateSend(now);
if (packets != null) {
if (_log.shouldInfo())
_log.info("ReTX Sess Conf on " + this);
for (int i = 0; i < packets.length; i++) {
_transport.send(packets[i]);
}
}
return true;
}
// SSU 1 unsupported things
@@ -314,6 +326,13 @@ public class PeerState2 extends PeerState implements SSU2Payload.PayloadCallback
if (header.getDestConnID() != _rcvConnID) {
if (_log.shouldWarn())
_log.warn("bad Dest Conn id " + header + " size " + len + " on " + this);
if (!_isInbound && _ackedMessages.getOffset() == 0 && !_ackedMessages.get(0)) {
// this was probably a retransmitted session created,
// sent with k_header_1 = bob's intro key, and we're
// attempting to decrypt with our intro key.
// resend session confirmed in response
checkRetransmitSessionConfirmed(_context.clock().now(), true);
}
return;
}
if (header.getType() != DATA_FLAG_BYTE) {