mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-13 03:09:04 +01:00
SLTP reads and writes should time out eventually.
This commit is contained in:
@@ -4,7 +4,7 @@ import net.sf.briar.util.ByteUtils;
|
||||
|
||||
class Ack extends Frame {
|
||||
|
||||
static final int LENGTH = 12;
|
||||
static final int LENGTH = 11;
|
||||
|
||||
Ack() {
|
||||
super(new byte[LENGTH]);
|
||||
@@ -18,10 +18,10 @@ class Ack extends Frame {
|
||||
}
|
||||
|
||||
int getWindowSize() {
|
||||
return ByteUtils.readUint24(buf, 5);
|
||||
return ByteUtils.readUint16(buf, 5);
|
||||
}
|
||||
|
||||
void setWindowSize(int windowSize) {
|
||||
ByteUtils.writeUint24(windowSize, buf, 5);
|
||||
ByteUtils.writeUint16(windowSize, buf, 5);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,8 @@ import net.sf.briar.api.reliability.ReadHandler;
|
||||
|
||||
class Receiver implements ReadHandler {
|
||||
|
||||
static final int MAX_WINDOW_SIZE = 8 * Data.MAX_PAYLOAD_LENGTH;
|
||||
private static final int READ_TIMEOUT = 5 * 60 * 1000; // Milliseconds
|
||||
private static final int MAX_WINDOW_SIZE = 8 * Data.MAX_PAYLOAD_LENGTH;
|
||||
|
||||
private final Sender sender;
|
||||
private final SortedSet<Data> dataFrames; // Locking: this
|
||||
@@ -27,10 +28,11 @@ class Receiver implements ReadHandler {
|
||||
}
|
||||
|
||||
synchronized Data read() throws IOException, InterruptedException {
|
||||
while(valid) {
|
||||
long now = System.currentTimeMillis(), end = now + READ_TIMEOUT;
|
||||
while(now < end && valid) {
|
||||
if(dataFrames.isEmpty()) {
|
||||
// Wait for a data frame
|
||||
wait();
|
||||
wait(end - now);
|
||||
} else {
|
||||
Data d = dataFrames.first();
|
||||
if(d.getSequenceNumber() == nextSequenceNumber) {
|
||||
@@ -42,10 +44,12 @@ class Receiver implements ReadHandler {
|
||||
return d;
|
||||
} else {
|
||||
// Wait for the next in-order data frame
|
||||
wait();
|
||||
wait(end - now);
|
||||
}
|
||||
}
|
||||
now = System.currentTimeMillis();
|
||||
}
|
||||
if(valid) throw new IOException("Read timed out");
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
|
||||
|
||||
@@ -11,20 +11,23 @@ import net.sf.briar.api.reliability.WriteHandler;
|
||||
class Sender {
|
||||
|
||||
// All times are in milliseconds
|
||||
private static final int MIN_TIMEOUT = 1000;
|
||||
private static final int MAX_TIMEOUT = 60 * 1000;
|
||||
private static final int WRITE_TIMEOUT = 5 * 60 * 1000;
|
||||
private static final int MIN_RTO = 1000;
|
||||
private static final int MAX_RTO = 60 * 1000;
|
||||
private static final int INITIAL_RTT = 0;
|
||||
private static final int INITIAL_RTT_VAR = 3 * 1000;
|
||||
private static final int MAX_WINDOW_SIZE = 64 * Data.MAX_PAYLOAD_LENGTH;
|
||||
|
||||
private final WriteHandler writeHandler;
|
||||
private final LinkedList<Outstanding> outstanding; // Locking: this
|
||||
|
||||
private int outstandingBytes = 0; // Locking: this
|
||||
private int windowSize = Data.MAX_PAYLOAD_LENGTH; // Locking: this
|
||||
private int rtt = INITIAL_RTT, rttVar = INITIAL_RTT_VAR; // Locking: this
|
||||
private int timeout = rtt + (rttVar << 2); // Locking: this
|
||||
private long lastWindowUpdateOrProbe = Long.MAX_VALUE; // Locking: this
|
||||
private boolean dataWaiting = false; // Locking: this
|
||||
// All of the following are locking: this
|
||||
private int outstandingBytes = 0;
|
||||
private int windowSize = Data.MAX_PAYLOAD_LENGTH;
|
||||
private int rtt = INITIAL_RTT, rttVar = INITIAL_RTT_VAR;
|
||||
private int rto = rtt + (rttVar << 2);
|
||||
private long lastWindowUpdateOrProbe = Long.MAX_VALUE;
|
||||
private boolean dataWaiting = false;
|
||||
|
||||
Sender(WriteHandler writeHandler) {
|
||||
this.writeHandler = writeHandler;
|
||||
@@ -62,15 +65,15 @@ class Sender {
|
||||
it.remove();
|
||||
outstandingBytes -= o.data.getPayloadLength();
|
||||
foundIndex = i;
|
||||
// Update the round-trip time and retransmission timer
|
||||
// Update the round-trip time and retransmission timeout
|
||||
if(!o.retransmitted) {
|
||||
int sample = (int) (now - o.lastTransmitted);
|
||||
int error = sample - rtt;
|
||||
rtt += (error >> 3);
|
||||
rttVar += (Math.abs(error) - rttVar) >> 2;
|
||||
timeout = rtt + (rttVar << 2);
|
||||
if(timeout < MIN_TIMEOUT) timeout = MIN_TIMEOUT;
|
||||
else if(timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT;
|
||||
rto = rtt + (rttVar << 2);
|
||||
if(rto < MIN_RTO) rto = MIN_RTO;
|
||||
else if(rto > MAX_RTO) rto = MAX_RTO;
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -86,7 +89,7 @@ class Sender {
|
||||
lastWindowUpdateOrProbe = now;
|
||||
int oldWindowSize = windowSize;
|
||||
// Don't accept an unreasonably large window size
|
||||
windowSize = Math.min(a.getWindowSize(), Receiver.MAX_WINDOW_SIZE);
|
||||
windowSize = Math.min(a.getWindowSize(), MAX_WINDOW_SIZE);
|
||||
// If space has become available, notify any waiting writers
|
||||
if(windowSize > oldWindowSize || foundIndex != -1) notifyAll();
|
||||
}
|
||||
@@ -101,22 +104,23 @@ class Sender {
|
||||
boolean sendProbe = false;
|
||||
synchronized(this) {
|
||||
if(outstanding.isEmpty()) {
|
||||
if(dataWaiting && now - lastWindowUpdateOrProbe > timeout) {
|
||||
if(dataWaiting && now - lastWindowUpdateOrProbe > rto) {
|
||||
sendProbe = true;
|
||||
timeout <<= 1;
|
||||
if(timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT;
|
||||
rto <<= 1;
|
||||
if(rto > MAX_RTO) rto = MAX_RTO;
|
||||
}
|
||||
} else {
|
||||
Iterator<Outstanding> it = outstanding.iterator();
|
||||
while(it.hasNext()) {
|
||||
Outstanding o = it.next();
|
||||
if(now - o.lastTransmitted > timeout) {
|
||||
if(now - o.lastTransmitted > rto) {
|
||||
it.remove();
|
||||
if(retransmit == null)
|
||||
retransmit = new ArrayList<Outstanding>();
|
||||
retransmit.add(o);
|
||||
timeout <<= 1;
|
||||
if(timeout > MAX_TIMEOUT) timeout = MAX_TIMEOUT;
|
||||
// Update the retransmission timeout
|
||||
rto <<= 1;
|
||||
if(rto > MAX_RTO) rto = MAX_RTO;
|
||||
}
|
||||
}
|
||||
if(retransmit != null) {
|
||||
@@ -146,10 +150,14 @@ class Sender {
|
||||
int payloadLength = d.getPayloadLength();
|
||||
synchronized(this) {
|
||||
// Wait for space in the window
|
||||
while(outstandingBytes + payloadLength >= windowSize) {
|
||||
long now = System.currentTimeMillis(), end = now + WRITE_TIMEOUT;
|
||||
while(now < end && outstandingBytes + payloadLength >= windowSize) {
|
||||
dataWaiting = true;
|
||||
wait();
|
||||
wait(end - now);
|
||||
now = System.currentTimeMillis();
|
||||
}
|
||||
if(outstandingBytes + payloadLength >= windowSize)
|
||||
throw new IOException("Write timed out");
|
||||
outstanding.add(new Outstanding(d));
|
||||
outstandingBytes += payloadLength;
|
||||
dataWaiting = false;
|
||||
|
||||
@@ -7,11 +7,6 @@ public class ByteUtils {
|
||||
*/
|
||||
public static final int MAX_16_BIT_UNSIGNED = 65535; // 2^16 - 1
|
||||
|
||||
/**
|
||||
* The maximum value that can be represented as an unsigned 24-bit integer.
|
||||
*/
|
||||
public static final int MAX_24_BIT_UNSIGNED = 16777215; // 2^24 - 1
|
||||
|
||||
/**
|
||||
* The maximum value that can be represented as an unsigned 32-bit integer.
|
||||
*/
|
||||
@@ -32,15 +27,6 @@ public class ByteUtils {
|
||||
b[offset + 1] = (byte) (i & 0xFF);
|
||||
}
|
||||
|
||||
public static void writeUint24(long i, byte[] b, int offset) {
|
||||
if(i < 0L) throw new IllegalArgumentException();
|
||||
if(i > MAX_24_BIT_UNSIGNED) throw new IllegalArgumentException();
|
||||
if(b.length < offset + 3) throw new IllegalArgumentException();
|
||||
b[offset] = (byte) (i >> 16);
|
||||
b[offset + 1] = (byte) (i >> 8 & 0xFF);
|
||||
b[offset + 2] = (byte) (i & 0xFF);
|
||||
}
|
||||
|
||||
public static void writeUint32(long i, byte[] b, int offset) {
|
||||
if(i < 0L) throw new IllegalArgumentException();
|
||||
if(i > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException();
|
||||
@@ -56,12 +42,6 @@ public class ByteUtils {
|
||||
return ((b[offset] & 0xFF) << 8) | (b[offset + 1] & 0xFF);
|
||||
}
|
||||
|
||||
public static int readUint24(byte[] b, int offset) {
|
||||
if(b.length < offset + 3) throw new IllegalArgumentException();
|
||||
return ((b[offset] & 0xFF) << 16) | ((b[offset + 1] & 0xFF) << 8)
|
||||
| (b[offset + 2] & 0xFF);
|
||||
}
|
||||
|
||||
public static long readUint32(byte[] b, int offset) {
|
||||
if(b.length < offset + 4) throw new IllegalArgumentException();
|
||||
return ((b[offset] & 0xFFL) << 24) | ((b[offset + 1] & 0xFFL) << 16)
|
||||
|
||||
Reference in New Issue
Block a user