I2P Address: [http://git.idk.i2p]

Skip to content
Snippets Groups Projects
Commit 73a12d47 authored by jrandom's avatar jrandom Committed by zzz
Browse files

* you mean we should implement congestion *avoidance* too?

* ack properly on duplicates
* set the message input stream buffer large enough to fit the max window (duh)
parent 83165df7
No related branches found
No related tags found
No related merge requests found
......@@ -56,6 +56,9 @@ public class Connection {
private boolean _disconnectScheduled;
private long _lastReceivedOn;
private ActivityTimer _activityTimer;
/** window size when we last saw congestion */
private int _lastCongestionSeenAt;
private boolean _ackSinceCongestion;
public static final long MAX_RESEND_DELAY = 60*1000;
public static final long MIN_RESEND_DELAY = 20*1000;
......@@ -63,6 +66,9 @@ public class Connection {
/** wait up to 5 minutes after disconnection so we can ack/close packets */
public static long DISCONNECT_TIMEOUT = 5*60*1000;
/** lets be sane.. no more than 32 packets in the air in each dir */
public static final int MAX_WINDOW_SIZE = 32;
public Connection(I2PAppContext ctx, ConnectionManager manager, SchedulerChooser chooser, PacketQueue queue, ConnectionPacketHandler handler) {
this(ctx, manager, chooser, queue, handler, null);
}
......@@ -86,12 +92,14 @@ public class Connection {
_unackedPacketsReceived = 0;
_congestionWindowEnd = 0;
_highestAckedThrough = -1;
_lastCongestionSeenAt = MAX_WINDOW_SIZE;
_connectionManager = manager;
_resetReceived = false;
_connected = true;
_disconnectScheduled = false;
_lastReceivedOn = -1;
_activityTimer = new ActivityTimer();
_ackSinceCongestion = true;
}
public long getNextOutboundPacketNum() {
......@@ -275,6 +283,8 @@ public class Connection {
}
_outboundPackets.notifyAll();
}
if ((acked != null) && (acked.size() > 0) )
_ackSinceCongestion = true;
return acked;
}
......@@ -438,6 +448,17 @@ public class Connection {
return (_lastSendTime > _lastReceivedOn ? _lastSendTime : _lastReceivedOn);
}
public int getLastCongestionSeenAt() { return _lastCongestionSeenAt; }
void congestionOccurred() {
// if we hit congestion and e.g. 5 packets are resent,
// dont set the size to (winSize >> 4). only set the
if (_ackSinceCongestion) {
_lastCongestionSeenAt = _options.getWindowSize();
_ackSinceCongestion = false;
}
}
void packetReceived() {
_lastReceivedOn = _context.clock().now();
resetActivityTimer();
......@@ -563,6 +584,7 @@ public class Connection {
// shrink the window
int newWindowSize = getOptions().getWindowSize();
_lastCongestionSeenAt = newWindowSize;
newWindowSize /= 2;
if (newWindowSize <= 0)
newWindowSize = 1;
......
......@@ -74,7 +74,7 @@ public class ConnectionOptions extends I2PSocketOptions {
setWriteTimeout(-1);
setInactivityTimeout(5*60*1000);
setInactivityAction(INACTIVITY_ACTION_SEND);
setInboundBufferSize(256*1024);
setInboundBufferSize((Packet.MAX_PAYLOAD_SIZE + 2) * Connection.MAX_WINDOW_SIZE);
}
}
......@@ -103,15 +103,14 @@ public class ConnectionOptions extends I2PSocketOptions {
public boolean getRequireFullySigned() { return _fullySigned; }
public void setRequireFullySigned(boolean sign) { _fullySigned = sign; }
private static final int MAX_WINDOW_SIZE = 32;
/**
* How many messages will we send before waiting for an ACK?
*
*/
public int getWindowSize() { return _windowSize; }
public void setWindowSize(int numMsgs) {
if (numMsgs > MAX_WINDOW_SIZE)
numMsgs = MAX_WINDOW_SIZE;
if (numMsgs > Connection.MAX_WINDOW_SIZE)
numMsgs = Connection.MAX_WINDOW_SIZE;
_windowSize = numMsgs;
}
......
......@@ -124,10 +124,17 @@ public class ConnectionPacketHandler {
if ( (!isNew) && (sequenceNum > 0) ) {
// dup real packet
int oldSize = con.getOptions().getWindowSize();
con.congestionOccurred();
oldSize >>>= 1;
if (oldSize <= 0)
oldSize = 1;
con.getOptions().setWindowSize(oldSize);
if (_log.shouldLog(Log.DEBUG))
_log.debug("Congestion occurred - new windowSize " + oldSize + " congestionSeenAt: "
+ con.getLastCongestionSeenAt() + " (#resends: " + numResends
+ ") for " + con);
return true;
} else if (numResends > 0) {
// window sizes are shrunk on resend, not on ack
......@@ -137,9 +144,23 @@ public class ConnectionPacketHandler {
if (lowest >= con.getCongestionWindowEnd()) {
// new packet that ack'ed uncongested data, or an empty ack
int newWindowSize = con.getOptions().getWindowSize();
newWindowSize += 1; // acked; // 1
if (newWindowSize > con.getLastCongestionSeenAt() / 2) {
// congestion avoidance
// we can't use newWindowSize += 1/newWindowSize, since we're
// integers, so lets use a random distribution instead
int shouldIncrement = _context.random().nextInt(newWindowSize);
if (shouldIncrement <= 0)
newWindowSize += 1;
} else {
// slow start
newWindowSize += 1;
}
if (_log.shouldLog(Log.DEBUG))
_log.debug("New window size " + newWindowSize + " (#resends: " + numResends
_log.debug("New window size " + newWindowSize + " congestionSeenAt: "
+ con.getLastCongestionSeenAt() + " (#resends: " + numResends
+ ") for " + con);
con.getOptions().setWindowSize(newWindowSize);
con.setCongestionWindowEnd(newWindowSize + lowest);
......@@ -267,9 +288,9 @@ public class ConnectionPacketHandler {
_con = con;
}
public void timeReached() {
if (_con.getLastActivityOn() <= _created) {
if (_con.getLastSendTime() <= _created) {
if (_log.shouldLog(Log.DEBUG))
_log.debug("Last activity was a while ago, and we want to ack a dup");
_log.debug("Last sent was a while ago, and we want to ack a dup");
// we haven't done anything since receiving the dup, send an
// ack now
_con.ackImmediately();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment