Allow for the maximum overhead when calculating capacity.

This commit is contained in:
akwizgran
2012-08-28 14:22:29 +01:00
parent 521ed076ca
commit a104548f7c
5 changed files with 37 additions and 36 deletions

View File

@@ -1,19 +1,18 @@
package net.sf.briar.api.protocol; package net.sf.briar.api.protocol;
import net.sf.briar.api.transport.TransportConstants; import static net.sf.briar.api.transport.TransportConstants.MIN_CONNECTION_LENGTH;
public interface ProtocolConstants { public interface ProtocolConstants {
/** /**
* The maximum length of a serialised packet in bytes. To allow for future * The maximum length of a serialised packet in bytes. To allow for future
* changes in the protocol, this is smaller than the minimum connection * changes in the protocol, this is smaller than the minimum connection
* length minus the encryption and authentication overhead. * length minus the maximum encryption and authentication overhead.
*/ */
static final int MAX_PACKET_LENGTH = static final int MAX_PACKET_LENGTH = MIN_CONNECTION_LENGTH / 2;
TransportConstants.MIN_CONNECTION_LENGTH - 1024;
/** The maximum number of transports a node may support. */ /** The maximum number of transports a node may support. */
static final int MAX_TRANSPORTS = 50; static final int MAX_TRANSPORTS = 25;
/** The maximum number of properties per transport. */ /** The maximum number of properties per transport. */
static final int MAX_PROPERTIES_PER_TRANSPORT = 100; static final int MAX_PROPERTIES_PER_TRANSPORT = 100;

View File

@@ -35,11 +35,7 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
} }
public long getRemainingCapacity() { public long getRemainingCapacity() {
long capacity = out.getRemainingCapacity(); return out.getRemainingCapacity();
int maxPayloadLength = frameLength - HEADER_LENGTH - MAC_LENGTH;
long frames = (long) Math.ceil((double) capacity / maxPayloadLength);
long overhead = (frames + 1) * (HEADER_LENGTH + MAC_LENGTH);
return capacity - overhead - length;
} }
@Override @Override
@@ -83,12 +79,9 @@ class ConnectionWriterImpl extends OutputStream implements ConnectionWriter {
length += len; length += len;
} }
private void writeFrame(boolean lastFrame) throws IOException { private void writeFrame(boolean finalFrame) throws IOException {
if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException(); if(frameNumber > MAX_32_BIT_UNSIGNED) throw new IllegalStateException();
int capacity = (int) Math.min(frameLength, out.getRemainingCapacity()); out.writeFrame(frame, length, finalFrame);
int paddingLength = capacity - HEADER_LENGTH - length - MAC_LENGTH;
if(paddingLength < 0) throw new IllegalStateException();
out.writeFrame(frame, length, lastFrame ? 0 : paddingLength, lastFrame);
length = 0; length = 0;
frameNumber++; frameNumber++;
} }

View File

