mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Incoming error correction layer (untested).
This commit is contained in:
13
components/net/sf/briar/transport/ErasureDecoder.java
Normal file
13
components/net/sf/briar/transport/ErasureDecoder.java
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
|
import net.sf.briar.api.FormatException;
|
||||||
|
import net.sf.briar.api.transport.Segment;
|
||||||
|
|
||||||
|
interface ErasureDecoder {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decodes the given set of segments into the given frame, or returns false
|
||||||
|
* if the segments cannot be decoded. The segment set may contain nulls.
|
||||||
|
*/
|
||||||
|
public boolean decodeFrame(Frame f, Segment[] set) throws FormatException;
|
||||||
|
}
|
||||||
@@ -6,6 +6,7 @@ import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
/** A frame window that allows a limited amount of reordering. */
|
||||||
class FrameWindowImpl implements FrameWindow {
|
class FrameWindowImpl implements FrameWindow {
|
||||||
|
|
||||||
private final Collection<Long> window;
|
private final Collection<Long> window;
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import net.sf.briar.api.FormatException;
|
||||||
|
import net.sf.briar.api.transport.Segment;
|
||||||
|
|
||||||
|
class IncomingErrorCorrectionLayerImpl implements IncomingErrorCorrectionLayer {
|
||||||
|
|
||||||
|
private final IncomingEncryptionLayer in;
|
||||||
|
private final ErasureDecoder decoder;
|
||||||
|
private final int n, k;
|
||||||
|
private final Map<Long, Integer> discardCounts;
|
||||||
|
private final Map<Long, Segment[]> segmentSets;
|
||||||
|
|
||||||
|
IncomingErrorCorrectionLayerImpl(IncomingEncryptionLayer in,
|
||||||
|
ErasureDecoder decoder, int n, int k) {
|
||||||
|
this.in = in;
|
||||||
|
this.decoder = decoder;
|
||||||
|
this.n = n;
|
||||||
|
this.k = k;
|
||||||
|
discardCounts = new HashMap<Long, Integer>();
|
||||||
|
segmentSets = new HashMap<Long, Segment[]>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean readFrame(Frame f, FrameWindow window) throws IOException,
|
||||||
|
InvalidDataException {
|
||||||
|
// Free any segment sets that have been removed from the window
|
||||||
|
Iterator<Long> it = segmentSets.keySet().iterator();
|
||||||
|
while(it.hasNext()) if(!window.contains(it.next())) it.remove();
|
||||||
|
// 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
|
||||||
|
Segment s = new SegmentImpl();
|
||||||
|
// Read segments until a frame can be decoded
|
||||||
|
while(true) {
|
||||||
|
// Read segments until a segment in the window is returned
|
||||||
|
long frameNumber;
|
||||||
|
while(true) {
|
||||||
|
if(!in.readSegment(s)) return false;
|
||||||
|
frameNumber = s.getSegmentNumber() / n;
|
||||||
|
if(window.contains(frameNumber)) break;
|
||||||
|
if(window.isTooHigh(frameNumber)) countDiscard(frameNumber);
|
||||||
|
}
|
||||||
|
// Add the segment to its segment set, or create one if necessary
|
||||||
|
Segment[] set = segmentSets.get(frameNumber);
|
||||||
|
if(set == null) {
|
||||||
|
set = new Segment[n];
|
||||||
|
segmentSets.put(frameNumber, set);
|
||||||
|
} else {
|
||||||
|
set[(int) (frameNumber % n)] = s;
|
||||||
|
}
|
||||||
|
// Try to decode the frame
|
||||||
|
if(decoder.decodeFrame(f, set)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void countDiscard(long frameNumber) throws FormatException {
|
||||||
|
Integer count = discardCounts.get(frameNumber);
|
||||||
|
if(count == null) discardCounts.put(frameNumber, 1);
|
||||||
|
else if(count == n - k) throw new FormatException();
|
||||||
|
else discardCounts.put(frameNumber, count + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package net.sf.briar.transport;
|
|||||||
|
|
||||||
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
|
||||||
|
|
||||||
|
/** A frame window that does not allow any reordering. */
|
||||||
class NullFrameWindow implements FrameWindow {
|
class NullFrameWindow implements FrameWindow {
|
||||||
|
|
||||||
private long base = 0L;
|
private long base = 0L;
|
||||||
|
|||||||
@@ -14,12 +14,13 @@ class NullIncomingErrorCorrectionLayer implements IncomingErrorCorrectionLayer {
|
|||||||
segment = new SegmentImpl();
|
segment = new SegmentImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean readFrame(Frame f, FrameWindow window)
|
public boolean readFrame(Frame f, FrameWindow window) throws IOException,
|
||||||
throws IOException, InvalidDataException {
|
InvalidDataException {
|
||||||
while(true) {
|
while(true) {
|
||||||
if(!in.readSegment(segment)) return false;
|
if(!in.readSegment(segment)) return false;
|
||||||
byte[] buf = segment.getBuffer();
|
byte[] buf = segment.getBuffer();
|
||||||
if(window.contains(HeaderEncoder.getFrameNumber(buf))) break;
|
long frameNumber = HeaderEncoder.getFrameNumber(buf);
|
||||||
|
if(window.contains(frameNumber)) break;
|
||||||
}
|
}
|
||||||
int length = segment.getLength();
|
int length = segment.getLength();
|
||||||
// FIXME: Unnecessary copy
|
// FIXME: Unnecessary copy
|
||||||
|
|||||||
60
components/net/sf/briar/transport/XorErasureDecoder.java
Normal file
60
components/net/sf/briar/transport/XorErasureDecoder.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
package net.sf.briar.transport;
|
||||||
|
|
||||||
|
import static net.sf.briar.api.transport.TransportConstants.MAX_FRAME_LENGTH;
|
||||||
|
import net.sf.briar.api.FormatException;
|
||||||
|
import net.sf.briar.api.transport.Segment;
|
||||||
|
|
||||||
|
/** An erasure decoder that uses k data segments and one parity segment. */
|
||||||
|
class XorErasureDecoder implements ErasureDecoder {
|
||||||
|
|
||||||
|
private final int n;
|
||||||
|
|
||||||
|
XorErasureDecoder(int n) {
|
||||||
|
this.n = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean decodeFrame(Frame f, Segment[] set) throws FormatException {
|
||||||
|
// We need at least n - 1 pieces
|
||||||
|
int pieces = 0;
|
||||||
|
for(int i = 0; i < n; i++) if(set[i] != null) pieces++;
|
||||||
|
if(pieces < n - 1) return false;
|
||||||
|
// All the pieces must have the same length - take the minimum
|
||||||
|
int length = MAX_FRAME_LENGTH;
|
||||||
|
for(int i = 0; i < n; i++) {
|
||||||
|
if(set[i] == null) {
|
||||||
|
int len = set[i].getLength();
|
||||||
|
if(len < length) length = len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(length * (n - 1) > MAX_FRAME_LENGTH) throw new FormatException();
|
||||||
|
// Decode the frame
|
||||||
|
byte[] dest = f.getBuffer();
|
||||||
|
int offset = 0;
|
||||||
|
if(pieces == n || set[n - 1] == null) {
|
||||||
|
// We don't need no stinkin' parity segment
|
||||||
|
for(int i = 0; i < n - 1; i++) {
|
||||||
|
byte[] src = set[i].getBuffer();
|
||||||
|
System.arraycopy(src, 0, dest, offset, length);
|
||||||
|
offset += length;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Reconstruct the missing segment
|
||||||
|
byte[] parity = new byte[length];
|
||||||
|
int missingOffset = -1;
|
||||||
|
for(int i = 0; i < n; i++) {
|
||||||
|
if(set[i] == null) {
|
||||||
|
missingOffset = offset;
|
||||||
|
} else {
|
||||||
|
byte[] src = set[i].getBuffer();
|
||||||
|
System.arraycopy(src, 0, dest, offset, length);
|
||||||
|
for(int j = 0; j < length; j++) parity[j] ^= src[j];
|
||||||
|
}
|
||||||
|
offset += length;
|
||||||
|
}
|
||||||
|
assert missingOffset != -1;
|
||||||
|
System.arraycopy(parity, 0, dest, missingOffset, length);
|
||||||
|
}
|
||||||
|
f.setLength(offset);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user