SSU: Fix RTT/RTO calculations (ticket #2443)

This commit is contained in:
zzz
2019-02-26 17:17:00 +00:00
parent 566df1c275
commit cf1c0cb3ed
6 changed files with 47 additions and 20 deletions

View File

@ -62,7 +62,7 @@ class ACKSender implements Runnable {
public synchronized void shutdown() {
_alive = false;
PeerState poison = new PeerState(_context, _transport, new byte[4], 0, null, false);
PeerState poison = new PeerState(_context, _transport, new byte[4], 0, null, false, 0);
poison.setTheyRelayToUsAs(POISON_PS);
_peersToACK.offer(poison);
for (int i = 1; i <= 5 && !_peersToACK.isEmpty(); i++) {

View File

@ -694,7 +694,7 @@ class EstablishmentManager {
RouterIdentity remote = state.getConfirmedIdentity();
PeerState peer = new PeerState(_context, _transport,
state.getSentIP(), state.getSentPort(), remote.calculateHash(), true);
state.getSentIP(), state.getSentPort(), remote.calculateHash(), true, state.getRTT());
peer.setCurrentCipherKey(state.getCipherKey());
peer.setCurrentMACKey(state.getMACKey());
peer.setWeRelayToThemAs(state.getSentRelayTag());
@ -813,7 +813,7 @@ class EstablishmentManager {
_outboundByClaimedAddress.remove(claimed, state);
_outboundByHash.remove(remote.calculateHash(), state);
PeerState peer = new PeerState(_context, _transport,
state.getSentIP(), state.getSentPort(), remote.calculateHash(), false);
state.getSentIP(), state.getSentPort(), remote.calculateHash(), false, state.getRTT());
peer.setCurrentCipherKey(state.getCipherKey());
peer.setCurrentMACKey(state.getMACKey());
peer.setTheyRelayToUsAs(state.getReceivedRelayTag());

View File

@ -64,6 +64,8 @@ class InboundEstablishState {
private int _createdSentCount;
// default true
private boolean _introductionRequested = true;
private int _rtt;
public enum InboundState {
/** nothin known yet */
@ -296,6 +298,8 @@ class InboundEstablishState {
*/
public synchronized long getNextSendTime() { return _nextSend; }
synchronized int getRTT() { return _rtt; }
/** RemoteHostId, uniquely identifies an attempt */
RemoteHostId getRemoteHostId() { return _remoteHostId; }
@ -356,6 +360,10 @@ class InboundEstablishState {
_currentState = InboundState.IB_STATE_CONFIRMED_PARTIALLY;
}
if (_createdSentCount == 1) {
_rtt = (int) ( _context.clock().now() - _lastSend );
}
packetReceived();
}

View File

@ -74,6 +74,7 @@ class OutboundEstablishState {
private long _confirmedSentTime;
private long _requestSentTime;
private long _introSentTime;
private int _rtt;
public enum OutboundState {
/** nothin sent yet */
@ -179,6 +180,8 @@ class OutboundEstablishState {
* @since 0.9.24
*/
public boolean needIntroduction() { return _needIntroduction; }
synchronized int getRTT() { return _rtt; }
/**
* Queue a message to be sent after the session is established.
@ -304,6 +307,10 @@ class OutboundEstablishState {
_currentState == OutboundState.OB_STATE_INTRODUCED ||
_currentState == OutboundState.OB_STATE_PENDING_INTRO)
_currentState = OutboundState.OB_STATE_CREATED_RECEIVED;
if (_requestSentCount == 1) {
_rtt = (int) (_context.clock().now() - _requestSentTime);
}
packetReceived();
}

View File

@ -314,10 +314,10 @@ public class PeerState {
*/
public static final int MAX_MTU = Math.max(LARGE_MTU, MAX_IPV6_MTU);
private static final int MIN_RTO = 100 + ACKSender.ACK_FREQUENCY;
private static final int INIT_RTO = 3*1000;
public static final int INIT_RTT = INIT_RTO / 2;
private static final int MAX_RTO = 15*1000;
private static final int MIN_RTO = 1000;
private static final int INIT_RTO = 1000;
private static final int INIT_RTT = 0;
private static final int MAX_RTO = 60*1000;
private static final int CLOCK_SKEW_FUDGE = (ACKSender.ACK_FREQUENCY * 2) / 3;
/**
@ -336,8 +336,11 @@ public class PeerState {
private static final long RESEND_ACK_TIMEOUT = 5*60*1000;
/**
* @param rtt from the EstablishState, or 0 if not available
*/
public PeerState(RouterContext ctx, UDPTransport transport,
byte[] remoteIP, int remotePort, Hash remotePeer, boolean isInbound) {
byte[] remoteIP, int remotePort, Hash remotePeer, boolean isInbound, int rtt) {
_context = ctx;
_log = ctx.logManager().getLog(PeerState.class);
_transport = transport;
@ -366,9 +369,14 @@ public class PeerState {
}
//_mtuLastChecked = -1;
_lastACKSend = -1;
_rto = INIT_RTO;
_rtt = INIT_RTT;
_rttDeviation = _rtt;
if (rtt > 0)
recalculateTimeouts(rtt);
else
_rttDeviation = _rtt;
_inboundMessages = new HashMap<Long, InboundMessageState>(8);
_outboundMessages = new CachedIteratorCollection<OutboundMessageState>();
//_outboundQueue = new CoDelPriorityBlockingQueue(ctx, "UDP-PeerState", 32);
@ -1226,16 +1234,18 @@ public class PeerState {
* Caller should synch on this
*/
private void recalculateTimeouts(long lifetime) {
// the rttDev calculation matches that recommended in RFC 2988 (beta = 1/4)
_rttDeviation = _rttDeviation + (int)(0.25d*(Math.abs(lifetime-_rtt)-_rttDeviation));
if (_rtt <= 0) {
// first measurement
_rtt = (int) lifetime;
_rttDeviation = (int)(lifetime / 2);
} else {
// the rttDev calculation matches that recommended in RFC 2988 (beta = 1/4)
_rttDeviation = (int)( 0.75*_rttDeviation + 0.25*Math.abs(lifetime-_rtt) );
float scale = RTT_DAMPENING;
// the faster we are going, the slower we want to reduce the rtt
//if (_sendBps > 0)
// scale = lifetime / ((float)lifetime + (float)_sendBps);
//if (scale < 0.001f) scale = 0.001f;
float scale = RTT_DAMPENING;
_rtt = (int)(_rtt*(1.0f-scale) + (scale)*lifetime);
_rtt = (int)(_rtt*(1.0f-scale) + (scale)*lifetime);
}
// K = 4
_rto = Math.min(MAX_RTO, Math.max(minRTO(), _rtt + (_rttDeviation<<2)));
//if (_log.shouldLog(Log.DEBUG))
@ -1821,13 +1831,15 @@ public class PeerState {
+ " remaining"
+ " for message " + state.getMessageId() + ": " + state);
if (state.getPushCount() > 0)
int rto = getRTO();
if (state.getPushCount() > 0) {
_retransmitter = state;
rto = Math.min(MAX_RTO, rto << state.getPushCount()); // Section 5.5 RFC 6298
}
if (state.push())
_messagesSent++;
int rto = getRTO();
state.setNextSendTime(now + rto);
//if (peer.getSendWindowBytesRemaining() > 0)

View File

@ -2723,7 +2723,7 @@ public class UDPTransport extends TransportImpl implements TimedWeightedPriority
for (PeerState peer : _peersByIdent.values()) {
if ((!includeEverybody) && now - peer.getLastReceiveTime() > 5*60*1000)
continue; // skip old peers
if (peer.getRTT() > PeerState.INIT_RTT - 250)
if (peer.getRTT() > 1250)
continue; // Big RTT makes for a poor calculation
skews.addElement(Long.valueOf(peer.getClockSkew() / 1000));
}