@@ -5,8 +5,8 @@ import java.io.IOException;
interface FrameWriter { interface FrameWriter {
/** Writes the given frame. */ /** Writes the given frame. */
void writeFrame(byte[] frame, int payloadLength, int paddingLength, void writeFrame(byte[] frame, int payloadLength, boolean finalFrame)
boolean lastFrame) throws IOException; throws IOException;
/** Flushes the stack. */ /** Flushes the stack. */
void flush() throws IOException; void flush() throws IOException;

View File

@@ -6,6 +6,7 @@ import static net.sf.briar.api.transport.TransportConstants.HEADER_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH; import static net.sf.briar.api.transport.TransportConstants.IV_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH; import static net.sf.briar.api.transport.TransportConstants.MAC_LENGTH;
import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH; import static net.sf.briar.api.transport.TransportConstants.TAG_LENGTH;
import static net.sf.briar.util.ByteUtils.MAX_32_BIT_UNSIGNED;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@@ -33,7 +34,7 @@ class OutgoingEncryptionLayer implements FrameWriter {
AuthenticatedCipher frameCipher, ErasableKey tagKey, AuthenticatedCipher frameCipher, ErasableKey tagKey,
ErasableKey frameKey, int frameLength) { ErasableKey frameKey, int frameLength) {
this.out = out; this.out = out;
this.capacity = capacity - TAG_LENGTH; this.capacity = capacity;
this.tagCipher = tagCipher; this.tagCipher = tagCipher;
this.frameCipher = frameCipher; this.frameCipher = frameCipher;
this.tagKey = tagKey; this.tagKey = tagKey;
@@ -64,17 +65,11 @@ class OutgoingEncryptionLayer implements FrameWriter {
writeTag = false; writeTag = false;
} }
public void writeFrame(byte[] frame, int payloadLength, int paddingLength, public void writeFrame(byte[] frame, int payloadLength, boolean finalFrame)
boolean lastFrame) throws IOException { throws IOException {
int plaintextLength = HEADER_LENGTH + payloadLength + paddingLength;
int ciphertextLength = plaintextLength + MAC_LENGTH;
if(ciphertextLength > frameLength)
throw new IllegalArgumentException();
if(!lastFrame && ciphertextLength < frameLength)
throw new IllegalArgumentException();
// If the initiator's side of the connection is closed without writing // If the initiator's side of the connection is closed without writing
// any payload or padding, don't write a tag or an empty frame // any data, don't write anything to the underlying transport
if(writeTag && lastFrame && payloadLength + paddingLength == 0) return; if(writeTag && finalFrame && payloadLength == 0) return;
// Write the tag if required // Write the tag if required
if(writeTag) { if(writeTag) {
TagEncoder.encodeTag(ciphertext, tagCipher, tagKey); TagEncoder.encodeTag(ciphertext, tagCipher, tagKey);
@@ -85,10 +80,20 @@ class OutgoingEncryptionLayer implements FrameWriter {
tagKey.erase(); tagKey.erase();
throw e; throw e;
} }
capacity -= TAG_LENGTH;
writeTag = false; writeTag = false;
} }
// Encode the header // Encode the header
FrameEncoder.encodeHeader(frame, lastFrame, payloadLength); FrameEncoder.encodeHeader(frame, finalFrame, payloadLength);
// Don't pad the final frame
int plaintextLength, ciphertextLength;
if(finalFrame) {
plaintextLength = HEADER_LENGTH + payloadLength;
ciphertextLength = plaintextLength + MAC_LENGTH;
} else {
plaintextLength = frameLength - MAC_LENGTH;
ciphertextLength = frameLength;
}
// If there's any padding it must all be zeroes // If there's any padding it must all be zeroes
for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++) for(int i = HEADER_LENGTH + payloadLength; i < plaintextLength; i++)
frame[i] = 0; frame[i] = 0;
@@ -120,6 +125,10 @@ class OutgoingEncryptionLayer implements FrameWriter {
} }
public long getRemainingCapacity() { public long getRemainingCapacity() {
return capacity; long capacityExcludingTag = writeTag ? capacity - TAG_LENGTH : capacity;
long frames = capacityExcludingTag / frameLength;
long frameNumbers = MAX_32_BIT_UNSIGNED - frameNumber + 1;
int maxPayloadLength = frameLength - HEADER_LENGTH - MAC_LENGTH;
return maxPayloadLength * Math.min(frames, frameNumbers);
} }
} }

View File

@@ -48,14 +48,14 @@ public class ConnectionWriterTest extends BriarTestCase {
MIN_CONNECTION_LENGTH, secret, true); MIN_CONNECTION_LENGTH, secret, true);
// Check that the connection writer thinks there's room for a packet // Check that the connection writer thinks there's room for a packet
long capacity = w.getRemainingCapacity(); long capacity = w.getRemainingCapacity();
assertTrue(capacity >= MAX_PACKET_LENGTH); assertTrue(capacity > MAX_PACKET_LENGTH);
assertTrue(capacity <= MIN_CONNECTION_LENGTH); assertTrue(capacity < MIN_CONNECTION_LENGTH);
// Check that there really is room for a packet // Check that there really is room for a packet
byte[] payload = new byte[MAX_PACKET_LENGTH]; byte[] payload = new byte[MAX_PACKET_LENGTH];
w.getOutputStream().write(payload); w.getOutputStream().write(payload);
w.getOutputStream().close(); w.getOutputStream().close();
long used = out.size(); long used = out.size();
assertTrue(used >= MAX_PACKET_LENGTH); assertTrue(used > MAX_PACKET_LENGTH);
assertTrue(used <= MIN_CONNECTION_LENGTH); assertTrue(used <= MIN_CONNECTION_LENGTH);
} }
@@ -67,14 +67,14 @@ public class ConnectionWriterTest extends BriarTestCase {
MIN_CONNECTION_LENGTH, secret, false); MIN_CONNECTION_LENGTH, secret, false);
// Check that the connection writer thinks there's room for a packet // Check that the connection writer thinks there's room for a packet
long capacity = w.getRemainingCapacity(); long capacity = w.getRemainingCapacity();
assertTrue(capacity >= MAX_PACKET_LENGTH); assertTrue(capacity > MAX_PACKET_LENGTH);
assertTrue(capacity <= MIN_CONNECTION_LENGTH); assertTrue(capacity < MIN_CONNECTION_LENGTH);
// Check that there really is room for a packet // Check that there really is room for a packet
byte[] payload = new byte[MAX_PACKET_LENGTH]; byte[] payload = new byte[MAX_PACKET_LENGTH];
w.getOutputStream().write(payload); w.getOutputStream().write(payload);
w.getOutputStream().close(); w.getOutputStream().close();
long used = out.size(); long used = out.size();
assertTrue(used >= MAX_PACKET_LENGTH); assertTrue(used > MAX_PACKET_LENGTH);
assertTrue(used <= MIN_CONNECTION_LENGTH); assertTrue(used <= MIN_CONNECTION_LENGTH);
} }
} }