mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 14:19:53 +01:00
Allow for the maximum overhead when calculating capacity.
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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++;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user