Make room for the ack header.

This commit is contained in:
akwizgran
2012-01-24 09:28:28 +00:00
parent ffe3bafce4
commit 3d4b5e6282
21 changed files with 100 additions and 66 deletions

View File

@@ -45,19 +45,20 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
Cipher tagCipher = crypto.getTagCipher();
Cipher segCipher = crypto.getSegmentCipher();
IncomingEncryptionLayer encryption = new IncomingEncryptionLayerImpl(in,
tagCipher, segCipher, tagKey, segKey, false, bufferedTag);
tagCipher, segCipher, tagKey, segKey, false, false,
bufferedTag);
// No error correction
IncomingErrorCorrectionLayer correction =
new NullIncomingErrorCorrectionLayer(encryption);
// Create the authenticator
Mac mac = crypto.getMac();
IncomingAuthenticationLayer authentication =
new IncomingAuthenticationLayerImpl(correction, mac, macKey);
new IncomingAuthenticationLayerImpl(correction, mac, macKey, false);
// No reordering or retransmission
IncomingReliabilityLayer reliability =
new NullIncomingReliabilityLayer(authentication);
// Create the reader - don't tolerate errors
return new ConnectionReaderImpl(reliability, false);
return new ConnectionReaderImpl(reliability, false, false);
}
public ConnectionReader createConnectionReader(SegmentSource in,
@@ -82,18 +83,18 @@ class ConnectionReaderFactoryImpl implements ConnectionReaderFactory {
Cipher segCipher = crypto.getSegmentCipher();
IncomingEncryptionLayer encryption =
new SegmentedIncomingEncryptionLayer(in, tagCipher, segCipher,
tagKey, segKey, false, bufferedSegment);
tagKey, segKey, false, false, bufferedSegment);
// No error correction
IncomingErrorCorrectionLayer correction =
new NullIncomingErrorCorrectionLayer(encryption);
// Create the authenticator
Mac mac = crypto.getMac();
IncomingAuthenticationLayer authentication =
new IncomingAuthenticationLayerImpl(correction, mac, macKey);
new IncomingAuthenticationLayerImpl(correction, mac, macKey, false);
// No reordering or retransmission
IncomingReliabilityLayer reliability =
new NullIncomingReliabilityLayer(authentication);
// Create the reader - don't tolerate errors
return new ConnectionReaderImpl(reliability, false);
return new ConnectionReaderImpl(reliability, false, false);
}
}

View File

@@ -1,5 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.ACK_HEADER_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
import java.io.IOException;
@@ -12,13 +13,17 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
private final IncomingReliabilityLayer in;
private final boolean tolerateErrors;
private final int headerLength;
private Frame frame;
private int offset = 0, length = 0;
ConnectionReaderImpl(IncomingReliabilityLayer in, boolean tolerateErrors) {
ConnectionReaderImpl(IncomingReliabilityLayer in, boolean tolerateErrors,
boolean ackHeader) {
this.in = in;
this.tolerateErrors = tolerateErrors;
if(ackHeader) headerLength = FRAME_HEADER_LENGTH + ACK_HEADER_LENGTH;
else headerLength = FRAME_HEADER_LENGTH;
frame = new Frame(in.getMaxFrameLength());
}
@@ -61,7 +66,7 @@ class ConnectionReaderImpl extends InputStream implements ConnectionReader {
length = -1;
return false;
}
offset = FRAME_HEADER_LENGTH;
offset = headerLength;
length = HeaderEncoder.getPayloadLength(frame.getBuffer());
return true;
} catch(InvalidDataException e) {

View File

@@ -46,7 +46,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
OutgoingReliabilityLayer reliability =
new NullOutgoingReliabilityLayer(authentication);
// Create the writer
return new ConnectionWriterImpl(reliability);
return new ConnectionWriterImpl(reliability, false);
}
public ConnectionWriter createConnectionWriter(SegmentSink out,
@@ -61,7 +61,7 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
Cipher segCipher = crypto.getSegmentCipher();
OutgoingEncryptionLayer encryption =
new SegmentedOutgoingEncryptionLayer(out, capacity, tagCipher,
segCipher, tagKey, segKey, false);
segCipher, tagKey, segKey, false, false);
// No error correction
OutgoingErrorCorrectionLayer correction =
new NullOutgoingErrorCorrectionLayer(encryption);
@@ -73,6 +73,6 @@ class ConnectionWriterFactoryImpl implements ConnectionWriterFactory {
OutgoingReliabilityLayer reliability =
new NullOutgoingReliabilityLayer(authentication);
// Create the writer
return new ConnectionWriterImpl(reliability);
return new ConnectionWriterImpl(reliability, false);
}
}

