mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Expose serialisation overhead without breaking encapsulation.
This commit is contained in:
@@ -5,9 +5,6 @@ import java.util.Collection;
|
||||
/** A packet acknowledging receipt of one or more batches. */
|
||||
public interface Ack {
|
||||
|
||||
/** The maximum number of batch IDs per ack. */
|
||||
static final int MAX_IDS_PER_ACK = 29959;
|
||||
|
||||
/** Returns the IDs of the acknowledged batches. */
|
||||
Collection<BatchId> getBatchIds();
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@ import java.util.Collection;
|
||||
/** A packet offering the recipient some messages. */
|
||||
public interface Offer {
|
||||
|
||||
/** The maximum number of message IDs per offer. */
|
||||
static final int MAX_IDS_PER_OFFER = 29959;
|
||||
|
||||
/** Returns the message IDs contained in the offer. */
|
||||
Collection<MessageId> getMessageIds();
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import java.util.Map;
|
||||
public interface SubscriptionUpdate {
|
||||
|
||||
/** The maximum number of subscriptions per update. */
|
||||
static final int MAX_SUBS_PER_UPDATE = 6393;
|
||||
static final int MAX_SUBS_PER_UPDATE = 6000;
|
||||
|
||||
/** Returns the subscriptions contained in the update. */
|
||||
Map<Group, Long> getSubscriptions();
|
||||
|
||||
12
api/net/sf/briar/api/serial/SerialComponent.java
Normal file
12
api/net/sf/briar/api/serial/SerialComponent.java
Normal file
@@ -0,0 +1,12 @@
|
||||
package net.sf.briar.api.serial;
|
||||
|
||||
public interface SerialComponent {
|
||||
|
||||
int getSerialisedListEndLength();
|
||||
|
||||
int getSerialisedListStartLength();
|
||||
|
||||
int getSerialisedUniqueIdLength(int id);
|
||||
|
||||
int getSerialisedUserDefinedIdLength(int id);
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package net.sf.briar.protocol;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.BatchId;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
@@ -31,7 +30,6 @@ class AckReader implements ObjectReader<Ack> {
|
||||
r.readUserDefinedId(Types.ACK);
|
||||
r.addObjectReader(Types.BATCH_ID, batchIdReader);
|
||||
Collection<BatchId> batches = r.readList(BatchId.class);
|
||||
if(batches.size() > Ack.MAX_IDS_PER_ACK) throw new FormatException();
|
||||
r.removeObjectReader(Types.BATCH_ID);
|
||||
r.removeConsumer(counting);
|
||||
// Build and return the ack
|
||||
|
||||
@@ -3,7 +3,6 @@ package net.sf.briar.protocol;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
||||
import net.sf.briar.api.FormatException;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
@@ -32,8 +31,6 @@ class OfferReader implements ObjectReader<Offer> {
|
||||
r.readUserDefinedId(Types.OFFER);
|
||||
r.addObjectReader(Types.MESSAGE_ID, messageIdReader);
|
||||
Collection<MessageId> messages = r.readList(MessageId.class);
|
||||
if(messages.size() > Offer.MAX_IDS_PER_OFFER)
|
||||
throw new FormatException();
|
||||
r.removeObjectReader(Types.MESSAGE_ID);
|
||||
r.removeConsumer(counting);
|
||||
// Build and return the offer
|
||||
|
||||
@@ -3,46 +3,53 @@ package net.sf.briar.protocol.writers;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.BatchId;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.AckWriter;
|
||||
import net.sf.briar.api.serial.SerialComponent;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
class AckWriterImpl implements AckWriter {
|
||||
|
||||
private final OutputStream out;
|
||||
private final SerialComponent serial;
|
||||
private final Writer w;
|
||||
|
||||
private boolean started = false;
|
||||
private int idsWritten = 0;
|
||||
private int capacity = ProtocolConstants.MAX_PACKET_LENGTH; // FIXME
|
||||
|
||||
AckWriterImpl(OutputStream out, WriterFactory writerFactory) {
|
||||
AckWriterImpl(OutputStream out, SerialComponent serial,
|
||||
WriterFactory writerFactory) {
|
||||
this.out = out;
|
||||
this.serial = serial;
|
||||
w = writerFactory.createWriter(out);
|
||||
}
|
||||
|
||||
public boolean writeBatchId(BatchId b) throws IOException {
|
||||
if(!started) {
|
||||
w.writeUserDefinedTag(Types.ACK);
|
||||
w.writeListStart();
|
||||
started = true;
|
||||
}
|
||||
if(idsWritten >= Ack.MAX_IDS_PER_ACK) return false;
|
||||
if(!started) start();
|
||||
int length = serial.getSerialisedUniqueIdLength(Types.BATCH_ID);
|
||||
if(capacity < length + serial.getSerialisedListEndLength())
|
||||
return false;
|
||||
b.writeTo(w);
|
||||
idsWritten++;
|
||||
capacity -= length;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void finish() throws IOException {
|
||||
if(!started) {
|
||||
w.writeUserDefinedTag(Types.ACK);
|
||||
w.writeListStart();
|
||||
started = true;
|
||||
}
|
||||
if(!started) start();
|
||||
w.writeListEnd();
|
||||
out.flush();
|
||||
capacity = ProtocolConstants.MAX_PACKET_LENGTH; // FIXME
|
||||
started = false;
|
||||
}
|
||||
|
||||
private void start() throws IOException {
|
||||
w.writeUserDefinedTag(Types.ACK);
|
||||
capacity -= serial.getSerialisedUserDefinedIdLength(Types.ACK);
|
||||
w.writeListStart();
|
||||
capacity -= serial.getSerialisedListStartLength();
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,50 +9,53 @@ import net.sf.briar.api.protocol.BatchId;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.BatchWriter;
|
||||
import net.sf.briar.api.serial.SerialComponent;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
class BatchWriterImpl implements BatchWriter {
|
||||
|
||||
private final DigestOutputStream out;
|
||||
private final SerialComponent serial;
|
||||
private final Writer w;
|
||||
private final MessageDigest messageDigest;
|
||||
|
||||
private boolean started = false;
|
||||
private int capacity = ProtocolConstants.MAX_PACKET_LENGTH; // FIXME
|
||||
|
||||
BatchWriterImpl(OutputStream out, WriterFactory writerFactory,
|
||||
MessageDigest messageDigest) {
|
||||
BatchWriterImpl(OutputStream out, SerialComponent serial,
|
||||
WriterFactory writerFactory, MessageDigest messageDigest) {
|
||||
this.out = new DigestOutputStream(out, messageDigest);
|
||||
this.serial = serial;
|
||||
w = writerFactory.createWriter(this.out);
|
||||
this.messageDigest = messageDigest;
|
||||
}
|
||||
|
||||
public boolean writeMessage(byte[] message) throws IOException {
|
||||
if(!started) {
|
||||
messageDigest.reset();
|
||||
w.writeUserDefinedTag(Types.BATCH);
|
||||
w.writeListStart();
|
||||
started = true;
|
||||
}
|
||||
// Allow one byte for the list end tag
|
||||
int capacity = ProtocolConstants.MAX_PACKET_LENGTH
|
||||
- (int) w.getBytesWritten() - 1;
|
||||
if(capacity < message.length) return false;
|
||||
// Bypass the writer and write each raw message directly
|
||||
if(!started) start();
|
||||
if(capacity < message.length + serial.getSerialisedListEndLength())
|
||||
return false;
|
||||
// Bypass the writer and write the raw message directly
|
||||
out.write(message);
|
||||
capacity -= message.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
public BatchId finish() throws IOException {
|
||||
if(!started) {
|
||||
messageDigest.reset();
|
||||
w.writeUserDefinedTag(Types.BATCH);
|
||||
w.writeListStart();
|
||||
started = true;
|
||||
}
|
||||
if(!started) start();
|
||||
w.writeListEnd();
|
||||
out.flush();
|
||||
capacity = ProtocolConstants.MAX_PACKET_LENGTH; // FIXME
|
||||
started = false;
|
||||
return new BatchId(messageDigest.digest());
|
||||
}
|
||||
|
||||
private void start() throws IOException {
|
||||
messageDigest.reset();
|
||||
w.writeUserDefinedTag(Types.BATCH);
|
||||
capacity -= serial.getSerialisedUserDefinedIdLength(Types.BATCH);
|
||||
w.writeListStart();
|
||||
capacity -= serial.getSerialisedListStartLength();
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,45 +4,50 @@ import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.Types;
|
||||
import net.sf.briar.api.protocol.writers.OfferWriter;
|
||||
import net.sf.briar.api.serial.SerialComponent;
|
||||
import net.sf.briar.api.serial.Writer;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
class OfferWriterImpl implements OfferWriter {
|
||||
|
||||
private final OutputStream out;
|
||||
private final SerialComponent serial;
|
||||
private final Writer w;
|
||||
|
||||
private boolean started = false;
|
||||
private int idsWritten = 0;
|
||||
private int capacity = ProtocolConstants.MAX_PACKET_LENGTH; // FIXME
|
||||
|
||||
OfferWriterImpl(OutputStream out, WriterFactory writerFactory) {
|
||||
OfferWriterImpl(OutputStream out, SerialComponent serial,
|
||||
WriterFactory writerFactory) {
|
||||
this.out = out;
|
||||
this.serial = serial;
|
||||
w = writerFactory.createWriter(out);
|
||||
}
|
||||
|
||||
public boolean writeMessageId(MessageId m) throws IOException {
|
||||
if(!started) {
|
||||
w.writeUserDefinedTag(Types.OFFER);
|
||||
w.writeListStart();
|
||||
started = true;
|
||||
}
|
||||
if(idsWritten >= Offer.MAX_IDS_PER_OFFER) return false;
|
||||
if(!started) start();
|
||||
int length = serial.getSerialisedUniqueIdLength(Types.MESSAGE_ID);
|
||||
if(capacity < length + serial.getSerialisedListEndLength())
|
||||
return false;
|
||||
m.writeTo(w);
|
||||
idsWritten++;
|
||||
capacity -= length;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void finish() throws IOException {
|
||||
if(!started) {
|
||||
w.writeUserDefinedTag(Types.OFFER);
|
||||
w.writeListStart();
|
||||
started = true;
|
||||
}
|
||||
if(!started) start();
|
||||
w.writeListEnd();
|
||||
out.flush();
|
||||
capacity = ProtocolConstants.MAX_PACKET_LENGTH; // FIXME
|
||||
started = false;
|
||||
}
|
||||
|
||||
private void start() throws IOException {
|
||||
w.writeUserDefinedTag(Types.OFFER);
|
||||
w.writeListStart();
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
|
||||
import net.sf.briar.api.protocol.writers.RequestWriter;
|
||||
import net.sf.briar.api.protocol.writers.SubscriptionWriter;
|
||||
import net.sf.briar.api.protocol.writers.TransportWriter;
|
||||
import net.sf.briar.api.serial.SerialComponent;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
@@ -18,25 +19,27 @@ import com.google.inject.Inject;
|
||||
class ProtocolWriterFactoryImpl implements ProtocolWriterFactory {
|
||||
|
||||
private final MessageDigest messageDigest;
|
||||
private final SerialComponent serial;
|
||||
private final WriterFactory writerFactory;
|
||||
|
||||
@Inject
|
||||
ProtocolWriterFactoryImpl(CryptoComponent crypto,
|
||||
WriterFactory writerFactory) {
|
||||
SerialComponent serial, WriterFactory writerFactory) {
|
||||
messageDigest = crypto.getMessageDigest();
|
||||
this.serial = serial;
|
||||
this.writerFactory = writerFactory;
|
||||
}
|
||||
|
||||
public AckWriter createAckWriter(OutputStream out) {
|
||||
return new AckWriterImpl(out, writerFactory);
|
||||
return new AckWriterImpl(out, serial, writerFactory);
|
||||
}
|
||||
|
||||
public BatchWriter createBatchWriter(OutputStream out) {
|
||||
return new BatchWriterImpl(out, writerFactory, messageDigest);
|
||||
return new BatchWriterImpl(out, serial, writerFactory, messageDigest);
|
||||
}
|
||||
|
||||
public OfferWriter createOfferWriter(OutputStream out) {
|
||||
return new OfferWriterImpl(out, writerFactory);
|
||||
return new OfferWriterImpl(out, serial, writerFactory);
|
||||
}
|
||||
|
||||
public RequestWriter createRequestWriter(OutputStream out) {
|
||||
|
||||
34
components/net/sf/briar/serial/SerialComponentImpl.java
Normal file
34
components/net/sf/briar/serial/SerialComponentImpl.java
Normal file
@@ -0,0 +1,34 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import net.sf.briar.api.protocol.UniqueId;
|
||||
import net.sf.briar.api.serial.SerialComponent;
|
||||
|
||||
class SerialComponentImpl implements SerialComponent {
|
||||
|
||||
public int getSerialisedListEndLength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getSerialisedListStartLength() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int getSerialisedUniqueIdLength(int id) {
|
||||
// User-defined ID, BYTES tag, length spec, bytes
|
||||
return getSerialisedUserDefinedIdLength(id) + 1 +
|
||||
getSerialisedLengthSpecLength(UniqueId.LENGTH) +
|
||||
UniqueId.LENGTH;
|
||||
}
|
||||
|
||||
private int getSerialisedLengthSpecLength(int length) {
|
||||
assert length >= 0;
|
||||
if(length < 128) return 1; // Uint7
|
||||
if(length < Short.MAX_VALUE) return 3; // Int16
|
||||
return 5; // Int32
|
||||
}
|
||||
|
||||
public int getSerialisedUserDefinedIdLength(int id) {
|
||||
assert id >= 0 && id <= 255;
|
||||
return id < 32 ? 1 : 2;
|
||||
}
|
||||
}
|
||||
@@ -1,15 +1,19 @@
|
||||
package net.sf.briar.serial;
|
||||
|
||||
import net.sf.briar.api.serial.ReaderFactory;
|
||||
import net.sf.briar.api.serial.SerialComponent;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
|
||||
import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Singleton;
|
||||
|
||||
public class SerialModule extends AbstractModule {
|
||||
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(ReaderFactory.class).to(ReaderFactoryImpl.class);
|
||||
bind(SerialComponent.class).to(SerialComponentImpl.class).in(
|
||||
Singleton.class);
|
||||
bind(WriterFactory.class).to(WriterFactoryImpl.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import java.util.Map;
|
||||
import junit.framework.TestCase;
|
||||
import net.sf.briar.TestUtils;
|
||||
import net.sf.briar.api.crypto.CryptoComponent;
|
||||
import net.sf.briar.api.protocol.Ack;
|
||||
import net.sf.briar.api.protocol.Author;
|
||||
import net.sf.briar.api.protocol.AuthorFactory;
|
||||
import net.sf.briar.api.protocol.BatchId;
|
||||
@@ -17,7 +16,6 @@ import net.sf.briar.api.protocol.GroupFactory;
|
||||
import net.sf.briar.api.protocol.Message;
|
||||
import net.sf.briar.api.protocol.MessageEncoder;
|
||||
import net.sf.briar.api.protocol.MessageId;
|
||||
import net.sf.briar.api.protocol.Offer;
|
||||
import net.sf.briar.api.protocol.ProtocolConstants;
|
||||
import net.sf.briar.api.protocol.SubscriptionUpdate;
|
||||
import net.sf.briar.api.protocol.TransportUpdate;
|
||||
@@ -27,6 +25,7 @@ import net.sf.briar.api.protocol.writers.BatchWriter;
|
||||
import net.sf.briar.api.protocol.writers.OfferWriter;
|
||||
import net.sf.briar.api.protocol.writers.SubscriptionWriter;
|
||||
import net.sf.briar.api.protocol.writers.TransportWriter;
|
||||
import net.sf.briar.api.serial.SerialComponent;
|
||||
import net.sf.briar.api.serial.WriterFactory;
|
||||
import net.sf.briar.crypto.CryptoModule;
|
||||
import net.sf.briar.protocol.ProtocolModule;
|
||||
@@ -41,6 +40,7 @@ public class ConstantsTest extends TestCase {
|
||||
|
||||
private final WriterFactory writerFactory;
|
||||
private final CryptoComponent crypto;
|
||||
private final SerialComponent serial;
|
||||
private final GroupFactory groupFactory;
|
||||
private final AuthorFactory authorFactory;
|
||||
private final MessageEncoder messageEncoder;
|
||||
@@ -51,6 +51,7 @@ public class ConstantsTest extends TestCase {
|
||||
new ProtocolModule(), new SerialModule());
|
||||
writerFactory = i.getInstance(WriterFactory.class);
|
||||
crypto = i.getInstance(CryptoComponent.class);
|
||||
serial = i.getInstance(SerialComponent.class);
|
||||
groupFactory = i.getInstance(GroupFactory.class);
|
||||
authorFactory = i.getInstance(AuthorFactory.class);
|
||||
messageEncoder = i.getInstance(MessageEncoder.class);
|
||||
@@ -61,15 +62,10 @@ public class ConstantsTest extends TestCase {
|
||||
// Create an ack with the maximum number of batch IDs
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(
|
||||
ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
AckWriter a = new AckWriterImpl(out, writerFactory);
|
||||
for(int i = 0; i < Ack.MAX_IDS_PER_ACK; i++) {
|
||||
assertTrue(a.writeBatchId(new BatchId(TestUtils.getRandomId())));
|
||||
}
|
||||
// Check that no more batch IDs can be written
|
||||
assertFalse(a.writeBatchId(new BatchId(TestUtils.getRandomId())));
|
||||
AckWriter a = new AckWriterImpl(out, serial, writerFactory);
|
||||
while(a.writeBatchId(new BatchId(TestUtils.getRandomId())));
|
||||
a.finish();
|
||||
// Check the size of the serialised ack
|
||||
assertTrue(out.size() > UniqueId.LENGTH * Ack.MAX_IDS_PER_ACK);
|
||||
assertTrue(out.size() <= ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
}
|
||||
|
||||
@@ -92,7 +88,7 @@ public class ConstantsTest extends TestCase {
|
||||
// Add the message to a batch
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(
|
||||
ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
BatchWriter b = new BatchWriterImpl(out, writerFactory,
|
||||
BatchWriter b = new BatchWriterImpl(out, serial, writerFactory,
|
||||
crypto.getMessageDigest());
|
||||
b.writeMessage(message.getBytes());
|
||||
b.finish();
|
||||
@@ -108,16 +104,10 @@ public class ConstantsTest extends TestCase {
|
||||
// Create an offer with the maximum number of message IDs
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(
|
||||
ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
OfferWriter o = new OfferWriterImpl(out, writerFactory);
|
||||
for(int i = 0; i < Offer.MAX_IDS_PER_OFFER; i++) {
|
||||
assertTrue(o.writeMessageId(new MessageId(
|
||||
TestUtils.getRandomId())));
|
||||
}
|
||||
// Check that no more message IDs can be written
|
||||
assertFalse(o.writeMessageId(new MessageId(TestUtils.getRandomId())));
|
||||
OfferWriter o = new OfferWriterImpl(out, serial, writerFactory);
|
||||
while(o.writeMessageId(new MessageId(TestUtils.getRandomId())));
|
||||
o.finish();
|
||||
// Check the size of the serialised offer
|
||||
assertTrue(out.size() > UniqueId.LENGTH * Offer.MAX_IDS_PER_OFFER);
|
||||
assertTrue(out.size() <= ProtocolConstants.MAX_PACKET_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user