diff --git a/api/net/sf/briar/api/protocol/Ack.java b/api/net/sf/briar/api/protocol/Ack.java index 53feeb754e6374625e64393e1bedea7e832588e1..8be9162b23ff254918ff4be6a78d4ed618410851 100644 --- a/api/net/sf/briar/api/protocol/Ack.java +++ b/api/net/sf/briar/api/protocol/Ack.java @@ -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(); } diff --git a/api/net/sf/briar/api/protocol/Offer.java b/api/net/sf/briar/api/protocol/Offer.java index 6ff90d833997557e1f755f39d6ba33fb0492962e..0d12875ca5fe5c2306120849cbf9d005b6f43369 100644 --- a/api/net/sf/briar/api/protocol/Offer.java +++ b/api/net/sf/briar/api/protocol/Offer.java @@ -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(); } diff --git a/api/net/sf/briar/api/protocol/SubscriptionUpdate.java b/api/net/sf/briar/api/protocol/SubscriptionUpdate.java index 2124a72e2df8577c9c09ed9bdf38c713062c9e15..31e2f4672f4b31b303700da7d479d8c0fd150d1d 100644 --- a/api/net/sf/briar/api/protocol/SubscriptionUpdate.java +++ b/api/net/sf/briar/api/protocol/SubscriptionUpdate.java @@ -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(); diff --git a/api/net/sf/briar/api/serial/SerialComponent.java b/api/net/sf/briar/api/serial/SerialComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..1dc84673202278bfb42c2cf38fc7042ce0fa014f --- /dev/null +++ b/api/net/sf/briar/api/serial/SerialComponent.java @@ -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); +} diff --git a/components/net/sf/briar/protocol/AckReader.java b/components/net/sf/briar/protocol/AckReader.java index 5f78511ae7fdfd78b1cb97ad8d5e5ed9908900c2..af02456d4265197733832dd814e1f0ee44b8bfc4 100644 --- a/components/net/sf/briar/protocol/AckReader.java +++ b/components/net/sf/briar/protocol/AckReader.java @@ -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 diff --git a/components/net/sf/briar/protocol/OfferReader.java b/components/net/sf/briar/protocol/OfferReader.java index 04a15536cf44ab3340d6b7900a535b676e68181c..7d16c0b2f3c377e3886e9592548faba666b6a762 100644 --- a/components/net/sf/briar/protocol/OfferReader.java +++ b/components/net/sf/briar/protocol/OfferReader.java @@ -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 diff --git a/components/net/sf/briar/protocol/writers/AckWriterImpl.java b/components/net/sf/briar/protocol/writers/AckWriterImpl.java index 886455753d280e209b9c578035c2f7ef3eb831c6..a3babc533eb44d6c4ee32681ba906c38081d3f1e 100644 --- a/components/net/sf/briar/protocol/writers/AckWriterImpl.java +++ b/components/net/sf/briar/protocol/writers/AckWriterImpl.java @@ -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; + } } diff --git a/components/net/sf/briar/protocol/writers/BatchWriterImpl.java b/components/net/sf/briar/protocol/writers/BatchWriterImpl.java index fac083baff88986a3979aa29d3300d3b52292a34..99e668bc5155d0d6584abcac4cfeb1312f61c1df 100644 --- a/components/net/sf/briar/protocol/writers/BatchWriterImpl.java +++ b/components/net/sf/briar/protocol/writers/BatchWriterImpl.java @@ -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; + } } diff --git a/components/net/sf/briar/protocol/writers/OfferWriterImpl.java b/components/net/sf/briar/protocol/writers/OfferWriterImpl.java index c9f0670da4f1359bc24c1a42495c30b84be2e5c6..13baf0258567c5d5b66e94df16e788c47064f2af 100644 --- a/components/net/sf/briar/protocol/writers/OfferWriterImpl.java +++ b/components/net/sf/briar/protocol/writers/OfferWriterImpl.java @@ -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; + } } diff --git a/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java b/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java index 25999403679a4406a1246f38cb61ebd77d4035c9..b0e36477993344b6b118ab78e82dbe272deca18d 100644 --- a/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java +++ b/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java @@ -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) { diff --git a/components/net/sf/briar/serial/SerialComponentImpl.java b/components/net/sf/briar/serial/SerialComponentImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..d256294e2bfe9cee30b1660ea410e8ccd5dfc6fa --- /dev/null +++ b/components/net/sf/briar/serial/SerialComponentImpl.java @@ -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; + } +} diff --git a/components/net/sf/briar/serial/SerialModule.java b/components/net/sf/briar/serial/SerialModule.java index 48fb7b1a222049664611f69600ac44caad2fbd98..667087076b365b859b2f05b85272c3fb09434239 100644 --- a/components/net/sf/briar/serial/SerialModule.java +++ b/components/net/sf/briar/serial/SerialModule.java @@ -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); } } diff --git a/test/net/sf/briar/protocol/writers/ConstantsTest.java b/test/net/sf/briar/protocol/writers/ConstantsTest.java index 6d3781433758f81effc5cf3f5f3b3f1b7f5ee9ce..6115e08af7152d8ed885fdbbd1d9bd312dca4678 100644 --- a/test/net/sf/briar/protocol/writers/ConstantsTest.java +++ b/test/net/sf/briar/protocol/writers/ConstantsTest.java @@ -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); }