View File

@@ -1,5 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.ACK_HEADER_LENGTH;
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.util.ByteUtils.MAX_32_BIT_UNSIGNED;
@@ -18,16 +19,20 @@ import net.sf.briar.api.transport.ConnectionWriter;
class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
private final OutgoingReliabilityLayer out;
private final int maxFrameLength;
private final int headerLength, maxFrameLength;
private final Frame frame;
private int offset = FRAME_HEADER_LENGTH;
private long frameNumber = 0L;
private int offset;
private long frameNumber;
ConnectionWriterImpl(OutgoingReliabilityLayer out) {
ConnectionWriterImpl(OutgoingReliabilityLayer out, boolean ackHeader) {
this.out = out;
if(ackHeader) headerLength = FRAME_HEADER_LENGTH + ACK_HEADER_LENGTH;
else headerLength = FRAME_HEADER_LENGTH;
maxFrameLength = out.getMaxFrameLength();
frame = new Frame(maxFrameLength);
offset = headerLength;
frameNumber = 0L;
}
public OutputStream getOutputStream() {
@@ -37,17 +42,16 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
public long getRemainingCapacity() {
long capacity = out.getRemainingCapacity();
// If there's any data buffered, subtract it and its overhead
if(offset > FRAME_HEADER_LENGTH)
capacity -= offset + MAC_LENGTH;
if(offset > headerLength) capacity -= offset + MAC_LENGTH;
// Subtract the overhead from the remaining capacity
long frames = (long) Math.ceil((double) capacity / maxFrameLength);
int overheadPerFrame = FRAME_HEADER_LENGTH + MAC_LENGTH;
int overheadPerFrame = headerLength + MAC_LENGTH;
return Math.max(0L, capacity - frames * overheadPerFrame);
}
@Override
public void flush() throws IOException {
if(offset > FRAME_HEADER_LENGTH) writeFrame();
if(offset > headerLength) writeFrame();
out.flush();
}
@@ -80,12 +84,12 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
private void writeFrame() throws IOException {
if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
int payload = offset - FRAME_HEADER_LENGTH;
int payload = offset - headerLength;
assert payload > 0;
HeaderEncoder.encodeHeader(frame.getBuffer(), frameNumber, payload, 0);
frame.setLength(offset + MAC_LENGTH);
out.writeFrame(frame);
offset = FRAME_HEADER_LENGTH;
offset = headerLength;
frameNumber++;
}
}

View File

@@ -37,7 +37,7 @@ class Frame {
}
public void setLength(int length) {
if(length < 0 || length > buf.length)
if(length < FRAME_HEADER_LENGTH + MAC_LENGTH || length > buf.length)
throw new IllegalArgumentException();
this.length = length;
}

View File

@@ -1,5 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.ACK_HEADER_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.FRAME_HEADER_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
@@ -13,11 +14,11 @@ import net.sf.briar.api.crypto.ErasableKey;
class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer {
private final IncomingErrorCorrectionLayer in;
private final int maxFrameLength;
private final Mac mac;
private final int headerLength, maxFrameLength;
IncomingAuthenticationLayerImpl(IncomingErrorCorrectionLayer in, Mac mac,
ErasableKey macKey) {
ErasableKey macKey, boolean ackHeader) {
this.in = in;
this.mac = mac;
try {
@@ -28,6 +29,8 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer {
macKey.erase();
if(mac.getMacLength() != MAC_LENGTH)
throw new IllegalArgumentException();
if(ackHeader) headerLength = FRAME_HEADER_LENGTH + ACK_HEADER_LENGTH;
else headerLength = FRAME_HEADER_LENGTH;
maxFrameLength = in.getMaxFrameLength();
}
@@ -37,22 +40,22 @@ class IncomingAuthenticationLayerImpl implements IncomingAuthenticationLayer {
if(!in.readFrame(f, window)) return false;
// Check that the length is legal
int length = f.getLength();
if(length < FRAME_HEADER_LENGTH + MAC_LENGTH)
if(length < headerLength + MAC_LENGTH)
throw new InvalidDataException();
if(length > maxFrameLength) throw new InvalidDataException();
// Check that the payload and padding lengths are correct
byte[] buf = f.getBuffer();
int payload = HeaderEncoder.getPayloadLength(buf);
int padding = HeaderEncoder.getPaddingLength(buf);
if(length != FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH)
if(length != headerLength + payload + padding + MAC_LENGTH)
throw new InvalidDataException();
// Check that the padding is all zeroes
int paddingStart = FRAME_HEADER_LENGTH + payload;
int paddingStart = headerLength + payload;
for(int i = paddingStart; i < paddingStart + padding; i++) {
if(buf[i] != 0) throw new InvalidDataException();
}
// Verify the MAC
int macStart = FRAME_HEADER_LENGTH + payload + padding;
int macStart = headerLength + payload + padding;
mac.update(buf, 0, macStart);
byte[] expectedMac = mac.doFinal();
for(int i = 0; i < expectedMac.length; i++) {

View File

@@ -1,5 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.ACK_HEADER_LENGTH;
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;
@@ -24,7 +25,7 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
private final Cipher tagCipher, segCipher;
private final ErasableKey tagKey, segKey;
private final boolean tagEverySegment;
private final int blockSize;
private final int headerLength, blockSize;
private final byte[] iv, ciphertext;
private byte[] bufferedTag;
@@ -33,7 +34,7 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
IncomingEncryptionLayerImpl(InputStream in, Cipher tagCipher,
Cipher segCipher, ErasableKey tagKey, ErasableKey segKey,
boolean tagEverySegment, byte[] bufferedTag) {
boolean tagEverySegment, boolean ackHeader, byte[] bufferedTag) {
this.in = in;
this.tagCipher = tagCipher;
this.segCipher = segCipher;
@@ -41,6 +42,8 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
this.segKey = segKey;
this.tagEverySegment = tagEverySegment;
this.bufferedTag = bufferedTag;
if(ackHeader) headerLength = FRAME_HEADER_LENGTH + ACK_HEADER_LENGTH;
else headerLength = FRAME_HEADER_LENGTH;
blockSize = segCipher.getBlockSize();
if(blockSize < FRAME_HEADER_LENGTH)
throw new IllegalArgumentException();
@@ -102,7 +105,7 @@ class IncomingEncryptionLayerImpl implements IncomingEncryptionLayer {
// Parse the frame header
int payload = HeaderEncoder.getPayloadLength(plaintext);
int padding = HeaderEncoder.getPaddingLength(plaintext);
int length = FRAME_HEADER_LENGTH + payload + padding + MAC_LENGTH;
int length = headerLength + payload + padding + MAC_LENGTH;
if(length > MAX_FRAME_LENGTH) throw new FormatException();
// Read the remainder of the frame
while(offset < length) {

View File

@@ -39,7 +39,7 @@ class SegmentImpl implements Segment {
}
public void setLength(int length) {
if(length < 0 || length > buf.length)
if(length < FRAME_HEADER_LENGTH + MAC_LENGTH || length > buf.length)
throw new IllegalArgumentException();
this.length = length;
}

View File

@@ -1,5 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.ACK_HEADER_LENGTH;
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_SEGMENT_LENGTH;
@@ -21,7 +22,7 @@ class SegmentedIncomingEncryptionLayer implements IncomingEncryptionLayer {
private final Cipher tagCipher, segCipher;
private final ErasableKey tagKey, segKey;
private final boolean tagEverySegment;
private final int blockSize, maxSegmentLength;
private final int blockSize, headerLength, maxSegmentLength;
private final Segment segment;
private final byte[] iv;
@@ -31,7 +32,8 @@ class SegmentedIncomingEncryptionLayer implements IncomingEncryptionLayer {
SegmentedIncomingEncryptionLayer(SegmentSource in, Cipher tagCipher,
Cipher segCipher, ErasableKey tagKey, ErasableKey segKey,
boolean tagEverySegment, Segment bufferedSegment) {
boolean tagEverySegment, boolean ackHeader,
Segment bufferedSegment) {
this.in = in;
this.tagCipher = tagCipher;
this.segCipher = segCipher;
@@ -42,8 +44,10 @@ class SegmentedIncomingEncryptionLayer implements IncomingEncryptionLayer {
blockSize = segCipher.getBlockSize();
if(blockSize < FRAME_HEADER_LENGTH)
throw new IllegalArgumentException();
if(ackHeader) headerLength = FRAME_HEADER_LENGTH + ACK_HEADER_LENGTH;
else headerLength = FRAME_HEADER_LENGTH;
int length = in.getMaxSegmentLength();
if(length < TAG_LENGTH + FRAME_HEADER_LENGTH + 1 + MAC_LENGTH)
if(length < TAG_LENGTH + headerLength + 1 + MAC_LENGTH)
throw new IllegalArgumentException();
if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException();
maxSegmentLength = length - TAG_LENGTH;
@@ -67,7 +71,7 @@ class SegmentedIncomingEncryptionLayer implements IncomingEncryptionLayer {
}
int offset = expectTag ? TAG_LENGTH : 0;
int length = segment.getLength();
if(length < offset + FRAME_HEADER_LENGTH + MAC_LENGTH)
if(length < offset + headerLength + MAC_LENGTH)
throw new InvalidDataException();
if(length > offset + maxSegmentLength)
throw new InvalidDataException();

View File

@@ -1,5 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.ACK_HEADER_LENGTH;
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_SEGMENT_LENGTH;
@@ -21,7 +22,7 @@ class SegmentedOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
private final Cipher tagCipher, segCipher;
private final ErasableKey tagKey, segKey;
private final boolean tagEverySegment;
private final int maxSegmentLength;
private final int headerLength, maxSegmentLength;
private final Segment segment;
private final byte[] iv;
@@ -29,7 +30,7 @@ class SegmentedOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
SegmentedOutgoingEncryptionLayer(SegmentSink out, long capacity,
Cipher tagCipher, Cipher segCipher, ErasableKey tagKey,
ErasableKey segKey, boolean tagEverySegment) {
ErasableKey segKey, boolean tagEverySegment, boolean ackHeader) {
this.out = out;
this.capacity = capacity;
this.tagCipher = tagCipher;
@@ -37,10 +38,12 @@ class SegmentedOutgoingEncryptionLayer implements OutgoingEncryptionLayer {
this.tagKey = tagKey;
this.segKey = segKey;
this.tagEverySegment = tagEverySegment;
if(ackHeader) headerLength = FRAME_HEADER_LENGTH + ACK_HEADER_LENGTH;
else headerLength = FRAME_HEADER_LENGTH;
int length = out.getMaxSegmentLength();
if(length < TAG_LENGTH + FRAME_HEADER_LENGTH + 1 + MAC_LENGTH)
throw new RuntimeException();
if(length > MAX_SEGMENT_LENGTH) throw new RuntimeException();
if(length < TAG_LENGTH + headerLength + 1 + MAC_LENGTH)
throw new IllegalArgumentException();
if(length > MAX_SEGMENT_LENGTH) throw new IllegalArgumentException();
maxSegmentLength = length - MAC_LENGTH;
segment = new SegmentImpl(length);
iv = IvEncoder.encodeIv(0L, segCipher.getBlockSize());

View File

@@ -1,5 +1,6 @@
package net.sf.briar.transport;
import static net.sf.briar.api.transport.TransportConstants.ACK_HEADER_LENGTH;
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;
@@ -9,10 +10,12 @@ 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;
private final int n, headerLength;
XorErasureDecoder(int n) {
XorErasureDecoder(int n, boolean ackHeader) {
this.n = n;
if(ackHeader) headerLength = FRAME_HEADER_LENGTH + ACK_HEADER_LENGTH;
else headerLength = FRAME_HEADER_LENGTH;
}
public boolean decodeFrame(Frame f, Segment[] set) throws FormatException {
@@ -61,10 +64,10 @@ class XorErasureDecoder implements ErasureDecoder {
int copyLength = Math.min(length, dest.length - missingOffset);
System.arraycopy(parity, 0, dest, missingOffset, copyLength);
}
// The frame length may not be an exact multiple of the segment length
// The frame length might 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;
int frameLength = headerLength + payload + padding + MAC_LENGTH;
if(frameLength > MAX_FRAME_LENGTH) throw new FormatException();
f.setLength(frameLength);
return true;