diff --git a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java index 95c0524571cbda43d2851afd543037db2fc1cf42..a2d73e9a39f240feedd6514e5dc95ce64463701c 100644 --- a/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java +++ b/components/net/sf/briar/transport/ConnectionReaderFactoryImpl.java @@ -67,7 +67,7 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory { public ConnectionReader createConnectionReader(SegmentSource in, byte[] secret) { - return createConnectionReader(in, secret, new SegmentImpl(), false); + return createConnectionReader(in, secret, null, false); } private ConnectionReader createConnectionReader(SegmentSource in, diff --git a/components/net/sf/briar/transport/ErasureEncoder.java b/components/net/sf/briar/transport/ErasureEncoder.java new file mode 100644 index 0000000000000000000000000000000000000000..b09fd687cb79916f803bd47be4357d6444866025 --- /dev/null +++ b/components/net/sf/briar/transport/ErasureEncoder.java @@ -0,0 +1,9 @@ +package net.sf.briar.transport; + +import net.sf.briar.api.transport.Segment; + +interface ErasureEncoder { + + /** Encodes the given frame as a set of segments. */ + Segment[] encodeFrame(Frame f); +} diff --git a/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java b/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java index db3ab691d2713d6470bf11550a6fbf387a182a00..d74dd5b5dc045b2c50cff003eaed209af5e3ff6e 100644 --- a/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java +++ b/components/net/sf/briar/transport/IncomingErrorCorrectionLayerImpl.java @@ -34,7 +34,7 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer { // Free any discard counts that are no longer too high for the window Iterator<Long> it1 = discardCounts.keySet().iterator(); while(it1.hasNext()) if(!window.isTooHigh(it1.next())) it1.remove(); - // Allocate a segment + // FIXME: Unnecessary allocation Segment s = new SegmentImpl(); // Read segments until a frame can be decoded while(true) { @@ -51,9 +51,8 @@ class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer { if(set == null) { set = new Segment[n]; segmentSets.put(frameNumber, set); - } else { - set[(int) (frameNumber % n)] = s; } + set[(int) (frameNumber % n)] = s; // Try to decode the frame if(decoder.decodeFrame(f, set)) return true; } diff --git a/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..24168939b68b6cd511108e00aa8103a81561bb85 --- /dev/null +++ b/components/net/sf/briar/transport/OutgoingErrorCorrectionLayerImpl.java @@ -0,0 +1,31 @@ +package net.sf.briar.transport; + +import java.io.IOException; + +import net.sf.briar.api.transport.Segment; + +class OutgoingErrorCorrectionLayerImpl implements OutgoingErrorCorrectionLayer { + + private final OutgoingEncryptionLayer out; + private final ErasureEncoder encoder; + private final int n; + + OutgoingErrorCorrectionLayerImpl(OutgoingEncryptionLayer out, + ErasureEncoder encoder, int n) { + this.out = out; + this.encoder = encoder; + this.n = n; + } + + public void writeFrame(Frame f) throws IOException { + for(Segment s : encoder.encodeFrame(f)) out.writeSegment(s); + } + + public void flush() throws IOException { + out.flush(); + } + + public long getRemainingCapacity() { + return out.getRemainingCapacity() / n; + } +} diff --git a/components/net/sf/briar/transport/SegmentImpl.java b/components/net/sf/briar/transport/SegmentImpl.java index 8cd7acc549b924109a2fd9a35567f7c4647eea1c..991585457303b9c9c32644420c4cfcad5164827c 100644 --- a/components/net/sf/briar/transport/SegmentImpl.java +++ b/components/net/sf/briar/transport/SegmentImpl.java @@ -1,16 +1,24 @@ package net.sf.briar.transport; import static net.sf.briar.api.transport.TransportConstants.MAX_SEGMENT_LENGTH; +import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED; import net.sf.briar.api.transport.Segment; -import net.sf.briar.util.ByteUtils; class SegmentImpl implements Segment { - private final byte[] buf = new byte[MAX_SEGMENT_LENGTH]; + private final byte[] buf; private int length = -1; private long segmentNumber = -1; + SegmentImpl() { + this(MAX_SEGMENT_LENGTH); + } + + SegmentImpl(int length) { + buf = new byte[length]; + } + public byte[] getBuffer() { return buf; } @@ -32,7 +40,7 @@ class SegmentImpl implements Segment { } public void setSegmentNumber(long segmentNumber) { - if(segmentNumber < 0 || segmentNumber > ByteUtils.MAX_32_BIT_UNSIGNED) + if(segmentNumber < 0 || segmentNumber > MAX_32_BIT_UNSIGNED) throw new IllegalArgumentException(); this.segmentNumber = segmentNumber; } diff --git a/components/net/sf/briar/transport/XorErasureDecoder.java b/components/net/sf/briar/transport/XorErasureDecoder.java index 61682185a1673f76f575e50707e6e2f86dd186f5..5c44778bbff196a28a87cee181da0f1668cfaa8e 100644 --- a/components/net/sf/briar/transport/XorErasureDecoder.java +++ b/components/net/sf/briar/transport/XorErasureDecoder.java @@ -1,5 +1,7 @@ package net.sf.briar.transport; +import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH; +import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH; import net.sf.briar.api.FormatException; import net.sf.briar.api.transport.Segment; @@ -54,7 +56,13 @@ class XorErasureDecoder implements ErasureDecoder { assert missingOffset != -1; System.arraycopy(parity, 0, dest, missingOffset, length); } - f.setLength(offset); + assert offset == length * (n - 1); + // The frame length may not be an exact multiple of the segment length + int payload = HeaderEncoder.getPayloadLength(dest); + int padding = HeaderEncoder.getPaddingLength(dest); + int frameLength = FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH; + if(frameLength > MAX_FRAME_LENGTH) throw new FormatException(); + f.setLength(frameLength); return true; } } diff --git a/components/net/sf/briar/transport/XorErasureEncoder.java b/components/net/sf/briar/transport/XorErasureEncoder.java new file mode 100644 index 0000000000000000000000000000000000000000..706f3147f2f1ea48869cb621924c4a1a715578b8 --- /dev/null +++ b/components/net/sf/briar/transport/XorErasureEncoder.java @@ -0,0 +1,30 @@ +package net.sf.briar.transport; + +import net.sf.briar.api.transport.Segment; + +/** An erasure encoder than uses k data segments and one parity segment. */ +class XorErasureEncoder implements ErasureEncoder { + + private final int n; + + XorErasureEncoder(int n) { + this.n = n; + } + + public Segment[] encodeFrame(Frame f) { + Segment[] set = new Segment[n]; + int length = (int) Math.ceil((float) f.getLength() / (n - 1)); + for(int i = 0; i < n; i++) { + set[i] = new SegmentImpl(length); + set[i].setLength(length); + } + byte[] src = f.getBuffer(), parity = set[n - 1].getBuffer(); + int offset = 0; + for(int i = 0; i < n - 1; i++) { + System.arraycopy(src, 0, set[i].getBuffer(), offset, length); + for(int j = 0; j < length; j++) parity[j] ^= src[j]; + offset += length; + } + return set; + } +}