mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +01:00
Incoming reliability layer with support for reordering (untested).
This commit is contained in:
@@ -55,8 +55,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
||||
new IncomingAuthenticationLayerImpl(correction, mac, macKey);
|
||||
// No reordering or retransmission
|
||||
IncomingReliabilityLayer reliability =
|
||||
new IncomingReliabilityLayerImpl(authentication,
|
||||
new NullFrameWindow());
|
||||
new NullIncomingReliabilityLayer(authentication);
|
||||
// Create the reader - don't tolerate errors
|
||||
return new ConnectionReaderImpl(reliability, false);
|
||||
}
|
||||
@@ -93,8 +92,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
|
||||
new IncomingAuthenticationLayerImpl(correction, mac, macKey);
|
||||
// No reordering or retransmission
|
||||
IncomingReliabilityLayer reliability =
|
||||
new IncomingReliabilityLayerImpl(authentication,
|
||||
new NullFrameWindow());
|
||||
new NullIncomingReliabilityLayer(authentication);
|
||||
// Create the reader - don't tolerate errors
|
||||
return new ConnectionReaderImpl(reliability, false);
|
||||
}
|
||||
|
||||
@@ -12,14 +12,13 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
|
||||
|
||||
private final IncomingReliabilityLayer in;
|
||||
private final boolean tolerateErrors;
|
||||
private final Frame frame;
|
||||
|
||||
private Frame frame;
|
||||
private int offset = 0, length = 0;
|
||||
|
||||
ConnectionReaderImpl(IncomingReliabilityLayer in, boolean tolerateErrors) {
|
||||
this.in = in;
|
||||
this.tolerateErrors = tolerateErrors;
|
||||
frame = new Frame(in.getMaxFrameLength());
|
||||
}
|
||||
|
||||
public InputStream getInputStream() {
|
||||
@@ -28,7 +27,8 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
while(length == 0) if(!readValidFrame()) return -1;
|
||||
if(length == -1) return -1;
|
||||
while(length == 0) if(!readFrame()) return -1;
|
||||
int b = frame.getBuffer()[offset] & 0xff;
|
||||
offset++;
|
||||
length--;
|
||||
@@ -42,7 +42,8 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int off, int len) throws IOException {
|
||||
while(length == 0) if(!readValidFrame()) return -1;
|
||||
if(length == -1) return -1;
|
||||
while(length == 0) if(!readFrame()) return -1;
|
||||
len = Math.min(len, length);
|
||||
System.arraycopy(frame.getBuffer(), offset, b, off, len);
|
||||
offset += len;
|
||||
@@ -50,11 +51,15 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
|
||||
return len;
|
||||
}
|
||||
|
||||
private boolean readValidFrame() throws IOException {
|
||||
private boolean readFrame() throws IOException {
|
||||
assert length == 0;
|
||||
while(true) {
|
||||
try {
|
||||
if(!in.readFrame(frame)) return false;
|
||||
frame = in.readFrame(frame);
|
||||
if(frame == null) {
|
||||
length = -1;
|
||||
return false;
|
||||
}
|
||||
offset = FRAME_HEADER_LENGTH;
|
||||
length = HeaderEncoder.getPayloadLength(frame.getBuffer());
|
||||
return true;
|
||||
|
||||
@@ -26,6 +26,11 @@ class Frame {
|
||||
return buf;
|
||||
}
|
||||
|
||||
public long getFrameNumber() {
|
||||
if(length == -1) throw new IllegalStateException();
|
||||
return HeaderEncoder.getFrameNumber(buf);
|
||||
}
|
||||
|
||||
public int getLength() {
|
||||
if(length == -1) throw new IllegalStateException();
|
||||
return length;
|
||||
|
||||
@@ -5,14 +5,14 @@ import java.io.IOException;
|
||||
interface IncomingReliabilityLayer {
|
||||
|
||||
/**
|
||||
* Reads a frame into the given buffer. Returns false if no more frames
|
||||
* can be read from the connection.
|
||||
* Reads and returns a frame, possibly using the given buffer. Returns null
|
||||
* if no more frames can be read from the connection.
|
||||
* @throws IOException if an unrecoverable error occurs and the connection
|
||||
* must be closed.
|
||||
* @throws InvalidDataException if a recoverable error occurs. The caller
|
||||
* may choose whether to retry the read or close the connection.
|
||||
*/
|
||||
boolean readFrame(Frame f) throws IOException, InvalidDataException;
|
||||
Frame readFrame(Frame f) throws IOException, InvalidDataException;
|
||||
|
||||
/** Returns the maximum length in bytes of the frames this layer returns. */
|
||||
int getMaxFrameLength();
|
||||
|
||||
@@ -1,25 +1,69 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.ListIterator;
|
||||
|
||||
class IncomingReliabilityLayerImpl implements IncomingReliabilityLayer {
|
||||
|
||||
private final IncomingAuthenticationLayer in;
|
||||
private final FrameWindow window;
|
||||
private final int maxFrameLength;
|
||||
private final FrameWindow window;
|
||||
private final LinkedList<Frame> frames;
|
||||
private final ArrayList<Frame> freeFrames;
|
||||
|
||||
IncomingReliabilityLayerImpl(IncomingAuthenticationLayer in,
|
||||
FrameWindow window) {
|
||||
private long nextFrameNumber = 0L;
|
||||
|
||||
IncomingReliabilityLayerImpl(IncomingAuthenticationLayer in) {
|
||||
this.in = in;
|
||||
this.window = window;
|
||||
maxFrameLength = in.getMaxFrameLength();
|
||||
window = new FrameWindowImpl();
|
||||
frames = new LinkedList<Frame>();
|
||||
freeFrames = new ArrayList<Frame>();
|
||||
}
|
||||
|
||||
public boolean readFrame(Frame f) throws IOException, InvalidDataException {
|
||||
if(!in.readFrame(f, window)) return false;
|
||||
long frameNumber = HeaderEncoder.getFrameNumber(f.getBuffer());
|
||||
if(!window.remove(frameNumber)) throw new IllegalStateException();
|
||||
return true;
|
||||
public Frame readFrame(Frame f) throws IOException,
|
||||
InvalidDataException {
|
||||
freeFrames.add(f);
|
||||
// Read frames until there's an in-order frame to return
|
||||
Frame next = frames.peek();
|
||||
while(next == null || next.getFrameNumber() > nextFrameNumber) {
|
||||
// Grab a free frame, or allocate one if necessary
|
||||
int free = freeFrames.size();
|
||||
if(free == 0) f = new Frame(maxFrameLength);
|
||||
else f = freeFrames.remove(free - 1);
|
||||
// Read a frame
|
||||
if(!in.readFrame(f, window)) return null;
|
||||
// If the frame is in order, return it
|
||||
long frameNumber = f.getFrameNumber();
|
||||
if(frameNumber == nextFrameNumber) {
|
||||
nextFrameNumber++;
|
||||
return f;
|
||||
}
|
||||
// Insert the frame into the list
|
||||
if(next == null || next.getFrameNumber() > frameNumber) {
|
||||
frames.push(f);
|
||||
} else {
|
||||
boolean inserted = false;
|
||||
ListIterator<Frame> it = frames.listIterator();
|
||||
while(it.hasNext()) {
|
||||
if(it.next().getFrameNumber() > frameNumber) {
|
||||
// Insert the frame before the one just examined
|
||||
it.previous();
|
||||
it.add(f);
|
||||
inserted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!inserted) frames.add(f);
|
||||
}
|
||||
next = frames.peek();
|
||||
}
|
||||
assert next != null && next.getFrameNumber() == nextFrameNumber;
|
||||
frames.poll();
|
||||
nextFrameNumber++;
|
||||
return next;
|
||||
}
|
||||
|
||||
public int getMaxFrameLength() {
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.sf.briar.transport;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
class NullIncomingReliabilityLayer implements IncomingReliabilityLayer {
|
||||
|
||||
private final IncomingAuthenticationLayer in;
|
||||
private final int maxFrameLength;
|
||||
private final FrameWindow window;
|
||||
|
||||
NullIncomingReliabilityLayer(IncomingAuthenticationLayer in) {
|
||||
this.in = in;
|
||||
maxFrameLength = in.getMaxFrameLength();
|
||||
window = new NullFrameWindow();
|
||||
}
|
||||
|
||||
public Frame readFrame(Frame f) throws IOException, InvalidDataException {
|
||||
if(!in.readFrame(f, window)) return null;
|
||||
if(!window.remove(f.getFrameNumber()))
|
||||
throw new IllegalStateException();
|
||||
return f;
|
||||
}
|
||||
|
||||
public int getMaxFrameLength() {
|
||||
return maxFrameLength;
|
||||
}
|
||||
}
|
||||
@@ -224,8 +224,7 @@ public class ConnectionReaderImplTest extends TransportTest {
|
||||
IncomingAuthenticationLayer authentication =
|
||||
new IncomingAuthenticationLayerImpl(correction, mac, macKey);
|
||||
IncomingReliabilityLayer reliability =
|
||||
new IncomingReliabilityLayerImpl(authentication,
|
||||
new NullFrameWindow());
|
||||
new NullIncomingReliabilityLayer(authentication);
|
||||
return new ConnectionReaderImpl(reliability, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,8 +103,7 @@ public class FrameReadWriteTest extends BriarTestCase {
|
||||
IncomingAuthenticationLayer authenticationIn =
|
||||
new IncomingAuthenticationLayerImpl(correctionIn, mac, macKey);
|
||||
IncomingReliabilityLayer reliabilityIn =
|
||||
new IncomingReliabilityLayerImpl(authenticationIn,
|
||||
new NullFrameWindow());
|
||||
new NullIncomingReliabilityLayer(authenticationIn);
|
||||
ConnectionReader reader = new ConnectionReaderImpl(reliabilityIn,
|
||||
false);
|
||||
InputStream in1 = reader.getInputStream();
|
||||
|
||||
Reference in New Issue
Block a user