From 50ad1f486ebbc142478f0e27f8758047d10228dc Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Wed, 16 Jan 2013 22:56:03 +0000 Subject: [PATCH] Removed batches from BMP. Messages are now sent and acked individually. --- .../sf/briar/api/db/DatabaseComponent.java | 31 +- .../api/db/event/BatchReceivedEvent.java | 6 - ...AddedEvent.java => MessageAddedEvent.java} | 2 +- .../api/db/event/MessageReceivedEvent.java | 6 + .../src/net/sf/briar/api/protocol/Ack.java | 6 +- .../src/net/sf/briar/api/protocol/Batch.java | 13 - .../net/sf/briar/api/protocol/BatchId.java | 21 -- .../briar/api/protocol/MessageVerifier.java | 8 + .../sf/briar/api/protocol/PacketFactory.java | 4 +- .../sf/briar/api/protocol/ProtocolReader.java | 4 +- .../sf/briar/api/protocol/ProtocolWriter.java | 6 +- .../net/sf/briar/api/protocol/RawBatch.java | 13 - .../src/net/sf/briar/api/protocol/Types.java | 1 - .../briar/api/protocol/UnverifiedBatch.java | 8 - .../api}/protocol/UnverifiedMessage.java | 10 +- briar-core/.classpath | 1 + briar-core/src/net/sf/briar/db/Database.java | 71 ++-- .../sf/briar/db/DatabaseComponentImpl.java | 93 +++--- .../net/sf/briar/db/DatabaseConstants.java | 6 - .../src/net/sf/briar/db/JdbcDatabase.java | 303 +++++------------- .../src/net/sf/briar/protocol/AckImpl.java | 8 +- .../src/net/sf/briar/protocol/AckReader.java | 10 +- .../src/net/sf/briar/protocol/BatchImpl.java | 27 -- .../net/sf/briar/protocol/BatchReader.java | 41 --- .../net/sf/briar/protocol/MessageReader.java | 3 +- ...atchImpl.java => MessageVerifierImpl.java} | 49 +-- .../sf/briar/protocol/PacketFactoryImpl.java | 21 +- .../net/sf/briar/protocol/ProtocolModule.java | 12 +- .../protocol/ProtocolReaderFactoryImpl.java | 15 +- .../sf/briar/protocol/ProtocolReaderImpl.java | 16 +- .../sf/briar/protocol/ProtocolWriterImpl.java | 31 +- .../net/sf/briar/protocol/RawBatchImpl.java | 25 -- .../protocol/UnverifiedBatchFactory.java | 11 - .../protocol/UnverifiedBatchFactoryImpl.java | 23 -- .../briar/protocol/UnverifiedMessageImpl.java | 3 +- .../protocol/duplex/DuplexConnection.java | 66 ++-- .../duplex/DuplexConnectionFactoryImpl.java | 19 +- .../duplex/IncomingDuplexConnection.java | 10 +- .../duplex/OutgoingDuplexConnection.java | 10 +- .../simplex/IncomingSimplexConnection.java | 38 ++- .../simplex/OutgoingSimplexConnection.java | 24 +- .../simplex/SimplexConnectionFactoryImpl.java | 11 +- briar-tests/build.xml | 3 - .../net/sf/briar/ProtocolIntegrationTest.java | 80 +++-- .../net/sf/briar/{db => }/TestMessage.java | 4 +- .../sf/briar/db/DatabaseComponentTest.java | 179 ++++------- .../src/net/sf/briar/db/H2DatabaseTest.java | 237 ++++---------- .../sf/briar/protocol/BatchReaderTest.java | 137 -------- .../net/sf/briar/protocol/ConstantsTest.java | 52 ++- .../protocol/ProtocolIntegrationTest.java | 134 -------- .../protocol/UnverifiedBatchImplTest.java | 242 -------------- .../OutgoingSimplexConnectionTest.java | 25 +- .../SimplexProtocolIntegrationTest.java | 13 +- .../transport/ConnectionWriterImplTest.java | 1 - .../transport/TransportIntegrationTest.java | 11 +- 55 files changed, 556 insertions(+), 1648 deletions(-) delete mode 100644 briar-api/src/net/sf/briar/api/db/event/BatchReceivedEvent.java rename briar-api/src/net/sf/briar/api/db/event/{MessagesAddedEvent.java => MessageAddedEvent.java} (70%) create mode 100644 briar-api/src/net/sf/briar/api/db/event/MessageReceivedEvent.java delete mode 100644 briar-api/src/net/sf/briar/api/protocol/Batch.java delete mode 100644 briar-api/src/net/sf/briar/api/protocol/BatchId.java create mode 100644 briar-api/src/net/sf/briar/api/protocol/MessageVerifier.java delete mode 100644 briar-api/src/net/sf/briar/api/protocol/RawBatch.java delete mode 100644 briar-api/src/net/sf/briar/api/protocol/UnverifiedBatch.java rename {briar-core/src/net/sf/briar => briar-api/src/net/sf/briar/api}/protocol/UnverifiedMessage.java (58%) delete mode 100644 briar-core/src/net/sf/briar/protocol/BatchImpl.java delete mode 100644 briar-core/src/net/sf/briar/protocol/BatchReader.java rename briar-core/src/net/sf/briar/protocol/{UnverifiedBatchImpl.java => MessageVerifierImpl.java} (54%) delete mode 100644 briar-core/src/net/sf/briar/protocol/RawBatchImpl.java delete mode 100644 briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactory.java delete mode 100644 briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactoryImpl.java rename briar-tests/src/net/sf/briar/{db => }/TestMessage.java (96%) delete mode 100644 briar-tests/src/net/sf/briar/protocol/BatchReaderTest.java delete mode 100644 briar-tests/src/net/sf/briar/protocol/ProtocolIntegrationTest.java delete mode 100644 briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java diff --git a/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java b/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java index b584830233..37675ac399 100644 --- a/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java +++ b/briar-api/src/net/sf/briar/api/db/DatabaseComponent.java @@ -11,13 +11,11 @@ import net.sf.briar.api.TransportProperties; import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.protocol.Ack; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.Batch; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Transport; @@ -70,25 +68,28 @@ public interface DatabaseComponent { /** * Generates an acknowledgement for the given contact. Returns null if - * there are no batches to acknowledge. + * there are no messages to acknowledge. */ - Ack generateAck(ContactId c, int maxBatches) throws DbException; + Ack generateAck(ContactId c, int maxMessages) throws DbException; /** - * Generates a batch of messages for the given contact. Returns null if - * there are no sendable messages that fit in the given capacity. + * Generates a batch of raw messages for the given contact, with a total + * length less than or equal to the given length. Returns null if + * there are no sendable messages that fit in the given length. */ - RawBatch generateBatch(ContactId c, int capacity) throws DbException; + Collection<byte[]> generateBatch(ContactId c, int maxLength) + throws DbException; /** - * Generates a batch of messages for the given contact from the given - * collection of requested messages. Any messages that were either added to - * the batch, or were considered but are no longer sendable to the contact, - * are removed from the collection of requested messages before returning. + * Generates a batch of raw messages for the given contact from the given + * collection of requested messages, with a total length less than or equal + * to the given length. Any messages that were either added to the batch, + * or were considered but are no longer sendable to the contact, are + * removed from the collection of requested messages before returning. * Returns null if there are no sendable messages that fit in the given - * capacity. + * length. */ - RawBatch generateBatch(ContactId c, int capacity, + Collection<byte[]> generateBatch(ContactId c, int maxLength, Collection<MessageId> requested) throws DbException; /** @@ -170,8 +171,8 @@ public interface DatabaseComponent { /** Processes an acknowledgement from the given contact. */ void receiveAck(ContactId c, Ack a) throws DbException; - /** Processes a batch of messages from the given contact. */ - void receiveBatch(ContactId c, Batch b) throws DbException; + /** Processes a message from the given contact. */ + void receiveMessage(ContactId c, Message m) throws DbException; /** * Processes an offer from the given contact and generates a request for diff --git a/briar-api/src/net/sf/briar/api/db/event/BatchReceivedEvent.java b/briar-api/src/net/sf/briar/api/db/event/BatchReceivedEvent.java deleted file mode 100644 index a7ebcdef98..0000000000 --- a/briar-api/src/net/sf/briar/api/db/event/BatchReceivedEvent.java +++ /dev/null @@ -1,6 +0,0 @@ -package net.sf.briar.api.db.event; - -/** An event that is broadcast when a batch of messages is received. */ -public class BatchReceivedEvent extends DatabaseEvent { - -} diff --git a/briar-api/src/net/sf/briar/api/db/event/MessagesAddedEvent.java b/briar-api/src/net/sf/briar/api/db/event/MessageAddedEvent.java similarity index 70% rename from briar-api/src/net/sf/briar/api/db/event/MessagesAddedEvent.java rename to briar-api/src/net/sf/briar/api/db/event/MessageAddedEvent.java index c51515d528..d28dd1664d 100644 --- a/briar-api/src/net/sf/briar/api/db/event/MessagesAddedEvent.java +++ b/briar-api/src/net/sf/briar/api/db/event/MessageAddedEvent.java @@ -4,6 +4,6 @@ package net.sf.briar.api.db.event; * An event that is broadcast when one or more messages are added to the * database. */ -public class MessagesAddedEvent extends DatabaseEvent { +public class MessageAddedEvent extends DatabaseEvent { } diff --git a/briar-api/src/net/sf/briar/api/db/event/MessageReceivedEvent.java b/briar-api/src/net/sf/briar/api/db/event/MessageReceivedEvent.java new file mode 100644 index 0000000000..4a5ae2c688 --- /dev/null +++ b/briar-api/src/net/sf/briar/api/db/event/MessageReceivedEvent.java @@ -0,0 +1,6 @@ +package net.sf.briar.api.db.event; + +/** An event that is broadcast when a message is received. */ +public class MessageReceivedEvent extends DatabaseEvent { + +} diff --git a/briar-api/src/net/sf/briar/api/protocol/Ack.java b/briar-api/src/net/sf/briar/api/protocol/Ack.java index 8be9162b23..4608fee530 100644 --- a/briar-api/src/net/sf/briar/api/protocol/Ack.java +++ b/briar-api/src/net/sf/briar/api/protocol/Ack.java @@ -2,9 +2,9 @@ package net.sf.briar.api.protocol; import java.util.Collection; -/** A packet acknowledging receipt of one or more batches. */ +/** A packet acknowledging receipt of one or more messages. */ public interface Ack { - /** Returns the IDs of the acknowledged batches. */ - Collection<BatchId> getBatchIds(); + /** Returns the IDs of the acknowledged messages. */ + Collection<MessageId> getMessageIds(); } diff --git a/briar-api/src/net/sf/briar/api/protocol/Batch.java b/briar-api/src/net/sf/briar/api/protocol/Batch.java deleted file mode 100644 index eec1fef477..0000000000 --- a/briar-api/src/net/sf/briar/api/protocol/Batch.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.sf.briar.api.protocol; - -import java.util.Collection; - -/** An incoming packet containing messages. */ -public interface Batch { - - /** Returns the batch's unique identifier. */ - BatchId getId(); - - /** Returns the messages contained in the batch. */ - Collection<Message> getMessages(); -} \ No newline at end of file diff --git a/briar-api/src/net/sf/briar/api/protocol/BatchId.java b/briar-api/src/net/sf/briar/api/protocol/BatchId.java deleted file mode 100644 index ab33800761..0000000000 --- a/briar-api/src/net/sf/briar/api/protocol/BatchId.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.sf.briar.api.protocol; - -import java.util.Arrays; - -/** - * Type-safe wrapper for a byte array that uniquely identifies a batch of - * messages. - */ -public class BatchId extends UniqueId { - - public BatchId(byte[] id) { - super(id); - } - - @Override - public boolean equals(Object o) { - if(o instanceof BatchId) - return Arrays.equals(id, ((BatchId) o).id); - return false; - } -} diff --git a/briar-api/src/net/sf/briar/api/protocol/MessageVerifier.java b/briar-api/src/net/sf/briar/api/protocol/MessageVerifier.java new file mode 100644 index 0000000000..59313414fb --- /dev/null +++ b/briar-api/src/net/sf/briar/api/protocol/MessageVerifier.java @@ -0,0 +1,8 @@ +package net.sf.briar.api.protocol; + +import java.security.GeneralSecurityException; + +public interface MessageVerifier { + + Message verifyMessage(UnverifiedMessage m) throws GeneralSecurityException; +} diff --git a/briar-api/src/net/sf/briar/api/protocol/PacketFactory.java b/briar-api/src/net/sf/briar/api/protocol/PacketFactory.java index 3f15e8bc8f..9c3c51116d 100644 --- a/briar-api/src/net/sf/briar/api/protocol/PacketFactory.java +++ b/briar-api/src/net/sf/briar/api/protocol/PacketFactory.java @@ -6,9 +6,7 @@ import java.util.Map; public interface PacketFactory { - Ack createAck(Collection<BatchId> acked); - - RawBatch createBatch(Collection<byte[]> messages); + Ack createAck(Collection<MessageId> acked); Offer createOffer(Collection<MessageId> offered); diff --git a/briar-api/src/net/sf/briar/api/protocol/ProtocolReader.java b/briar-api/src/net/sf/briar/api/protocol/ProtocolReader.java index 104b0d60a5..24f4c8aac8 100644 --- a/briar-api/src/net/sf/briar/api/protocol/ProtocolReader.java +++ b/briar-api/src/net/sf/briar/api/protocol/ProtocolReader.java @@ -9,8 +9,8 @@ public interface ProtocolReader { boolean hasAck() throws IOException; Ack readAck() throws IOException; - boolean hasBatch() throws IOException; - UnverifiedBatch readBatch() throws IOException; + boolean hasMessage() throws IOException; + UnverifiedMessage readMessage() throws IOException; boolean hasOffer() throws IOException; Offer readOffer() throws IOException; diff --git a/briar-api/src/net/sf/briar/api/protocol/ProtocolWriter.java b/briar-api/src/net/sf/briar/api/protocol/ProtocolWriter.java index fc30d803fd..4ddd4c4fb9 100644 --- a/briar-api/src/net/sf/briar/api/protocol/ProtocolWriter.java +++ b/briar-api/src/net/sf/briar/api/protocol/ProtocolWriter.java @@ -4,15 +4,13 @@ import java.io.IOException; public interface ProtocolWriter { - int getMaxBatchesForAck(long capacity); + int getMaxMessagesForAck(long capacity); int getMaxMessagesForOffer(long capacity); - int getMessageCapacityForBatch(long capacity); - void writeAck(Ack a) throws IOException; - void writeBatch(RawBatch b) throws IOException; + void writeMessage(byte[] raw) throws IOException; void writeOffer(Offer o) throws IOException; diff --git a/briar-api/src/net/sf/briar/api/protocol/RawBatch.java b/briar-api/src/net/sf/briar/api/protocol/RawBatch.java deleted file mode 100644 index f1337f6458..0000000000 --- a/briar-api/src/net/sf/briar/api/protocol/RawBatch.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.sf.briar.api.protocol; - -import java.util.Collection; - -/** An outgoing packet containing messages. */ -public interface RawBatch { - - /** Returns the batch's unique identifier. */ - BatchId getId(); - - /** Returns the serialised messages contained in the batch. */ - Collection<byte[]> getMessages(); -} diff --git a/briar-api/src/net/sf/briar/api/protocol/Types.java b/briar-api/src/net/sf/briar/api/protocol/Types.java index 2fd63f7eee..71ec94a397 100644 --- a/briar-api/src/net/sf/briar/api/protocol/Types.java +++ b/briar-api/src/net/sf/briar/api/protocol/Types.java @@ -5,7 +5,6 @@ public interface Types { int ACK = 0; int AUTHOR = 1; - int BATCH = 2; int GROUP = 3; int MESSAGE = 4; int OFFER = 5; diff --git a/briar-api/src/net/sf/briar/api/protocol/UnverifiedBatch.java b/briar-api/src/net/sf/briar/api/protocol/UnverifiedBatch.java deleted file mode 100644 index abd1f15159..0000000000 --- a/briar-api/src/net/sf/briar/api/protocol/UnverifiedBatch.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.sf.briar.api.protocol; - -import java.security.GeneralSecurityException; - -public interface UnverifiedBatch { - - Batch verify() throws GeneralSecurityException; -} diff --git a/briar-core/src/net/sf/briar/protocol/UnverifiedMessage.java b/briar-api/src/net/sf/briar/api/protocol/UnverifiedMessage.java similarity index 58% rename from briar-core/src/net/sf/briar/protocol/UnverifiedMessage.java rename to briar-api/src/net/sf/briar/api/protocol/UnverifiedMessage.java index 64866d2a01..8fd391d2f8 100644 --- a/briar-core/src/net/sf/briar/protocol/UnverifiedMessage.java +++ b/briar-api/src/net/sf/briar/api/protocol/UnverifiedMessage.java @@ -1,10 +1,6 @@ -package net.sf.briar.protocol; +package net.sf.briar.api.protocol; -import net.sf.briar.api.protocol.Author; -import net.sf.briar.api.protocol.Group; -import net.sf.briar.api.protocol.MessageId; - -interface UnverifiedMessage { +public interface UnverifiedMessage { MessageId getParent(); @@ -16,7 +12,7 @@ interface UnverifiedMessage { long getTimestamp(); - byte[] getRaw(); + byte[] getSerialised(); byte[] getAuthorSignature(); diff --git a/briar-core/.classpath b/briar-core/.classpath index 4638c93899..f09021d12c 100644 --- a/briar-core/.classpath +++ b/briar-core/.classpath @@ -13,6 +13,7 @@ <classpathentry kind="lib" path="libs/weupnp-0.1.1.jar"/> <classpathentry kind="lib" path="libs/bluecove-2.1.1-SNAPSHOT-briar.jar"/> <classpathentry kind="lib" path="libs/bluecove-gpl-2.1.1-SNAPSHOT.jar"/> + <classpathentry kind="lib" path="libs/javax.inject.jar"/> <classpathentry combineaccessrules="false" kind="src" path="/briar-api"/> <classpathentry kind="lib" path="/briar-api/libs/android.jar"/> <classpathentry kind="lib" path="/briar-api/libs/guice-3.0-no_aop.jar"/> diff --git a/briar-core/src/net/sf/briar/db/Database.java b/briar-core/src/net/sf/briar/db/Database.java index 3959e735d1..08b420d59c 100644 --- a/briar-core/src/net/sf/briar/db/Database.java +++ b/briar-core/src/net/sf/briar/db/Database.java @@ -11,7 +11,6 @@ import net.sf.briar.api.TransportProperties; import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; @@ -71,13 +70,6 @@ interface Database<T> { */ void commitTransaction(T txn) throws DbException; - /** - * Records a received batch as needing to be acknowledged. - * <p> - * Locking: contact read, messageStatus write. - */ - void addBatchToAck(T txn, ContactId c, BatchId b) throws DbException; - /** * Adds a new contact to the database and returns an ID for the contact. * <p> @@ -101,12 +93,19 @@ interface Database<T> { boolean addGroupMessage(T txn, Message m) throws DbException; /** - * Records a sent batch as needing to be acknowledged. + * Records a received message as needing to be acknowledged. + * <p> + * Locking: contact read, messageStatus write. + */ + void addMessageToAck(T txn, ContactId c, MessageId m) throws DbException; + + /** + * Records a collection of sent messages as needing to be acknowledged. * <p> * Locking: contact read, message read, messageStatus write. */ - void addOutstandingBatch(T txn, ContactId c, BatchId b, - Collection<MessageId> sent) throws DbException; + void addOutstandingMessages(T txn, ContactId c, Collection<MessageId> sent) + throws DbException; /** * Returns false if the given message is already in the database. Otherwise @@ -196,15 +195,6 @@ interface Database<T> { boolean containsVisibleSubscription(T txn, GroupId g, ContactId c, long time) throws DbException; - /** - * Returns the IDs of any batches received from the given contact that need - * to be acknowledged. - * <p> - * Locking: contact read, messageStatus read. - */ - Collection<BatchId> getBatchesToAck(T txn, ContactId c, int maxBatches) - throws DbException; - /** * Returns the configuration for the given transport. * <p> @@ -267,12 +257,13 @@ interface Database<T> { Collection<Transport> getLocalTransports(T txn) throws DbException; /** - * Returns the IDs of any batches sent to the given contact that should now - * be considered lost. + * Returns the IDs of any messages sent to the given contact that should + * now be considered lost. * <p> * Locking: contact read, message read, messageStatus read. */ - Collection<BatchId> getLostBatches(T txn, ContactId c) throws DbException; + Collection<MessageId> getLostMessages(T txn, ContactId c) + throws DbException; /** * Returns the message identified by the given ID, in serialised form. @@ -315,6 +306,15 @@ interface Database<T> { Collection<MessageId> getMessagesByAuthor(T txn, AuthorId a) throws DbException; + /** + * Returns the IDs of any messages received from the given contact that + * need to be acknowledged. + * <p> + * Locking: contact read, messageStatus read. + */ + Collection<MessageId> getMessagesToAck(T txn, ContactId c, int maxMessages) + throws DbException; + /** * Returns the number of children of the message identified by the given * ID that are present in the database and have sendability scores greater @@ -380,12 +380,13 @@ interface Database<T> { /** * Returns the IDs of some messages that are eligible to be sent to the - * given contact, with a total size less than or equal to the given size. + * given contact, with a total length less than or equal to the given + * length. * <p> * Locking: contact read, message read, messageStatus read, * subscription read. */ - Collection<MessageId> getSendableMessages(T txn, ContactId c, int capacity) + Collection<MessageId> getSendableMessages(T txn, ContactId c, int maxLength) throws DbException; /** @@ -493,21 +494,22 @@ interface Database<T> { throws DbException; /** - * Removes an outstanding batch that has been acknowledged. Any messages in - * the batch that are still considered outstanding (Status.SENT) with + * Removes outstanding messages that have been acknowledged. Any of the + * messages that are still considered outstanding (Status.SENT) with * respect to the given contact are now considered seen (Status.SEEN). * <p> * Locking: contact read, message read, messageStatus write. */ - void removeAckedBatch(T txn, ContactId c, BatchId b) throws DbException; + void removeAckedMessages(T txn, ContactId c, Collection<MessageId> acked) + throws DbException; /** - * Marks the given batches received from the given contact as having been + * Marks the given messages received from the given contact as having been * acknowledged. * <p> * Locking: contact read, messageStatus write. */ - void removeBatchesToAck(T txn, ContactId c, Collection<BatchId> sent) + void removeMessagesToAck(T txn, ContactId c, Collection<MessageId> acked) throws DbException; /** @@ -519,13 +521,14 @@ interface Database<T> { void removeContact(T txn, ContactId c) throws DbException; /** - * Removes an outstanding batch that has been lost. Any messages in the - * batch that are still considered outstanding (Status.SENT) with respect - * to the given contact are now considered unsent (Status.NEW). + * Removes outstanding messages that have been lost. Any messages that are + * still considered outstanding (Status.SENT) with respect to the given + * contact are now considered unsent (Status.NEW). * <p> * Locking: contact read, message read, messageStatus write. */ - void removeLostBatch(T txn, ContactId c, BatchId b) throws DbException; + void removeLostMessages(T txn, ContactId c, Collection<MessageId> lost) + throws DbException; /** * Removes a message (and all associated state) from the database. diff --git a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java index 8c81c4ee9f..2fa615d601 100644 --- a/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java +++ b/briar-core/src/net/sf/briar/db/DatabaseComponentImpl.java @@ -32,28 +32,25 @@ import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.db.NoSuchContactException; import net.sf.briar.api.db.NoSuchContactTransportException; -import net.sf.briar.api.db.event.BatchReceivedEvent; import net.sf.briar.api.db.event.ContactAddedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent; -import net.sf.briar.api.db.event.MessagesAddedEvent; +import net.sf.briar.api.db.event.MessageAddedEvent; +import net.sf.briar.api.db.event.MessageReceivedEvent; import net.sf.briar.api.db.event.RatingChangedEvent; import net.sf.briar.api.db.event.RemoteTransportsUpdatedEvent; import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent; import net.sf.briar.api.lifecycle.ShutdownManager; import net.sf.briar.api.protocol.Ack; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.Batch; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.PacketFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Transport; @@ -270,7 +267,7 @@ DatabaseCleaner.Callback { contactLock.readLock().unlock(); } // Call the listeners outside the lock - if(added) callListeners(new MessagesAddedEvent()); + if(added) callListeners(new MessageAddedEvent()); } /** @@ -388,7 +385,7 @@ DatabaseCleaner.Callback { contactLock.readLock().unlock(); } // Call the listeners outside the lock - if(added) callListeners(new MessagesAddedEvent()); + if(added) callListeners(new MessageAddedEvent()); } public void addSecrets(Collection<TemporarySecret> secrets) @@ -444,8 +441,8 @@ DatabaseCleaner.Callback { return true; } - public Ack generateAck(ContactId c, int maxBatches) throws DbException { - Collection<BatchId> acked; + public Ack generateAck(ContactId c, int maxMessages) throws DbException { + Collection<MessageId> acked; contactLock.readLock().lock(); try { messageStatusLock.readLock().lock(); @@ -454,7 +451,7 @@ DatabaseCleaner.Callback { try { if(!db.containsContact(txn, c)) throw new NoSuchContactException(); - acked = db.getBatchesToAck(txn, c, maxBatches); + acked = db.getMessagesToAck(txn, c, maxMessages); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -469,7 +466,7 @@ DatabaseCleaner.Callback { try { T txn = db.startTransaction(); try { - db.removeBatchesToAck(txn, c, acked); + db.removeMessagesToAck(txn, c, acked); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -484,11 +481,10 @@ DatabaseCleaner.Callback { return packetFactory.createAck(acked); } - public RawBatch generateBatch(ContactId c, int capacity) + public Collection<byte[]> generateBatch(ContactId c, int maxLength) throws DbException { Collection<MessageId> ids; List<byte[]> messages = new ArrayList<byte[]>(); - RawBatch b; // Get some sendable messages from the database contactLock.readLock().lock(); try { @@ -502,7 +498,7 @@ DatabaseCleaner.Callback { try { if(!db.containsContact(txn, c)) throw new NoSuchContactException(); - ids = db.getSendableMessages(txn, c, capacity); + ids = db.getSendableMessages(txn, c, maxLength); for(MessageId m : ids) { messages.add(db.getMessage(txn, m)); } @@ -518,13 +514,11 @@ DatabaseCleaner.Callback { messageStatusLock.readLock().unlock(); } if(messages.isEmpty()) return null; - messages = Collections.unmodifiableList(messages); - b = packetFactory.createBatch(messages); messageStatusLock.writeLock().lock(); try { T txn = db.startTransaction(); try { - db.addOutstandingBatch(txn, c, b.getId(), ids); + db.addOutstandingMessages(txn, c, ids); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -539,14 +533,13 @@ DatabaseCleaner.Callback { } finally { contactLock.readLock().unlock(); } - return b; + return Collections.unmodifiableList(messages); } - public RawBatch generateBatch(ContactId c, int capacity, + public Collection<byte[]> generateBatch(ContactId c, int maxLength, Collection<MessageId> requested) throws DbException { Collection<MessageId> ids = new ArrayList<MessageId>(); List<byte[]> messages = new ArrayList<byte[]>(); - RawBatch b; // Get some sendable messages from the database contactLock.readLock().lock(); try { @@ -565,10 +558,10 @@ DatabaseCleaner.Callback { MessageId m = it.next(); byte[] raw = db.getMessageIfSendable(txn, c, m); if(raw != null) { - if(raw.length > capacity) break; + if(raw.length > maxLength) break; messages.add(raw); ids.add(m); - capacity -= raw.length; + maxLength -= raw.length; } it.remove(); } @@ -584,13 +577,11 @@ DatabaseCleaner.Callback { messageStatusLock.readLock().unlock(); } if(messages.isEmpty()) return null; - messages = Collections.unmodifiableList(messages); - b = packetFactory.createBatch(messages); messageStatusLock.writeLock().lock(); try { T txn = db.startTransaction(); try { - db.addOutstandingBatch(txn, c, b.getId(), ids); + db.addOutstandingMessages(txn, c, ids); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -605,7 +596,7 @@ DatabaseCleaner.Callback { } finally { contactLock.readLock().unlock(); } - return b; + return Collections.unmodifiableList(messages); } public Offer generateOffer(ContactId c, int maxMessages) @@ -1057,12 +1048,12 @@ DatabaseCleaner.Callback { try { if(!db.containsContact(txn, c)) throw new NoSuchContactException(); - Collection<BatchId> acks = a.getBatchIds(); - // Mark all messages in acked batches as seen - for(BatchId b : acks) db.removeAckedBatch(txn, c, b); - // Find any lost batches that need to be retransmitted - Collection<BatchId> lost = db.getLostBatches(txn, c); - for(BatchId b : lost) db.removeLostBatch(txn, c, b); + // Mark all acked messages as seen + db.removeAckedMessages(txn, c, a.getMessageIds()); + // Find any lost messages that need to be retransmitted + // FIXME: Merge these methods + Collection<MessageId> lost = db.getLostMessages(txn, c); + if(!lost.isEmpty()) db.removeLostMessages(txn, c, lost); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -1079,8 +1070,8 @@ DatabaseCleaner.Callback { } } - public void receiveBatch(ContactId c, Batch b) throws DbException { - boolean anyAdded = false; + public void receiveMessage(ContactId c, Message m) throws DbException { + boolean added = false; contactLock.readLock().lock(); try { messageLock.writeLock().lock(); @@ -1093,8 +1084,8 @@ DatabaseCleaner.Callback { try { if(!db.containsContact(txn, c)) throw new NoSuchContactException(); - anyAdded = storeMessages(txn, c, b.getMessages()); - db.addBatchToAck(txn, c, b.getId()); + added = storeMessage(txn, c, m); + db.addMessageToAck(txn, c, m.getId()); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -1113,32 +1104,24 @@ DatabaseCleaner.Callback { contactLock.readLock().unlock(); } // Call the listeners outside the lock - callListeners(new BatchReceivedEvent()); - if(anyAdded) callListeners(new MessagesAddedEvent()); + callListeners(new MessageReceivedEvent()); + if(added) callListeners(new MessageAddedEvent()); } /** - * Attempts to store a collection of messages received from the given - * contact, and returns true if any were stored. + * Attempts to store a message received from the given contact, and returns + * true if it was stored. * <p> * Locking: contact read, message write, messageStatus write, * subscription read. */ - private boolean storeMessages(T txn, ContactId c, - Collection<Message> messages) throws DbException { - boolean anyStored = false; - for(Message m : messages) { - GroupId g = m.getGroup(); - if(g == null) { - if(storePrivateMessage(txn, m, c, true)) anyStored = true; - } else { - long timestamp = m.getTimestamp(); - if(db.containsVisibleSubscription(txn, g, c, timestamp)) { - if(storeGroupMessage(txn, m, c)) anyStored = true; - } - } - } - return anyStored; + private boolean storeMessage(T txn, ContactId c, Message m) + throws DbException { + GroupId g = m.getGroup(); + if(g == null) return storePrivateMessage(txn, m, c, true); + if(!db.containsVisibleSubscription(txn, g, c, m.getTimestamp())) + return false; + return storeGroupMessage(txn, m, c); } public Request receiveOffer(ContactId c, Offer o) throws DbException { diff --git a/briar-core/src/net/sf/briar/db/DatabaseConstants.java b/briar-core/src/net/sf/briar/db/DatabaseConstants.java index 27af159268..eb00f1290c 100644 --- a/briar-core/src/net/sf/briar/db/DatabaseConstants.java +++ b/briar-core/src/net/sf/briar/db/DatabaseConstants.java @@ -42,12 +42,6 @@ interface DatabaseConstants { */ long EXPIRY_MODULUS = 60L * 60L * 1000L; // 1 hour - /** - * A batch sent to a contact is considered lost when this many more - * recently sent batches have been acknowledged. - */ - int RETRANSMIT_THRESHOLD = 5; - /** * The time in milliseconds after which a subscription or transport update * should be sent to a contact even if no changes have occurred. diff --git a/briar-core/src/net/sf/briar/db/JdbcDatabase.java b/briar-core/src/net/sf/briar/db/JdbcDatabase.java index 15d89cd666..10e29501bd 100644 --- a/briar-core/src/net/sf/briar/db/JdbcDatabase.java +++ b/briar-core/src/net/sf/briar/db/JdbcDatabase.java @@ -3,7 +3,6 @@ package net.sf.briar.db; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static net.sf.briar.db.DatabaseConstants.EXPIRY_MODULUS; -import static net.sf.briar.db.DatabaseConstants.RETRANSMIT_THRESHOLD; import java.io.File; import java.io.FileNotFoundException; @@ -33,7 +32,6 @@ import net.sf.briar.api.db.DbClosedException; import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; @@ -112,11 +110,11 @@ abstract class JdbcDatabase implements Database<Connection> { private static final String INDEX_VISIBILITIES_BY_NEXT = "CREATE INDEX visibilitiesByNext on visibilities (nextId)"; - private static final String CREATE_BATCHES_TO_ACK = - "CREATE TABLE batchesToAck" - + " (batchId HASH NOT NULL," + private static final String CREATE_MESSAGES_TO_ACK = + "CREATE TABLE messagesToAck" + + " (messageId HASH NOT NULL," + " contactId INT NOT NULL," - + " PRIMARY KEY (batchId, contactId)," + + " PRIMARY KEY (messageId, contactId)," + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; @@ -131,32 +129,6 @@ abstract class JdbcDatabase implements Database<Connection> { + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; - private static final String CREATE_OUTSTANDING_BATCHES = - "CREATE TABLE outstandingBatches" - + " (batchId HASH NOT NULL," - + " contactId INT NOT NULL," - + " timestamp BIGINT NOT NULL," - + " passover INT NOT NULL," - + " PRIMARY KEY (batchId, contactId)," - + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" - + " ON DELETE CASCADE)"; - - private static final String CREATE_OUTSTANDING_MESSAGES = - "CREATE TABLE outstandingMessages" - + " (batchId HASH NOT NULL," - + " contactId INT NOT NULL," - + " messageId HASH NOT NULL," - + " PRIMARY KEY (batchId, contactId, messageId)," - + " FOREIGN KEY (batchId, contactId)" - + " REFERENCES outstandingBatches (batchId, contactId)" - + " ON DELETE CASCADE," - + " FOREIGN KEY (messageId) REFERENCES messages (messageId)" - + " ON DELETE CASCADE)"; - - private static final String INDEX_OUTSTANDING_MESSAGES_BY_BATCH = - "CREATE INDEX outstandingMessagesByBatch" - + " ON outstandingMessages (batchId)"; - private static final String CREATE_RATINGS = "CREATE TABLE ratings" + " (authorId HASH NOT NULL," @@ -322,11 +294,8 @@ abstract class JdbcDatabase implements Database<Connection> { s.executeUpdate(insertTypeNames(CREATE_VISIBILITIES)); s.executeUpdate(INDEX_VISIBILITIES_BY_GROUP); s.executeUpdate(INDEX_VISIBILITIES_BY_NEXT); - s.executeUpdate(insertTypeNames(CREATE_BATCHES_TO_ACK)); + s.executeUpdate(insertTypeNames(CREATE_MESSAGES_TO_ACK)); s.executeUpdate(insertTypeNames(CREATE_CONTACT_SUBSCRIPTIONS)); - s.executeUpdate(insertTypeNames(CREATE_OUTSTANDING_BATCHES)); - s.executeUpdate(insertTypeNames(CREATE_OUTSTANDING_MESSAGES)); - s.executeUpdate(INDEX_OUTSTANDING_MESSAGES_BY_BATCH); s.executeUpdate(insertTypeNames(CREATE_RATINGS)); s.executeUpdate(insertTypeNames(CREATE_STATUSES)); s.executeUpdate(INDEX_STATUSES_BY_MESSAGE); @@ -452,37 +421,6 @@ abstract class JdbcDatabase implements Database<Connection> { if(interrupted) Thread.currentThread().interrupt(); } - public void addBatchToAck(Connection txn, ContactId c, BatchId b) - throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT NULL FROM batchesToAck" - + " WHERE batchId = ? AND contactId = ?"; - ps = txn.prepareStatement(sql); - ps.setBytes(1, b.getBytes()); - ps.setInt(2, c.getInt()); - rs = ps.executeQuery(); - boolean found = rs.next(); - if(rs.next()) throw new DbStateException(); - rs.close(); - ps.close(); - if(found) return; - sql = "INSERT INTO batchesToAck (batchId, contactId)" - + " VALUES (?, ?)"; - ps = txn.prepareStatement(sql); - ps.setBytes(1, b.getBytes()); - ps.setInt(2, c.getInt()); - int affected = ps.executeUpdate(); - if(affected != 1) throw new DbStateException(); - ps.close(); - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - } - public ContactId addContact(Connection txn) throws DbException { PreparedStatement ps = null; ResultSet rs = null; @@ -596,42 +534,30 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void addOutstandingBatch(Connection txn, ContactId c, BatchId b, - Collection<MessageId> sent) throws DbException { + public void addMessageToAck(Connection txn, ContactId c, MessageId m) + throws DbException { PreparedStatement ps = null; - ResultSet rs = null; try { - // Create an outstanding batch row - String sql = "INSERT INTO outstandingBatches" - + " (batchId, contactId, timestamp, passover)" - + " VALUES (?, ?, ?, ZERO())"; + String sql = "INSERT INTO messagesToAck (messageId, contactId)" + + " VALUES (?, ?)"; ps = txn.prepareStatement(sql); - ps.setBytes(1, b.getBytes()); + ps.setBytes(1, m.getBytes()); ps.setInt(2, c.getInt()); - ps.setLong(3, clock.currentTimeMillis()); int affected = ps.executeUpdate(); - if(affected != 1) throw new DbStateException(); - ps.close(); - // Create an outstanding message row for each message in the batch - sql = "INSERT INTO outstandingMessages" - + " (batchId, contactId, messageId)" - + " VALUES (?, ?, ?)"; - ps = txn.prepareStatement(sql); - ps.setBytes(1, b.getBytes()); - ps.setInt(2, c.getInt()); - for(MessageId m : sent) { - ps.setBytes(3, m.getBytes()); - ps.addBatch(); - } - int[] batchAffected = ps.executeBatch(); - if(batchAffected.length != sent.size()) - throw new DbStateException(); - for(int i = 0; i < batchAffected.length; i++) { - if(batchAffected[i] != 1) throw new DbStateException(); - } + if(affected > 1) throw new DbStateException(); ps.close(); - // Set the status of each message in the batch to SENT - sql = "UPDATE statuses SET status = ?" + } catch(SQLException e) { + tryToClose(ps); + throw new DbException(e); + } + } + + public void addOutstandingMessages(Connection txn, ContactId c, + Collection<MessageId> sent) throws DbException { + PreparedStatement ps = null; + try { + // Set the status of each message to SENT if it's currently NEW + String sql = "UPDATE statuses SET status = ?" + " WHERE messageId = ? AND contactId = ? AND status = ?"; ps = txn.prepareStatement(sql); ps.setShort(1, (short) Status.SENT.ordinal()); @@ -641,7 +567,7 @@ abstract class JdbcDatabase implements Database<Connection> { ps.setBytes(2, m.getBytes()); ps.addBatch(); } - batchAffected = ps.executeBatch(); + int[] batchAffected = ps.executeBatch(); if(batchAffected.length != sent.size()) throw new DbStateException(); for(int i = 0; i < batchAffected.length; i++) { @@ -649,7 +575,6 @@ abstract class JdbcDatabase implements Database<Connection> { } ps.close(); } catch(SQLException e) { - tryToClose(rs); tryToClose(ps); throw new DbException(e); } @@ -1006,30 +931,6 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public Collection<BatchId> getBatchesToAck(Connection txn, ContactId c, - int maxBatches) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT batchId FROM batchesToAck" - + " WHERE contactId = ?" - + " LIMIT ?"; - ps = txn.prepareStatement(sql); - ps.setInt(1, c.getInt()); - ps.setInt(2, maxBatches); - rs = ps.executeQuery(); - List<BatchId> ids = new ArrayList<BatchId>(); - while(rs.next()) ids.add(new BatchId(rs.getBytes(1))); - rs.close(); - ps.close(); - return Collections.unmodifiableList(ids); - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - } - public TransportConfig getConfig(Connection txn, TransportId t) throws DbException { PreparedStatement ps = null; @@ -1216,27 +1117,10 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public Collection<BatchId> getLostBatches(Connection txn, ContactId c) + public Collection<MessageId> getLostMessages(Connection txn, ContactId c) throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT batchId FROM outstandingBatches" - + " WHERE contactId = ? AND passover >= ?"; - ps = txn.prepareStatement(sql); - ps.setInt(1, c.getInt()); - ps.setInt(2, RETRANSMIT_THRESHOLD); - rs = ps.executeQuery(); - List<BatchId> ids = new ArrayList<BatchId>(); - while(rs.next()) ids.add(new BatchId(rs.getBytes(1))); - rs.close(); - ps.close(); - return Collections.unmodifiableList(ids); - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } + // FIXME: Retransmission + return Collections.emptyList(); } public byte[] getMessage(Connection txn, MessageId m) throws DbException { @@ -1411,6 +1295,30 @@ abstract class JdbcDatabase implements Database<Connection> { } } + public Collection<MessageId> getMessagesToAck(Connection txn, ContactId c, + int maxMessages) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT messageId FROM messagesToAck" + + " WHERE contactId = ?" + + " LIMIT ?"; + ps = txn.prepareStatement(sql); + ps.setInt(1, c.getInt()); + ps.setInt(2, maxMessages); + rs = ps.executeQuery(); + List<MessageId> ids = new ArrayList<MessageId>(); + while(rs.next()) ids.add(new MessageId(rs.getBytes(1))); + rs.close(); + ps.close(); + return Collections.unmodifiableList(ids); + } catch(SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + public int getNumberOfSendableChildren(Connection txn, MessageId m) throws DbException { PreparedStatement ps = null; @@ -1670,7 +1578,7 @@ abstract class JdbcDatabase implements Database<Connection> { } public Collection<MessageId> getSendableMessages(Connection txn, - ContactId c, int capacity) throws DbException { + ContactId c, int maxLength) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { @@ -1688,13 +1596,13 @@ abstract class JdbcDatabase implements Database<Connection> { int total = 0; while(rs.next()) { int length = rs.getInt(1); - if(total + length > capacity) break; + if(total + length > maxLength) break; ids.add(new MessageId(rs.getBytes(2))); total += length; } rs.close(); ps.close(); - if(total == capacity) return Collections.unmodifiableList(ids); + if(total == maxLength) return Collections.unmodifiableList(ids); // Do we have any sendable group messages? sql = "SELECT length, m.messageId FROM messages AS m" + " JOIN contactSubscriptions AS cs" @@ -1719,7 +1627,7 @@ abstract class JdbcDatabase implements Database<Connection> { rs = ps.executeQuery(); while(rs.next()) { int length = rs.getInt(1); - if(total + length > capacity) break; + if(total + length > maxLength) break; ids.add(new MessageId(rs.getBytes(2))); total += length; } @@ -2067,99 +1975,52 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void removeAckedBatch(Connection txn, ContactId c, BatchId b) - throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT timestamp FROM outstandingBatches" - + " WHERE contactId = ? AND batchId = ?"; - ps = txn.prepareStatement(sql); - ps.setInt(1, c.getInt()); - ps.setBytes(2, b.getBytes()); - rs = ps.executeQuery(); - if(!rs.next()) throw new DbStateException(); - long timestamp = rs.getLong(1); - if(rs.next()) throw new DbStateException(); - rs.close(); - ps.close(); - // Increment the passover count of all older outstanding batches - sql = "UPDATE outstandingBatches SET passover = passover + ?" - + " WHERE contactId = ? AND timestamp < ?"; - ps = txn.prepareStatement(sql); - ps.setInt(1, 1); - ps.setInt(2, c.getInt()); - ps.setLong(3, timestamp); - ps.executeUpdate(); - ps.close(); - } catch(SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - removeBatch(txn, c, b, Status.SEEN); + public void removeAckedMessages(Connection txn, ContactId c, + Collection<MessageId> acked) throws DbException { + setStatus(txn, c, acked, Status.SEEN); } - private void removeBatch(Connection txn, ContactId c, BatchId b, - Status newStatus) throws DbException { - PreparedStatement ps = null, ps1 = null; - ResultSet rs = null; + private void setStatus(Connection txn, ContactId c, + Collection<MessageId> ids, Status newStatus) throws DbException { + PreparedStatement ps = null; try { - String sql = "SELECT messageId FROM outstandingMessages" - + " WHERE contactId = ? AND batchId = ?"; - ps = txn.prepareStatement(sql); - ps.setInt(1, c.getInt()); - ps.setBytes(2, b.getBytes()); - rs = ps.executeQuery(); - sql = "UPDATE statuses SET status = ?" + // Set the status of each message if it's currently SENT + String sql = "UPDATE statuses SET status = ?" + " WHERE messageId = ? AND contactId = ? AND status = ?"; - ps1 = txn.prepareStatement(sql); - ps1.setShort(1, (short) newStatus.ordinal()); - ps1.setInt(3, c.getInt()); - ps1.setShort(4, (short) Status.SENT.ordinal()); - int messages = 0; - while(rs.next()) { - messages++; - ps1.setBytes(2, rs.getBytes(1)); - ps1.addBatch(); + ps = txn.prepareStatement(sql); + ps.setShort(1, (short) newStatus.ordinal()); + ps.setInt(3, c.getInt()); + ps.setShort(4, (short) Status.SENT.ordinal()); + for(MessageId m : ids) { + ps.setBytes(2, m.getBytes()); + ps.addBatch(); } - rs.close(); - ps.close(); - int[] batchAffected = ps1.executeBatch(); - if(batchAffected.length != messages) throw new DbStateException(); + int[] batchAffected = ps.executeBatch(); + if(batchAffected.length != ids.size()) throw new DbStateException(); for(int i = 0; i < batchAffected.length; i++) { if(batchAffected[i] > 1) throw new DbStateException(); } - ps1.close(); - // Cascade on delete - sql = "DELETE FROM outstandingBatches WHERE batchId = ?"; - ps = txn.prepareStatement(sql); - ps.setBytes(1, b.getBytes()); - int affected = ps.executeUpdate(); - if(affected > 1) throw new DbStateException(); ps.close(); } catch(SQLException e) { - tryToClose(rs); tryToClose(ps); - tryToClose(ps1); throw new DbException(e); } } - public void removeBatchesToAck(Connection txn, ContactId c, - Collection<BatchId> sent) throws DbException { + public void removeMessagesToAck(Connection txn, ContactId c, + Collection<MessageId> acked) throws DbException { PreparedStatement ps = null; try { - String sql = "DELETE FROM batchesToAck" - + " WHERE contactId = ? and batchId = ?"; + String sql = "DELETE FROM messagesToAck" + + " WHERE contactId = ? AND messageId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); - for(BatchId b : sent) { - ps.setBytes(2, b.getBytes()); + for(MessageId m : acked) { + ps.setBytes(2, m.getBytes()); ps.addBatch(); } int[] batchAffected = ps.executeBatch(); - if(batchAffected.length != sent.size()) + if(batchAffected.length != acked.size()) throw new DbStateException(); for(int i = 0; i < batchAffected.length; i++) { if(batchAffected[i] != 1) throw new DbStateException(); @@ -2187,9 +2048,9 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void removeLostBatch(Connection txn, ContactId c, BatchId b) - throws DbException { - removeBatch(txn, c, b, Status.NEW); + public void removeLostMessages(Connection txn, ContactId c, + Collection<MessageId> lost) throws DbException { + setStatus(txn, c, lost, Status.NEW); } public void removeMessage(Connection txn, MessageId m) throws DbException { diff --git a/briar-core/src/net/sf/briar/protocol/AckImpl.java b/briar-core/src/net/sf/briar/protocol/AckImpl.java index 9b956ff462..ea8e924284 100644 --- a/briar-core/src/net/sf/briar/protocol/AckImpl.java +++ b/briar-core/src/net/sf/briar/protocol/AckImpl.java @@ -3,17 +3,17 @@ package net.sf.briar.protocol; import java.util.Collection; import net.sf.briar.api.protocol.Ack; -import net.sf.briar.api.protocol.BatchId; +import net.sf.briar.api.protocol.MessageId; class AckImpl implements Ack { - private final Collection<BatchId> acked; + private final Collection<MessageId> acked; - AckImpl(Collection<BatchId> acked) { + AckImpl(Collection<MessageId> acked) { this.acked = acked; } - public Collection<BatchId> getBatchIds() { + public Collection<MessageId> getMessageIds() { return acked; } } diff --git a/briar-core/src/net/sf/briar/protocol/AckReader.java b/briar-core/src/net/sf/briar/protocol/AckReader.java index 0b614d7c1b..397a0b66e4 100644 --- a/briar-core/src/net/sf/briar/protocol/AckReader.java +++ b/briar-core/src/net/sf/briar/protocol/AckReader.java @@ -10,7 +10,7 @@ import java.util.List; import net.sf.briar.api.Bytes; 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.MessageId; import net.sf.briar.api.protocol.PacketFactory; import net.sf.briar.api.protocol.Types; import net.sf.briar.api.protocol.UniqueId; @@ -38,14 +38,14 @@ class AckReader implements StructReader<Ack> { r.resetMaxBytesLength(); r.removeConsumer(counting); if(raw.isEmpty()) throw new FormatException(); - // Convert the byte arrays to batch IDs - List<BatchId> batches = new ArrayList<BatchId>(); + // Convert the byte arrays to message IDs + List<MessageId> acked = new ArrayList<MessageId>(); for(Bytes b : raw) { if(b.getBytes().length != UniqueId.LENGTH) throw new FormatException(); - batches.add(new BatchId(b.getBytes())); + acked.add(new MessageId(b.getBytes())); } // Build and return the ack - return packetFactory.createAck(Collections.unmodifiableList(batches)); + return packetFactory.createAck(Collections.unmodifiableList(acked)); } } diff --git a/briar-core/src/net/sf/briar/protocol/BatchImpl.java b/briar-core/src/net/sf/briar/protocol/BatchImpl.java deleted file mode 100644 index 86f54548ea..0000000000 --- a/briar-core/src/net/sf/briar/protocol/BatchImpl.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.sf.briar.protocol; - -import java.util.Collection; - -import net.sf.briar.api.protocol.Batch; -import net.sf.briar.api.protocol.BatchId; -import net.sf.briar.api.protocol.Message; - -/** A simple in-memory implementation of a batch. */ -class BatchImpl implements Batch { - - private final BatchId id; - private final Collection<Message> messages; - - BatchImpl(BatchId id, Collection<Message> messages) { - this.id = id; - this.messages = messages; - } - - public BatchId getId() { - return id; - } - - public Collection<Message> getMessages() { - return messages; - } -} diff --git a/briar-core/src/net/sf/briar/protocol/BatchReader.java b/briar-core/src/net/sf/briar/protocol/BatchReader.java deleted file mode 100644 index e650ac9bb3..0000000000 --- a/briar-core/src/net/sf/briar/protocol/BatchReader.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.sf.briar.protocol; - -import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH; - -import java.io.IOException; -import java.util.List; - -import net.sf.briar.api.FormatException; -import net.sf.briar.api.protocol.Types; -import net.sf.briar.api.protocol.UnverifiedBatch; -import net.sf.briar.api.serial.Consumer; -import net.sf.briar.api.serial.CountingConsumer; -import net.sf.briar.api.serial.StructReader; -import net.sf.briar.api.serial.Reader; - -class BatchReader implements StructReader<UnverifiedBatch> { - - private final StructReader<UnverifiedMessage> messageReader; - private final UnverifiedBatchFactory batchFactory; - - BatchReader(StructReader<UnverifiedMessage> messageReader, - UnverifiedBatchFactory batchFactory) { - this.messageReader = messageReader; - this.batchFactory = batchFactory; - } - - public UnverifiedBatch readStruct(Reader r) throws IOException { - // Initialise the consumer - Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); - // Read the data - r.addConsumer(counting); - r.readStructId(Types.BATCH); - r.addStructReader(Types.MESSAGE, messageReader); - List<UnverifiedMessage> messages = r.readList(UnverifiedMessage.class); - r.removeStructReader(Types.MESSAGE); - r.removeConsumer(counting); - if(messages.isEmpty()) throw new FormatException(); - // Build and return the batch - return batchFactory.createUnverifiedBatch( messages); - } -} diff --git a/briar-core/src/net/sf/briar/protocol/MessageReader.java b/briar-core/src/net/sf/briar/protocol/MessageReader.java index cd62801904..97e9871e40 100644 --- a/briar-core/src/net/sf/briar/protocol/MessageReader.java +++ b/briar-core/src/net/sf/briar/protocol/MessageReader.java @@ -14,10 +14,11 @@ import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Types; import net.sf.briar.api.protocol.UniqueId; +import net.sf.briar.api.protocol.UnverifiedMessage; import net.sf.briar.api.serial.CopyingConsumer; import net.sf.briar.api.serial.CountingConsumer; -import net.sf.briar.api.serial.StructReader; import net.sf.briar.api.serial.Reader; +import net.sf.briar.api.serial.StructReader; class MessageReader implements StructReader<UnverifiedMessage> { diff --git a/briar-core/src/net/sf/briar/protocol/UnverifiedBatchImpl.java b/briar-core/src/net/sf/briar/protocol/MessageVerifierImpl.java similarity index 54% rename from briar-core/src/net/sf/briar/protocol/UnverifiedBatchImpl.java rename to briar-core/src/net/sf/briar/protocol/MessageVerifierImpl.java index 8f1e22c582..cb445a8c9b 100644 --- a/briar-core/src/net/sf/briar/protocol/UnverifiedBatchImpl.java +++ b/briar-core/src/net/sf/briar/protocol/MessageVerifierImpl.java @@ -3,63 +3,44 @@ package net.sf.briar.protocol; import java.security.GeneralSecurityException; import java.security.PublicKey; import java.security.Signature; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.KeyParser; import net.sf.briar.api.crypto.MessageDigest; import net.sf.briar.api.protocol.Author; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.Batch; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; -import net.sf.briar.api.protocol.UnverifiedBatch; +import net.sf.briar.api.protocol.MessageVerifier; +import net.sf.briar.api.protocol.UnverifiedMessage; -class UnverifiedBatchImpl implements UnverifiedBatch { +import com.google.inject.Inject; - private final CryptoComponent crypto; - private final Collection<UnverifiedMessage> messages; - private final MessageDigest batchDigest, messageDigest; +class MessageVerifierImpl implements MessageVerifier { - // Initialise lazily - the batch may contain unsigned messages - private KeyParser keyParser = null; - private Signature signature = null; + private final CryptoComponent crypto; + private final KeyParser keyParser; - UnverifiedBatchImpl(CryptoComponent crypto, - Collection<UnverifiedMessage> messages) { + @Inject + MessageVerifierImpl(CryptoComponent crypto) { this.crypto = crypto; - this.messages = messages; - batchDigest = crypto.getMessageDigest(); - messageDigest = crypto.getMessageDigest(); - } - - public Batch verify() throws GeneralSecurityException { - List<Message> verified = new ArrayList<Message>(); - for(UnverifiedMessage m : messages) verified.add(verify(m)); - BatchId id = new BatchId(batchDigest.digest()); - return new BatchImpl(id, Collections.unmodifiableList(verified)); + keyParser = crypto.getSignatureKeyParser(); } - private Message verify(UnverifiedMessage m) - throws GeneralSecurityException { - // The batch ID is the hash of the concatenated messages - byte[] raw = m.getRaw(); - batchDigest.update(raw); + public Message verifyMessage(UnverifiedMessage m) + throws GeneralSecurityException { + MessageDigest messageDigest = crypto.getMessageDigest(); + Signature signature = crypto.getSignature(); // Hash the message, including the signatures, to get the message ID + byte[] raw = m.getSerialised(); messageDigest.update(raw); MessageId id = new MessageId(messageDigest.digest()); // Verify the author's signature, if there is one Author author = m.getAuthor(); if(author != null) { - if(keyParser == null) keyParser = crypto.getSignatureKeyParser(); PublicKey k = keyParser.parsePublicKey(author.getPublicKey()); - if(signature == null) signature = crypto.getSignature(); signature.initVerify(k); signature.update(raw, 0, m.getLengthSignedByAuthor()); if(!signature.verify(m.getAuthorSignature())) @@ -68,9 +49,7 @@ class UnverifiedBatchImpl implements UnverifiedBatch { // Verify the group's signature, if there is one Group group = m.getGroup(); if(group != null && group.getPublicKey() != null) { - if(keyParser == null) keyParser = crypto.getSignatureKeyParser(); PublicKey k = keyParser.parsePublicKey(group.getPublicKey()); - if(signature == null) signature = crypto.getSignature(); signature.initVerify(k); signature.update(raw, 0, m.getLengthSignedByGroup()); if(!signature.verify(m.getGroupSignature())) diff --git a/briar-core/src/net/sf/briar/protocol/PacketFactoryImpl.java b/briar-core/src/net/sf/briar/protocol/PacketFactoryImpl.java index 75885951d9..a8e9e32c20 100644 --- a/briar-core/src/net/sf/briar/protocol/PacketFactoryImpl.java +++ b/briar-core/src/net/sf/briar/protocol/PacketFactoryImpl.java @@ -4,42 +4,23 @@ import java.util.BitSet; import java.util.Collection; import java.util.Map; -import net.sf.briar.api.crypto.CryptoComponent; -import net.sf.briar.api.crypto.MessageDigest; import net.sf.briar.api.protocol.Ack; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.PacketFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Transport; import net.sf.briar.api.protocol.TransportUpdate; -import com.google.inject.Inject; - class PacketFactoryImpl implements PacketFactory { - private final CryptoComponent crypto; - - @Inject - PacketFactoryImpl(CryptoComponent crypto) { - this.crypto = crypto; - } - - public Ack createAck(Collection<BatchId> acked) { + public Ack createAck(Collection<MessageId> acked) { return new AckImpl(acked); } - public RawBatch createBatch(Collection<byte[]> messages) { - MessageDigest messageDigest = crypto.getMessageDigest(); - for(byte[] raw : messages) messageDigest.update(raw); - return new RawBatchImpl(new BatchId(messageDigest.digest()), messages); - } - public Offer createOffer(Collection<MessageId> offered) { return new OfferImpl(offered); } diff --git a/briar-core/src/net/sf/briar/protocol/ProtocolModule.java b/briar-core/src/net/sf/briar/protocol/ProtocolModule.java index 49b0bd55bc..075f4158b9 100644 --- a/briar-core/src/net/sf/briar/protocol/ProtocolModule.java +++ b/briar-core/src/net/sf/briar/protocol/ProtocolModule.java @@ -9,6 +9,7 @@ import net.sf.briar.api.protocol.AuthorFactory; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.MessageFactory; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.PacketFactory; import net.sf.briar.api.protocol.ProtocolReaderFactory; @@ -16,7 +17,7 @@ import net.sf.briar.api.protocol.ProtocolWriterFactory; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.TransportUpdate; -import net.sf.briar.api.protocol.UnverifiedBatch; +import net.sf.briar.api.protocol.UnverifiedMessage; import net.sf.briar.api.protocol.VerificationExecutor; import net.sf.briar.api.serial.StructReader; import net.sf.briar.util.BoundedExecutor; @@ -46,10 +47,10 @@ public class ProtocolModule extends AbstractModule { bind(AuthorFactory.class).to(AuthorFactoryImpl.class); bind(GroupFactory.class).to(GroupFactoryImpl.class); bind(MessageFactory.class).to(MessageFactoryImpl.class); + bind(MessageVerifier.class).to(MessageVerifierImpl.class); bind(PacketFactory.class).to(PacketFactoryImpl.class); bind(ProtocolReaderFactory.class).to(ProtocolReaderFactoryImpl.class); bind(ProtocolWriterFactory.class).to(ProtocolWriterFactoryImpl.class); - bind(UnverifiedBatchFactory.class).to(UnverifiedBatchFactoryImpl.class); // The executor is bounded, so tasks must be independent and short-lived bind(Executor.class).annotatedWith( VerificationExecutor.class).toInstance( @@ -68,13 +69,6 @@ public class ProtocolModule extends AbstractModule { return new AuthorReader(crypto, authorFactory); } - @Provides - StructReader<UnverifiedBatch> getBatchReader( - StructReader<UnverifiedMessage> messageReader, - UnverifiedBatchFactory batchFactory) { - return new BatchReader(messageReader, batchFactory); - } - @Provides StructReader<Group> getGroupReader(CryptoComponent crypto) { return new GroupReader(crypto); diff --git a/briar-core/src/net/sf/briar/protocol/ProtocolReaderFactoryImpl.java b/briar-core/src/net/sf/briar/protocol/ProtocolReaderFactoryImpl.java index 0a2ff03307..3ac7649d52 100644 --- a/briar-core/src/net/sf/briar/protocol/ProtocolReaderFactoryImpl.java +++ b/briar-core/src/net/sf/briar/protocol/ProtocolReaderFactoryImpl.java @@ -9,9 +9,9 @@ import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.TransportUpdate; -import net.sf.briar.api.protocol.UnverifiedBatch; -import net.sf.briar.api.serial.StructReader; +import net.sf.briar.api.protocol.UnverifiedMessage; import net.sf.briar.api.serial.ReaderFactory; +import net.sf.briar.api.serial.StructReader; import com.google.inject.Inject; import com.google.inject.Provider; @@ -20,7 +20,7 @@ class ProtocolReaderFactoryImpl implements ProtocolReaderFactory { private final ReaderFactory readerFactory; private final Provider<StructReader<Ack>> ackProvider; - private final Provider<StructReader<UnverifiedBatch>> batchProvider; + private final Provider<StructReader<UnverifiedMessage>> messageProvider; private final Provider<StructReader<Offer>> offerProvider; private final Provider<StructReader<Request>> requestProvider; private final Provider<StructReader<SubscriptionUpdate>> subscriptionProvider; @@ -29,14 +29,14 @@ class ProtocolReaderFactoryImpl implements ProtocolReaderFactory { @Inject ProtocolReaderFactoryImpl(ReaderFactory readerFactory, Provider<StructReader<Ack>> ackProvider, - Provider<StructReader<UnverifiedBatch>> batchProvider, + Provider<StructReader<UnverifiedMessage>> messageProvider, Provider<StructReader<Offer>> offerProvider, Provider<StructReader<Request>> requestProvider, Provider<StructReader<SubscriptionUpdate>> subscriptionProvider, Provider<StructReader<TransportUpdate>> transportProvider) { this.readerFactory = readerFactory; this.ackProvider = ackProvider; - this.batchProvider = batchProvider; + this.messageProvider = messageProvider; this.offerProvider = offerProvider; this.requestProvider = requestProvider; this.subscriptionProvider = subscriptionProvider; @@ -45,7 +45,8 @@ class ProtocolReaderFactoryImpl implements ProtocolReaderFactory { public ProtocolReader createProtocolReader(InputStream in) { return new ProtocolReaderImpl(in, readerFactory, ackProvider.get(), - batchProvider.get(), offerProvider.get(), requestProvider.get(), - subscriptionProvider.get(), transportProvider.get()); + messageProvider.get(), offerProvider.get(), + requestProvider.get(), subscriptionProvider.get(), + transportProvider.get()); } } diff --git a/briar-core/src/net/sf/briar/protocol/ProtocolReaderImpl.java b/briar-core/src/net/sf/briar/protocol/ProtocolReaderImpl.java index cf6ff211f4..05c2562964 100644 --- a/briar-core/src/net/sf/briar/protocol/ProtocolReaderImpl.java +++ b/briar-core/src/net/sf/briar/protocol/ProtocolReaderImpl.java @@ -10,10 +10,10 @@ import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.Types; -import net.sf.briar.api.protocol.UnverifiedBatch; -import net.sf.briar.api.serial.StructReader; +import net.sf.briar.api.protocol.UnverifiedMessage; import net.sf.briar.api.serial.Reader; import net.sf.briar.api.serial.ReaderFactory; +import net.sf.briar.api.serial.StructReader; class ProtocolReaderImpl implements ProtocolReader { @@ -21,14 +21,14 @@ class ProtocolReaderImpl implements ProtocolReader { ProtocolReaderImpl(InputStream in, ReaderFactory readerFactory, StructReader<Ack> ackReader, - StructReader<UnverifiedBatch> batchReader, + StructReader<UnverifiedMessage> messageReader, StructReader<Offer> offerReader, StructReader<Request> requestReader, StructReader<SubscriptionUpdate> subscriptionReader, StructReader<TransportUpdate> transportReader) { reader = readerFactory.createReader(in); reader.addStructReader(Types.ACK, ackReader); - reader.addStructReader(Types.BATCH, batchReader); + reader.addStructReader(Types.MESSAGE, messageReader); reader.addStructReader(Types.OFFER, offerReader); reader.addStructReader(Types.REQUEST, requestReader); reader.addStructReader(Types.SUBSCRIPTION_UPDATE, subscriptionReader); @@ -47,12 +47,12 @@ class ProtocolReaderImpl implements ProtocolReader { return reader.readStruct(Types.ACK, Ack.class); } - public boolean hasBatch() throws IOException { - return reader.hasStruct(Types.BATCH); + public boolean hasMessage() throws IOException { + return reader.hasStruct(Types.MESSAGE); } - public UnverifiedBatch readBatch() throws IOException { - return reader.readStruct(Types.BATCH, UnverifiedBatch.class); + public UnverifiedMessage readMessage() throws IOException { + return reader.readStruct(Types.MESSAGE, UnverifiedMessage.class); } public boolean hasOffer() throws IOException { diff --git a/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java b/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java index fd100d561e..0fda305552 100644 --- a/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java +++ b/briar-core/src/net/sf/briar/protocol/ProtocolWriterImpl.java @@ -8,13 +8,11 @@ import java.util.BitSet; import java.util.Map.Entry; import net.sf.briar.api.protocol.Ack; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.ProtocolWriter; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Transport; @@ -40,11 +38,11 @@ class ProtocolWriterImpl implements ProtocolWriter { w = writerFactory.createWriter(out); } - public int getMaxBatchesForAck(long capacity) { + public int getMaxMessagesForAck(long capacity) { int packet = (int) Math.min(capacity, MAX_PACKET_LENGTH); int overhead = serial.getSerialisedStructIdLength(Types.ACK) - + serial.getSerialisedListStartLength() - + serial.getSerialisedListEndLength(); + + serial.getSerialisedListStartLength() + + serial.getSerialisedListEndLength(); int idLength = serial.getSerialisedUniqueIdLength(); return (packet - overhead) / idLength; } @@ -52,33 +50,22 @@ class ProtocolWriterImpl implements ProtocolWriter { public int getMaxMessagesForOffer(long capacity) { int packet = (int) Math.min(capacity, MAX_PACKET_LENGTH); int overhead = serial.getSerialisedStructIdLength(Types.OFFER) - + serial.getSerialisedListStartLength() - + serial.getSerialisedListEndLength(); + + serial.getSerialisedListStartLength() + + serial.getSerialisedListEndLength(); int idLength = serial.getSerialisedUniqueIdLength(); return (packet - overhead) / idLength; } - public int getMessageCapacityForBatch(long capacity) { - int packet = (int) Math.min(capacity, MAX_PACKET_LENGTH); - int overhead = serial.getSerialisedStructIdLength(Types.BATCH) - + serial.getSerialisedListStartLength() - + serial.getSerialisedListEndLength(); - return packet - overhead; - } - public void writeAck(Ack a) throws IOException { w.writeStructId(Types.ACK); w.writeListStart(); - for(BatchId b : a.getBatchIds()) w.writeBytes(b.getBytes()); + for(MessageId m : a.getMessageIds()) w.writeBytes(m.getBytes()); w.writeListEnd(); if(flush) out.flush(); } - public void writeBatch(RawBatch b) throws IOException { - w.writeStructId(Types.BATCH); - w.writeListStart(); - for(byte[] raw : b.getMessages()) out.write(raw); - w.writeListEnd(); + public void writeMessage(byte[] raw) throws IOException { + out.write(raw); if(flush) out.flush(); } @@ -111,7 +98,7 @@ class ProtocolWriterImpl implements ProtocolWriter { } public void writeSubscriptionUpdate(SubscriptionUpdate s) - throws IOException { + throws IOException { w.writeStructId(Types.SUBSCRIPTION_UPDATE); // Holes w.writeMapStart(); diff --git a/briar-core/src/net/sf/briar/protocol/RawBatchImpl.java b/briar-core/src/net/sf/briar/protocol/RawBatchImpl.java deleted file mode 100644 index 06da27023c..0000000000 --- a/briar-core/src/net/sf/briar/protocol/RawBatchImpl.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.sf.briar.protocol; - -import java.util.Collection; - -import net.sf.briar.api.protocol.BatchId; -import net.sf.briar.api.protocol.RawBatch; - -class RawBatchImpl implements RawBatch { - - private final BatchId id; - private final Collection<byte[]> messages; - - RawBatchImpl(BatchId id, Collection<byte[]> messages) { - this.id = id; - this.messages = messages; - } - - public BatchId getId() { - return id; - } - - public Collection<byte[]> getMessages() { - return messages; - } -} diff --git a/briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactory.java b/briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactory.java deleted file mode 100644 index 93e20ac8aa..0000000000 --- a/briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactory.java +++ /dev/null @@ -1,11 +0,0 @@ -package net.sf.briar.protocol; - -import java.util.Collection; - -import net.sf.briar.api.protocol.UnverifiedBatch; - -interface UnverifiedBatchFactory { - - UnverifiedBatch createUnverifiedBatch( - Collection<UnverifiedMessage> messages); -} diff --git a/briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactoryImpl.java b/briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactoryImpl.java deleted file mode 100644 index 980c09db57..0000000000 --- a/briar-core/src/net/sf/briar/protocol/UnverifiedBatchFactoryImpl.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.sf.briar.protocol; - -import java.util.Collection; - -import net.sf.briar.api.crypto.CryptoComponent; -import net.sf.briar.api.protocol.UnverifiedBatch; - -import com.google.inject.Inject; - -class UnverifiedBatchFactoryImpl implements UnverifiedBatchFactory { - - private final CryptoComponent crypto; - - @Inject - UnverifiedBatchFactoryImpl(CryptoComponent crypto) { - this.crypto = crypto; - } - - public UnverifiedBatch createUnverifiedBatch( - Collection<UnverifiedMessage> messages) { - return new UnverifiedBatchImpl(crypto, messages); - } -} diff --git a/briar-core/src/net/sf/briar/protocol/UnverifiedMessageImpl.java b/briar-core/src/net/sf/briar/protocol/UnverifiedMessageImpl.java index dd3f941c62..57cdb0fc69 100644 --- a/briar-core/src/net/sf/briar/protocol/UnverifiedMessageImpl.java +++ b/briar-core/src/net/sf/briar/protocol/UnverifiedMessageImpl.java @@ -3,6 +3,7 @@ package net.sf.briar.protocol; import net.sf.briar.api.protocol.Author; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.MessageId; +import net.sf.briar.api.protocol.UnverifiedMessage; class UnverifiedMessageImpl implements UnverifiedMessage { @@ -52,7 +53,7 @@ class UnverifiedMessageImpl implements UnverifiedMessage { return timestamp; } - public byte[] getRaw() { + public byte[] getSerialised() { return raw; } diff --git a/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnection.java b/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnection.java index 4eb35d8b70..24d084bc85 100644 --- a/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnection.java +++ b/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnection.java @@ -24,28 +24,28 @@ import net.sf.briar.api.FormatException; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseExecutor; import net.sf.briar.api.db.DbException; -import net.sf.briar.api.db.event.BatchReceivedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.LocalTransportsUpdatedEvent; -import net.sf.briar.api.db.event.MessagesAddedEvent; +import net.sf.briar.api.db.event.MessageAddedEvent; +import net.sf.briar.api.db.event.MessageReceivedEvent; import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent; import net.sf.briar.api.plugins.duplex.DuplexTransportConnection; import net.sf.briar.api.protocol.Ack; -import net.sf.briar.api.protocol.Batch; +import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.ProtocolReader; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.ProtocolWriter; import net.sf.briar.api.protocol.ProtocolWriterFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportUpdate; -import net.sf.briar.api.protocol.UnverifiedBatch; +import net.sf.briar.api.protocol.UnverifiedMessage; import net.sf.briar.api.protocol.VerificationExecutor; import net.sf.briar.api.transport.ConnectionContext; import net.sf.briar.api.transport.ConnectionReader; @@ -76,6 +76,7 @@ abstract class DuplexConnection implements DatabaseListener { protected final TransportId transportId; private final Executor dbExecutor, verificationExecutor; + private final MessageVerifier messageVerifier; private final AtomicBoolean canSendOffer, disposed; private final BlockingQueue<Runnable> writerTasks; @@ -85,7 +86,8 @@ abstract class DuplexConnection implements DatabaseListener { DuplexConnection(@DatabaseExecutor Executor dbExecutor, @VerificationExecutor Executor verificationExecutor, - DatabaseComponent db, ConnectionRegistry connRegistry, + MessageVerifier messageVerifier, DatabaseComponent db, + ConnectionRegistry connRegistry, ConnectionReaderFactory connReaderFactory, ConnectionWriterFactory connWriterFactory, ProtocolReaderFactory protoReaderFactory, @@ -93,6 +95,7 @@ abstract class DuplexConnection implements DatabaseListener { DuplexTransportConnection transport) { this.dbExecutor = dbExecutor; this.verificationExecutor = verificationExecutor; + this.messageVerifier = messageVerifier; this.db = db; this.connRegistry = connRegistry; this.connReaderFactory = connReaderFactory; @@ -115,12 +118,12 @@ abstract class DuplexConnection implements DatabaseListener { throws IOException; public void eventOccurred(DatabaseEvent e) { - if(e instanceof BatchReceivedEvent) { + if(e instanceof MessageReceivedEvent) { dbExecutor.execute(new GenerateAcks()); } else if(e instanceof ContactRemovedEvent) { ContactId c = ((ContactRemovedEvent) e).getContactId(); if(contactId.equals(c)) dispose(false, true); - } else if(e instanceof MessagesAddedEvent) { + } else if(e instanceof MessageAddedEvent) { if(canSendOffer.getAndSet(false)) dbExecutor.execute(new GenerateOffer()); } else if(e instanceof SubscriptionsUpdatedEvent) { @@ -142,9 +145,9 @@ abstract class DuplexConnection implements DatabaseListener { if(reader.hasAck()) { Ack a = reader.readAck(); dbExecutor.execute(new ReceiveAck(a)); - } else if(reader.hasBatch()) { - UnverifiedBatch b = reader.readBatch(); - verificationExecutor.execute(new VerifyBatch(b)); + } else if(reader.hasMessage()) { + UnverifiedMessage m = reader.readMessage(); + verificationExecutor.execute(new VerifyMessage(m)); } else if(reader.hasOffer()) { Offer o = reader.readOffer(); dbExecutor.execute(new ReceiveOffer(o)); @@ -260,18 +263,18 @@ abstract class DuplexConnection implements DatabaseListener { } // This task runs on a verification thread - private class VerifyBatch implements Runnable { + private class VerifyMessage implements Runnable { - private final UnverifiedBatch batch; + private final UnverifiedMessage message; - private VerifyBatch(UnverifiedBatch batch) { - this.batch = batch; + private VerifyMessage(UnverifiedMessage message) { + this.message = message; } public void run() { try { - Batch b = batch.verify(); - dbExecutor.execute(new ReceiveBatch(b)); + Message m = messageVerifier.verifyMessage(message); + dbExecutor.execute(new ReceiveMessage(m)); } catch(GeneralSecurityException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } @@ -279,17 +282,17 @@ abstract class DuplexConnection implements DatabaseListener { } // This task runs on a database thread - private class ReceiveBatch implements Runnable { + private class ReceiveMessage implements Runnable { - private final Batch batch; + private final Message message; - private ReceiveBatch(Batch batch) { - this.batch = batch; + private ReceiveMessage(Message message) { + this.message = message; } public void run() { try { - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, message); } catch(DbException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } @@ -394,9 +397,9 @@ abstract class DuplexConnection implements DatabaseListener { public void run() { assert writer != null; - int maxBatches = writer.getMaxBatchesForAck(Long.MAX_VALUE); + int maxMessages = writer.getMaxMessagesForAck(Long.MAX_VALUE); try { - Ack a = db.generateAck(contactId, maxBatches); + Ack a = db.generateAck(contactId, maxMessages); if(a != null) writerTasks.add(new WriteAck(a)); } catch(DbException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); @@ -436,11 +439,11 @@ abstract class DuplexConnection implements DatabaseListener { public void run() { assert writer != null; - int capacity = writer.getMessageCapacityForBatch(Long.MAX_VALUE); try { - RawBatch b = db.generateBatch(contactId, capacity, requested); - if(b == null) new GenerateOffer().run(); - else writerTasks.add(new WriteBatch(b, requested)); + Collection<byte[]> batch = db.generateBatch(contactId, + Integer.MAX_VALUE, requested); + if(batch == null) new GenerateOffer().run(); + else writerTasks.add(new WriteBatch(batch, requested)); } catch(DbException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } @@ -450,10 +453,11 @@ abstract class DuplexConnection implements DatabaseListener { // This task runs on the writer thread private class WriteBatch implements Runnable { - private final RawBatch batch; + private final Collection<byte[]> batch; private final Collection<MessageId> requested; - private WriteBatch(RawBatch batch, Collection<MessageId> requested) { + private WriteBatch(Collection<byte[]> batch, + Collection<MessageId> requested) { this.batch = batch; this.requested = requested; } @@ -461,7 +465,7 @@ abstract class DuplexConnection implements DatabaseListener { public void run() { assert writer != null; try { - writer.writeBatch(batch); + for(byte[] raw : batch) writer.writeMessage(raw); if(requested.isEmpty()) dbExecutor.execute(new GenerateOffer()); else dbExecutor.execute(new GenerateBatches(requested)); } catch(IOException e) { diff --git a/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnectionFactoryImpl.java b/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnectionFactoryImpl.java index c005162d39..e60f9c0be7 100644 --- a/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnectionFactoryImpl.java +++ b/briar-core/src/net/sf/briar/protocol/duplex/DuplexConnectionFactoryImpl.java @@ -10,6 +10,7 @@ import net.sf.briar.api.crypto.KeyManager; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseExecutor; import net.sf.briar.api.plugins.duplex.DuplexTransportConnection; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.ProtocolWriterFactory; import net.sf.briar.api.protocol.TransportId; @@ -28,6 +29,7 @@ class DuplexConnectionFactoryImpl implements DuplexConnectionFactory { Logger.getLogger(DuplexConnectionFactoryImpl.class.getName()); private final Executor dbExecutor, verificationExecutor; + private final MessageVerifier messageVerifier; private final DatabaseComponent db; private final KeyManager keyManager; private final ConnectionRegistry connRegistry; @@ -39,13 +41,14 @@ class DuplexConnectionFactoryImpl implements DuplexConnectionFactory { @Inject DuplexConnectionFactoryImpl(@DatabaseExecutor Executor dbExecutor, @VerificationExecutor Executor verificationExecutor, - DatabaseComponent db, KeyManager keyManager, - ConnectionRegistry connRegistry, + MessageVerifier messageVerifier, DatabaseComponent db, + KeyManager keyManager, ConnectionRegistry connRegistry, ConnectionReaderFactory connReaderFactory, ConnectionWriterFactory connWriterFactory, ProtocolReaderFactory protoReaderFactory, ProtocolWriterFactory protoWriterFactory) { this.dbExecutor = dbExecutor; this.verificationExecutor = verificationExecutor; + this.messageVerifier = messageVerifier; this.db = db; this.keyManager = keyManager; this.connRegistry = connRegistry; @@ -58,9 +61,9 @@ class DuplexConnectionFactoryImpl implements DuplexConnectionFactory { public void createIncomingConnection(ConnectionContext ctx, DuplexTransportConnection transport) { final DuplexConnection conn = new IncomingDuplexConnection(dbExecutor, - verificationExecutor, db, connRegistry, connReaderFactory, - connWriterFactory, protoReaderFactory, protoWriterFactory, ctx, - transport); + verificationExecutor, messageVerifier, db, connRegistry, + connReaderFactory, connWriterFactory, protoReaderFactory, + protoWriterFactory, ctx, transport); Runnable write = new Runnable() { public void run() { conn.write(); @@ -84,9 +87,9 @@ class DuplexConnectionFactoryImpl implements DuplexConnectionFactory { return; } final DuplexConnection conn = new OutgoingDuplexConnection(dbExecutor, - verificationExecutor, db, connRegistry, connReaderFactory, - connWriterFactory, protoReaderFactory, protoWriterFactory, ctx, - transport); + verificationExecutor, messageVerifier, db, connRegistry, + connReaderFactory, connWriterFactory, protoReaderFactory, + protoWriterFactory, ctx, transport); Runnable write = new Runnable() { public void run() { conn.write(); diff --git a/briar-core/src/net/sf/briar/protocol/duplex/IncomingDuplexConnection.java b/briar-core/src/net/sf/briar/protocol/duplex/IncomingDuplexConnection.java index 3ec37b99cf..2f5b006eca 100644 --- a/briar-core/src/net/sf/briar/protocol/duplex/IncomingDuplexConnection.java +++ b/briar-core/src/net/sf/briar/protocol/duplex/IncomingDuplexConnection.java @@ -6,6 +6,7 @@ import java.util.concurrent.Executor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseExecutor; import net.sf.briar.api.plugins.duplex.DuplexTransportConnection; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.ProtocolWriterFactory; import net.sf.briar.api.protocol.VerificationExecutor; @@ -20,15 +21,16 @@ class IncomingDuplexConnection extends DuplexConnection { IncomingDuplexConnection(@DatabaseExecutor Executor dbExecutor, @VerificationExecutor Executor verificationExecutor, - DatabaseComponent db, ConnectionRegistry connRegistry, + MessageVerifier messageVerifier, DatabaseComponent db, + ConnectionRegistry connRegistry, ConnectionReaderFactory connReaderFactory, ConnectionWriterFactory connWriterFactory, ProtocolReaderFactory protoReaderFactory, ProtocolWriterFactory protoWriterFactory, ConnectionContext ctx, DuplexTransportConnection transport) { - super(dbExecutor, verificationExecutor, db, connRegistry, - connReaderFactory, connWriterFactory, protoReaderFactory, - protoWriterFactory, ctx, transport); + super(dbExecutor, verificationExecutor, messageVerifier, db, + connRegistry, connReaderFactory, connWriterFactory, + protoReaderFactory, protoWriterFactory, ctx, transport); } @Override diff --git a/briar-core/src/net/sf/briar/protocol/duplex/OutgoingDuplexConnection.java b/briar-core/src/net/sf/briar/protocol/duplex/OutgoingDuplexConnection.java index 8be0202ff6..4b67f433fb 100644 --- a/briar-core/src/net/sf/briar/protocol/duplex/OutgoingDuplexConnection.java +++ b/briar-core/src/net/sf/briar/protocol/duplex/OutgoingDuplexConnection.java @@ -6,6 +6,7 @@ import java.util.concurrent.Executor; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseExecutor; import net.sf.briar.api.plugins.duplex.DuplexTransportConnection; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.ProtocolWriterFactory; import net.sf.briar.api.protocol.VerificationExecutor; @@ -20,15 +21,16 @@ class OutgoingDuplexConnection extends DuplexConnection { OutgoingDuplexConnection(@DatabaseExecutor Executor dbExecutor, @VerificationExecutor Executor verificationExecutor, - DatabaseComponent db, ConnectionRegistry connRegistry, + MessageVerifier messageVerifier, DatabaseComponent db, + ConnectionRegistry connRegistry, ConnectionReaderFactory connReaderFactory, ConnectionWriterFactory connWriterFactory, ProtocolReaderFactory protoReaderFactory, ProtocolWriterFactory protoWriterFactory, ConnectionContext ctx, DuplexTransportConnection transport) { - super(dbExecutor, verificationExecutor, db, connRegistry, - connReaderFactory, connWriterFactory, protoReaderFactory, - protoWriterFactory, ctx, transport); + super(dbExecutor, verificationExecutor, messageVerifier, db, + connRegistry, connReaderFactory, connWriterFactory, + protoReaderFactory, protoWriterFactory, ctx, transport); } @Override diff --git a/briar-core/src/net/sf/briar/protocol/simplex/IncomingSimplexConnection.java b/briar-core/src/net/sf/briar/protocol/simplex/IncomingSimplexConnection.java index 24ae0701b8..ffc6b8479d 100644 --- a/briar-core/src/net/sf/briar/protocol/simplex/IncomingSimplexConnection.java +++ b/briar-core/src/net/sf/briar/protocol/simplex/IncomingSimplexConnection.java @@ -15,13 +15,14 @@ import net.sf.briar.api.db.DatabaseExecutor; import net.sf.briar.api.db.DbException; import net.sf.briar.api.plugins.simplex.SimplexTransportReader; import net.sf.briar.api.protocol.Ack; -import net.sf.briar.api.protocol.Batch; +import net.sf.briar.api.protocol.Message; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.ProtocolReader; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportUpdate; -import net.sf.briar.api.protocol.UnverifiedBatch; +import net.sf.briar.api.protocol.UnverifiedMessage; import net.sf.briar.api.protocol.VerificationExecutor; import net.sf.briar.api.transport.ConnectionContext; import net.sf.briar.api.transport.ConnectionReader; @@ -35,6 +36,7 @@ class IncomingSimplexConnection { Logger.getLogger(IncomingSimplexConnection.class.getName()); private final Executor dbExecutor, verificationExecutor; + private final MessageVerifier messageVerifier; private final DatabaseComponent db; private final ConnectionRegistry connRegistry; private final ConnectionReaderFactory connFactory; @@ -46,12 +48,14 @@ class IncomingSimplexConnection { IncomingSimplexConnection(@DatabaseExecutor Executor dbExecutor, @VerificationExecutor Executor verificationExecutor, - DatabaseComponent db, ConnectionRegistry connRegistry, + MessageVerifier messageVerifier, DatabaseComponent db, + ConnectionRegistry connRegistry, ConnectionReaderFactory connFactory, ProtocolReaderFactory protoFactory, ConnectionContext ctx, SimplexTransportReader transport) { this.dbExecutor = dbExecutor; this.verificationExecutor = verificationExecutor; + this.messageVerifier = messageVerifier; this.db = db; this.connRegistry = connRegistry; this.connFactory = connFactory; @@ -74,9 +78,9 @@ class IncomingSimplexConnection { if(reader.hasAck()) { Ack a = reader.readAck(); dbExecutor.execute(new ReceiveAck(a)); - } else if(reader.hasBatch()) { - UnverifiedBatch b = reader.readBatch(); - verificationExecutor.execute(new VerifyBatch(b)); + } else if(reader.hasMessage()) { + UnverifiedMessage m = reader.readMessage(); + verificationExecutor.execute(new VerifyMessage(m)); } else if(reader.hasSubscriptionUpdate()) { SubscriptionUpdate s = reader.readSubscriptionUpdate(); dbExecutor.execute(new ReceiveSubscriptionUpdate(s)); @@ -122,35 +126,35 @@ class IncomingSimplexConnection { } } - private class VerifyBatch implements Runnable { + private class VerifyMessage implements Runnable { - private final UnverifiedBatch batch; + private final UnverifiedMessage message; - private VerifyBatch(UnverifiedBatch batch) { - this.batch = batch; + private VerifyMessage(UnverifiedMessage message) { + this.message = message; } public void run() { try { - Batch b = batch.verify(); - dbExecutor.execute(new ReceiveBatch(b)); + Message m = messageVerifier.verifyMessage(message); + dbExecutor.execute(new ReceiveMessage(m)); } catch(GeneralSecurityException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } } } - private class ReceiveBatch implements Runnable { + private class ReceiveMessage implements Runnable { - private final Batch batch; + private final Message message; - private ReceiveBatch(Batch batch) { - this.batch = batch; + private ReceiveMessage(Message message) { + this.message = message; } public void run() { try { - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, message); } catch(DbException e) { if(LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); } diff --git a/briar-core/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnection.java b/briar-core/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnection.java index eea83eeddf..e53facc463 100644 --- a/briar-core/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnection.java +++ b/briar-core/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnection.java @@ -6,6 +6,7 @@ import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH; import java.io.EOFException; import java.io.IOException; import java.io.OutputStream; +import java.util.Collection; import java.util.logging.Logger; import net.sf.briar.api.ContactId; @@ -15,7 +16,6 @@ import net.sf.briar.api.plugins.simplex.SimplexTransportWriter; import net.sf.briar.api.protocol.Ack; import net.sf.briar.api.protocol.ProtocolWriter; import net.sf.briar.api.protocol.ProtocolWriterFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportUpdate; @@ -77,23 +77,23 @@ class OutgoingSimplexConnection { } // Write acks until you can't write acks no more capacity = conn.getRemainingCapacity(); - int maxBatches = writer.getMaxBatchesForAck(capacity); - Ack a = db.generateAck(contactId, maxBatches); + int maxMessages = writer.getMaxMessagesForAck(capacity); + Ack a = db.generateAck(contactId, maxMessages); while(a != null) { writer.writeAck(a); capacity = conn.getRemainingCapacity(); - maxBatches = writer.getMaxBatchesForAck(capacity); - a = db.generateAck(contactId, maxBatches); + maxMessages = writer.getMaxMessagesForAck(capacity); + a = db.generateAck(contactId, maxMessages); } - // Write batches until you can't write batches no more + // Write messages until you can't write messages no more capacity = conn.getRemainingCapacity(); - capacity = writer.getMessageCapacityForBatch(capacity); - RawBatch b = db.generateBatch(contactId, (int) capacity); - while(b != null) { - writer.writeBatch(b); + int maxLength = (int) Math.min(capacity, MAX_PACKET_LENGTH); + Collection<byte[]> batch = db.generateBatch(contactId, maxLength); + while(batch != null) { + for(byte[] raw : batch) writer.writeMessage(raw); capacity = conn.getRemainingCapacity(); - capacity = writer.getMessageCapacityForBatch(capacity); - b = db.generateBatch(contactId, (int) capacity); + maxLength = (int) Math.min(capacity, MAX_PACKET_LENGTH); + batch = db.generateBatch(contactId, maxLength); } writer.flush(); writer.close(); diff --git a/briar-core/src/net/sf/briar/protocol/simplex/SimplexConnectionFactoryImpl.java b/briar-core/src/net/sf/briar/protocol/simplex/SimplexConnectionFactoryImpl.java index e8cb98768d..6f6736ca3c 100644 --- a/briar-core/src/net/sf/briar/protocol/simplex/SimplexConnectionFactoryImpl.java +++ b/briar-core/src/net/sf/briar/protocol/simplex/SimplexConnectionFactoryImpl.java @@ -11,6 +11,7 @@ import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseExecutor; import net.sf.briar.api.plugins.simplex.SimplexTransportReader; import net.sf.briar.api.plugins.simplex.SimplexTransportWriter; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.ProtocolWriterFactory; import net.sf.briar.api.protocol.TransportId; @@ -29,6 +30,7 @@ class SimplexConnectionFactoryImpl implements SimplexConnectionFactory { Logger.getLogger(SimplexConnectionFactoryImpl.class.getName()); private final Executor dbExecutor, verificationExecutor; + private final MessageVerifier messageVerifier; private final DatabaseComponent db; private final KeyManager keyManager; private final ConnectionRegistry connRegistry; @@ -40,14 +42,15 @@ class SimplexConnectionFactoryImpl implements SimplexConnectionFactory { @Inject SimplexConnectionFactoryImpl(@DatabaseExecutor Executor dbExecutor, @VerificationExecutor Executor verificationExecutor, - DatabaseComponent db, KeyManager keyManager, - ConnectionRegistry connRegistry, + MessageVerifier messageVerifier, DatabaseComponent db, + KeyManager keyManager, ConnectionRegistry connRegistry, ConnectionReaderFactory connReaderFactory, ConnectionWriterFactory connWriterFactory, ProtocolReaderFactory protoReaderFactory, ProtocolWriterFactory protoWriterFactory) { this.dbExecutor = dbExecutor; this.verificationExecutor = verificationExecutor; + this.messageVerifier = messageVerifier; this.db = db; this.keyManager = keyManager; this.connRegistry = connRegistry; @@ -59,8 +62,8 @@ class SimplexConnectionFactoryImpl implements SimplexConnectionFactory { public void createIncomingConnection(ConnectionContext ctx, SimplexTransportReader r) { final IncomingSimplexConnection conn = new IncomingSimplexConnection( - dbExecutor, verificationExecutor, db, connRegistry, - connReaderFactory, protoReaderFactory, ctx, r); + dbExecutor, verificationExecutor, messageVerifier, db, + connRegistry, connReaderFactory, protoReaderFactory, ctx, r); Runnable read = new Runnable() { public void run() { conn.read(); diff --git a/briar-tests/build.xml b/briar-tests/build.xml index f1171d9052..5211bfe17a 100644 --- a/briar-tests/build.xml +++ b/briar-tests/build.xml @@ -89,14 +89,11 @@ <test name='net.sf.briar.plugins.modem.ModemPluginTest'/> <test name='net.sf.briar.plugins.tcp.LanTcpPluginTest'/> <test name='net.sf.briar.protocol.AckReaderTest'/> - <test name='net.sf.briar.protocol.BatchReaderTest'/> <test name='net.sf.briar.protocol.ConstantsTest'/> <test name='net.sf.briar.protocol.ConsumersTest'/> <test name='net.sf.briar.protocol.OfferReaderTest'/> - <test name='net.sf.briar.protocol.ProtocolIntegrationTest'/> <test name='net.sf.briar.protocol.ProtocolWriterImplTest'/> <test name='net.sf.briar.protocol.RequestReaderTest'/> - <test name='net.sf.briar.protocol.UnverifiedBatchImplTest'/> <test name='net.sf.briar.protocol.simplex.OutgoingSimplexConnectionTest'/> <test name='net.sf.briar.protocol.simplex.SimplexProtocolIntegrationTest'/> <test name='net.sf.briar.serial.ReaderImplTest'/> diff --git a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java index bbd7af2f9a..c0be507489 100644 --- a/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java +++ b/briar-tests/src/net/sf/briar/ProtocolIntegrationTest.java @@ -12,7 +12,6 @@ import java.util.Arrays; import java.util.BitSet; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.Random; @@ -22,26 +21,25 @@ 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.Batch; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageFactory; import net.sf.briar.api.protocol.MessageId; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.PacketFactory; import net.sf.briar.api.protocol.ProtocolReader; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.ProtocolWriter; import net.sf.briar.api.protocol.ProtocolWriterFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Transport; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportUpdate; +import net.sf.briar.api.protocol.UnverifiedMessage; import net.sf.briar.api.transport.ConnectionContext; import net.sf.briar.api.transport.ConnectionReader; import net.sf.briar.api.transport.ConnectionReaderFactory; @@ -64,15 +62,13 @@ import com.google.inject.Injector; public class ProtocolIntegrationTest extends BriarTestCase { - private final BatchId ack = new BatchId(TestUtils.getRandomId()); - private final long timestamp = System.currentTimeMillis(); - private final ConnectionReaderFactory connectionReaderFactory; private final ConnectionWriterFactory connectionWriterFactory; private final ProtocolReaderFactory protocolReaderFactory; private final ProtocolWriterFactory protocolWriterFactory; private final PacketFactory packetFactory; - private final CryptoComponent crypto; + private final MessageVerifier messageVerifier; + private final ContactId contactId; private final TransportId transportId; private final byte[] secret; @@ -82,30 +78,32 @@ public class ProtocolIntegrationTest extends BriarTestCase { private final String authorName = "Alice"; private final String subject = "Hello"; private final String messageBody = "Hello world"; + private final Collection<MessageId> messageIds; private final Collection<Transport> transports; + private final long timestamp = System.currentTimeMillis(); public ProtocolIntegrationTest() throws Exception { super(); - Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(), - new DatabaseModule(), new LifecycleModule(), - new ProtocolModule(), new SerialModule(), - new TestDatabaseModule(), new SimplexProtocolModule(), - new TransportModule(), new DuplexProtocolModule()); + Injector i = Guice.createInjector(new TestDatabaseModule(), + new ClockModule(), new CryptoModule(), new DatabaseModule(), + new LifecycleModule(), new ProtocolModule(), + new DuplexProtocolModule(), new SimplexProtocolModule(), + new SerialModule(), new TransportModule()); connectionReaderFactory = i.getInstance(ConnectionReaderFactory.class); connectionWriterFactory = i.getInstance(ConnectionWriterFactory.class); protocolReaderFactory = i.getInstance(ProtocolReaderFactory.class); protocolWriterFactory = i.getInstance(ProtocolWriterFactory.class); packetFactory = i.getInstance(PacketFactory.class); - crypto = i.getInstance(CryptoComponent.class); + messageVerifier = i.getInstance(MessageVerifier.class); contactId = new ContactId(234); transportId = new TransportId(TestUtils.getRandomId()); // Create a shared secret - Random r = new Random(); secret = new byte[32]; - r.nextBytes(secret); + new Random().nextBytes(secret); // Create two groups: one restricted, one unrestricted GroupFactory groupFactory = i.getInstance(GroupFactory.class); group = groupFactory.createGroup("Unrestricted group", null); + CryptoComponent crypto = i.getInstance(CryptoComponent.class); KeyPair groupKeyPair = crypto.generateSignatureKeyPair(); group1 = groupFactory.createGroup("Restricted group", groupKeyPair.getPublic().getEncoded()); @@ -127,6 +125,8 @@ public class ProtocolIntegrationTest extends BriarTestCase { message3 = messageFactory.createMessage(null, group1, groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(), subject, messageBody.getBytes("UTF-8")); + messageIds = Arrays.asList(message.getId(), + message1.getId(), message2.getId(), message3.getId()); // Create some transports TransportId transportId = new TransportId(TestUtils.getRandomId()); Transport transport = new Transport(transportId, @@ -149,18 +149,15 @@ public class ProtocolIntegrationTest extends BriarTestCase { ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out1, false); - Ack a = packetFactory.createAck(Collections.singletonList(ack)); + Ack a = packetFactory.createAck(messageIds); writer.writeAck(a); - Collection<byte[]> batch = Arrays.asList(message.getSerialised(), - message1.getSerialised(), message2.getSerialised(), - message3.getSerialised()); - RawBatch b = packetFactory.createBatch(batch); - writer.writeBatch(b); + writer.writeMessage(message.getSerialised()); + writer.writeMessage(message1.getSerialised()); + writer.writeMessage(message2.getSerialised()); + writer.writeMessage(message3.getSerialised()); - Collection<MessageId> offer = Arrays.asList(message.getId(), - message1.getId(), message2.getId(), message3.getId()); - Offer o = packetFactory.createOffer(offer); + Offer o = packetFactory.createOffer(messageIds); writer.writeOffer(o); BitSet requested = new BitSet(4); @@ -200,29 +197,26 @@ public class ProtocolIntegrationTest extends BriarTestCase { // Read the ack assertTrue(reader.hasAck()); Ack a = reader.readAck(); - assertEquals(Collections.singletonList(ack), a.getBatchIds()); + assertEquals(messageIds, a.getMessageIds()); - // Read and verify the batch - assertTrue(reader.hasBatch()); - Batch b = reader.readBatch().verify(); - Collection<Message> messages = b.getMessages(); - assertEquals(4, messages.size()); - Iterator<Message> it = messages.iterator(); - checkMessageEquality(message, it.next()); - checkMessageEquality(message1, it.next()); - checkMessageEquality(message2, it.next()); - checkMessageEquality(message3, it.next()); + // Read and verify the messages + assertTrue(reader.hasMessage()); + UnverifiedMessage m = reader.readMessage(); + checkMessageEquality(message, messageVerifier.verifyMessage(m)); + assertTrue(reader.hasMessage()); + m = reader.readMessage(); + checkMessageEquality(message1, messageVerifier.verifyMessage(m)); + assertTrue(reader.hasMessage()); + m = reader.readMessage(); + checkMessageEquality(message2, messageVerifier.verifyMessage(m)); + assertTrue(reader.hasMessage()); + m = reader.readMessage(); + checkMessageEquality(message3, messageVerifier.verifyMessage(m)); // Read the offer assertTrue(reader.hasOffer()); Offer o = reader.readOffer(); - Collection<MessageId> offered = o.getMessageIds(); - assertEquals(4, offered.size()); - Iterator<MessageId> it1 = offered.iterator(); - assertEquals(message.getId(), it1.next()); - assertEquals(message1.getId(), it1.next()); - assertEquals(message2.getId(), it1.next()); - assertEquals(message3.getId(), it1.next()); + assertEquals(messageIds, o.getMessageIds()); // Read the request assertTrue(reader.hasRequest()); diff --git a/briar-tests/src/net/sf/briar/db/TestMessage.java b/briar-tests/src/net/sf/briar/TestMessage.java similarity index 96% rename from briar-tests/src/net/sf/briar/db/TestMessage.java rename to briar-tests/src/net/sf/briar/TestMessage.java index bf25200e04..c66abc8bb0 100644 --- a/briar-tests/src/net/sf/briar/db/TestMessage.java +++ b/briar-tests/src/net/sf/briar/TestMessage.java @@ -1,4 +1,4 @@ -package net.sf.briar.db; +package net.sf.briar; import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -8,7 +8,7 @@ import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; -class TestMessage implements Message { +public class TestMessage implements Message { private final MessageId id, parent; private final GroupId group; diff --git a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java index aa598ac702..5a2fabba23 100644 --- a/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java +++ b/briar-tests/src/net/sf/briar/db/DatabaseComponentTest.java @@ -7,6 +7,7 @@ import java.util.Collection; import java.util.Collections; import net.sf.briar.BriarTestCase; +import net.sf.briar.TestMessage; import net.sf.briar.TestUtils; import net.sf.briar.api.ContactId; import net.sf.briar.api.Rating; @@ -17,21 +18,18 @@ import net.sf.briar.api.db.NoSuchContactTransportException; import net.sf.briar.api.db.event.ContactAddedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.DatabaseListener; -import net.sf.briar.api.db.event.MessagesAddedEvent; +import net.sf.briar.api.db.event.MessageAddedEvent; import net.sf.briar.api.db.event.RatingChangedEvent; import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent; import net.sf.briar.api.lifecycle.ShutdownManager; import net.sf.briar.api.protocol.Ack; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.Batch; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.PacketFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.Transport; @@ -48,10 +46,9 @@ public abstract class DatabaseComponentTest extends BriarTestCase { protected final Object txn = new Object(); protected final AuthorId authorId; - protected final BatchId batchId; protected final ContactId contactId; protected final GroupId groupId; - protected final MessageId messageId, parentId; + protected final MessageId messageId, messageId1; private final String subject; private final long timestamp; private final int size; @@ -66,11 +63,10 @@ public abstract class DatabaseComponentTest extends BriarTestCase { public DatabaseComponentTest() { super(); authorId = new AuthorId(TestUtils.getRandomId()); - batchId = new BatchId(TestUtils.getRandomId()); contactId = new ContactId(234); groupId = new GroupId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId()); - parentId = new MessageId(TestUtils.getRandomId()); + messageId1 = new MessageId(TestUtils.getRandomId()); subject = "Foo"; timestamp = System.currentTimeMillis(); size = 1234; @@ -250,11 +246,11 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).setSendability(txn, messageId, 1); // The parent exists, is in the DB, and is in the same group oneOf(database).getGroupMessageParent(txn, messageId); - will(returnValue(parentId)); + will(returnValue(messageId1)); // The parent is already sendable - oneOf(database).getSendability(txn, parentId); + oneOf(database).getSendability(txn, messageId1); will(returnValue(1)); - oneOf(database).setSendability(txn, parentId, 2); + oneOf(database).setSendability(txn, messageId1, 2); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, @@ -288,13 +284,13 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).setSendability(txn, messageId, 1); // The parent exists, is in the DB, and is in the same group oneOf(database).getGroupMessageParent(txn, messageId); - will(returnValue(parentId)); + will(returnValue(messageId1)); // The parent is not already sendable - oneOf(database).getSendability(txn, parentId); + oneOf(database).getSendability(txn, messageId1); will(returnValue(0)); - oneOf(database).setSendability(txn, parentId, 1); + oneOf(database).setSendability(txn, messageId1, 1); // The parent has no parent - oneOf(database).getGroupMessageParent(txn, parentId); + oneOf(database).getGroupMessageParent(txn, messageId1); will(returnValue(null)); oneOf(database).commitTransaction(txn); }}); @@ -494,7 +490,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); final Ack ack = context.mock(Ack.class); - final Batch batch = context.mock(Batch.class); final Offer offer = context.mock(Offer.class); final SubscriptionUpdate subscriptionUpdate = context.mock(SubscriptionUpdate.class); @@ -563,7 +558,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { } catch(NoSuchContactException expected) {} try { - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, message); fail(); } catch(NoSuchContactException expected) {} @@ -631,10 +626,8 @@ public abstract class DatabaseComponentTest extends BriarTestCase { @Test public void testGenerateAck() throws Exception { - final BatchId batchId1 = new BatchId(TestUtils.getRandomId()); - final Collection<BatchId> batchesToAck = new ArrayList<BatchId>(); - batchesToAck.add(batchId); - batchesToAck.add(batchId1); + final Collection<MessageId> messagesToAck = Arrays.asList(messageId, + messageId1); Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); @@ -648,14 +641,14 @@ public abstract class DatabaseComponentTest extends BriarTestCase { allowing(database).commitTransaction(txn); allowing(database).containsContact(txn, contactId); will(returnValue(true)); - // Get the batches to ack - oneOf(database).getBatchesToAck(txn, contactId, 123); - will(returnValue(batchesToAck)); - // Create the packet - oneOf(packetFactory).createAck(batchesToAck); + // Get the messages to ack + oneOf(database).getMessagesToAck(txn, contactId, 123); + will(returnValue(messagesToAck)); + // Create the ack packet + oneOf(packetFactory).createAck(messagesToAck); will(returnValue(ack)); - // Record the batches that were acked - oneOf(database).removeBatchesToAck(txn, contactId, batchesToAck); + // Record the messages that were acked + oneOf(database).removeMessagesToAck(txn, contactId, messagesToAck); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); @@ -667,7 +660,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { @Test public void testGenerateBatch() throws Exception { - final MessageId messageId1 = new MessageId(TestUtils.getRandomId()); final byte[] raw1 = new byte[size]; final Collection<MessageId> sendable = Arrays.asList(messageId, messageId1); @@ -678,7 +670,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final RawBatch batch = context.mock(RawBatch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -692,40 +683,32 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(raw)); oneOf(database).getMessage(txn, messageId1); will(returnValue(raw1)); - // Create the packet - oneOf(packetFactory).createBatch(messages); - will(returnValue(batch)); - // Record the outstanding batch - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addOutstandingBatch(txn, contactId, batchId, - sendable); + // Record the outstanding messages + oneOf(database).addOutstandingMessages(txn, contactId, sendable); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - assertEquals(batch, db.generateBatch(contactId, size * 2)); + assertEquals(messages, db.generateBatch(contactId, size * 2)); context.assertIsSatisfied(); } @Test public void testGenerateBatchFromRequest() throws Exception { - final MessageId messageId1 = new MessageId(TestUtils.getRandomId()); final MessageId messageId2 = new MessageId(TestUtils.getRandomId()); final byte[] raw1 = new byte[size]; final Collection<MessageId> requested = new ArrayList<MessageId>(); requested.add(messageId); requested.add(messageId1); requested.add(messageId2); - final Collection<byte[]> msgs = Arrays.asList(raw1); + final Collection<byte[]> messages = Arrays.asList(raw1); Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final RawBatch batch = context.mock(RawBatch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -739,19 +722,15 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(raw1)); // Message is sendable oneOf(database).getMessageIfSendable(txn, contactId, messageId2); will(returnValue(null)); // Message is not sendable - // Create the packet - oneOf(packetFactory).createBatch(msgs); - will(returnValue(batch)); - // Record the outstanding batch - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addOutstandingBatch(txn, contactId, batchId, + // Record the outstanding messages + oneOf(database).addOutstandingMessages(txn, contactId, Collections.singletonList(messageId1)); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - assertEquals(batch, db.generateBatch(contactId, size * 3, requested)); + assertEquals(messages, db.generateBatch(contactId, size * 3, + requested)); context.assertIsSatisfied(); } @@ -903,7 +882,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { @Test public void testReceiveAck() throws Exception { - final BatchId batchId1 = new BatchId(TestUtils.getRandomId()); Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); @@ -917,14 +895,14 @@ public abstract class DatabaseComponentTest extends BriarTestCase { allowing(database).commitTransaction(txn); allowing(database).containsContact(txn, contactId); will(returnValue(true)); - // Get the acked batches - oneOf(ack).getBatchIds(); - will(returnValue(Collections.singletonList(batchId))); - oneOf(database).removeAckedBatch(txn, contactId, batchId); - // Find lost batches - oneOf(database).getLostBatches(txn, contactId); - will(returnValue(Collections.singletonList(batchId1))); - oneOf(database).removeLostBatch(txn, contactId, batchId1); + // Get the acked messages + oneOf(ack).getMessageIds(); + will(returnValue(Collections.singletonList(messageId))); + oneOf(database).removeAckedMessages(txn, contactId, + Collections.singletonList(messageId)); + // Find lost messages + oneOf(database).getLostMessages(txn, contactId); + will(returnValue(Collections.emptyList())); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); @@ -935,74 +913,64 @@ public abstract class DatabaseComponentTest extends BriarTestCase { } @Test - public void testReceiveBatchStoresPrivateMessage() throws Exception { + public void testReceivePrivateMessage() throws Exception { Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); allowing(database).commitTransaction(txn); allowing(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(batch).getMessages(); - will(returnValue(Collections.singletonList(privateMessage))); // The message is stored oneOf(database).addPrivateMessage(txn, privateMessage, contactId); will(returnValue(true)); oneOf(database).setStatus(txn, contactId, messageId, Status.SEEN); - // The batch must be acked - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addBatchToAck(txn, contactId, batchId); + // The message must be acked + oneOf(database).addMessageToAck(txn, contactId, messageId); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, privateMessage); context.assertIsSatisfied(); } @Test - public void testReceiveBatchWithDuplicatePrivateMessage() throws Exception { + public void testReceiveDuplicatePrivateMessage() throws Exception { Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); allowing(database).commitTransaction(txn); allowing(database).containsContact(txn, contactId); will(returnValue(true)); - oneOf(batch).getMessages(); - will(returnValue(Collections.singletonList(privateMessage))); // The message is stored, but it's a duplicate oneOf(database).addPrivateMessage(txn, privateMessage, contactId); will(returnValue(false)); - // The batch must still be acked - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addBatchToAck(txn, contactId, batchId); + // The message must still be acked + oneOf(database).addMessageToAck(txn, contactId, messageId); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, privateMessage); context.assertIsSatisfied(); } @Test - public void testReceiveBatchDoesNotStoreGroupMessageUnlessSubscribed() + public void testReceiveMessageDoesNotStoreGroupMessageUnlessSubscribed() throws Exception { Mockery context = new Mockery(); @SuppressWarnings("unchecked") @@ -1010,7 +978,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -1018,26 +985,22 @@ public abstract class DatabaseComponentTest extends BriarTestCase { allowing(database).containsContact(txn, contactId); will(returnValue(true)); // Only store messages belonging to visible, subscribed groups - oneOf(batch).getMessages(); - will(returnValue(Collections.singletonList(message))); oneOf(database).containsVisibleSubscription(txn, groupId, contactId, timestamp); will(returnValue(false)); - // The message is not stored but the batch must still be acked - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addBatchToAck(txn, contactId, batchId); + // The message is not stored but it must still be acked + oneOf(database).addMessageToAck(txn, contactId, messageId); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, message); context.assertIsSatisfied(); } @Test - public void testReceiveBatchDoesNotCalculateSendabilityForDuplicates() + public void testReceiveMessageDoesNotCalculateSendabilityForDuplicates() throws Exception { Mockery context = new Mockery(); @SuppressWarnings("unchecked") @@ -1045,7 +1008,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -1053,8 +1015,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { allowing(database).containsContact(txn, contactId); will(returnValue(true)); // Only store messages belonging to visible, subscribed groups - oneOf(batch).getMessages(); - will(returnValue(Collections.singletonList(message))); oneOf(database).containsVisibleSubscription(txn, groupId, contactId, timestamp); will(returnValue(true)); @@ -1062,28 +1022,25 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).addGroupMessage(txn, message); will(returnValue(false)); oneOf(database).setStatus(txn, contactId, messageId, Status.SEEN); - // The batch needs to be acknowledged - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addBatchToAck(txn, contactId, batchId); + // The message must be acked + oneOf(database).addMessageToAck(txn, contactId, messageId); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, message); context.assertIsSatisfied(); } @Test - public void testReceiveBatchCalculatesSendability() throws Exception { + public void testReceiveMessageCalculatesSendability() throws Exception { Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -1091,8 +1048,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { allowing(database).containsContact(txn, contactId); will(returnValue(true)); // Only store messages belonging to visible, subscribed groups - oneOf(batch).getMessages(); - will(returnValue(Collections.singletonList(message))); oneOf(database).containsVisibleSubscription(txn, groupId, contactId, timestamp); will(returnValue(true)); @@ -1109,28 +1064,26 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).getNumberOfSendableChildren(txn, messageId); will(returnValue(0)); oneOf(database).setSendability(txn, messageId, 0); - // The batch needs to be acknowledged - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addBatchToAck(txn, contactId, batchId); + // The message must be acked + oneOf(database).addMessageToAck(txn, contactId, messageId); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, message); context.assertIsSatisfied(); } @Test - public void testReceiveBatchUpdatesAncestorSendability() throws Exception { + public void testReceiveMessageUpdatesAncestorSendability() + throws Exception { Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); final ShutdownManager shutdown = context.mock(ShutdownManager.class); final PacketFactory packetFactory = context.mock(PacketFactory.class); - final Batch batch = context.mock(Batch.class); context.checking(new Expectations() {{ allowing(database).startTransaction(); will(returnValue(txn)); @@ -1138,8 +1091,6 @@ public abstract class DatabaseComponentTest extends BriarTestCase { allowing(database).containsContact(txn, contactId); will(returnValue(true)); // Only store messages belonging to visible, subscribed groups - oneOf(batch).getMessages(); - will(returnValue(Collections.singletonList(message))); oneOf(database).containsVisibleSubscription(txn, groupId, contactId, timestamp); will(returnValue(true)); @@ -1158,15 +1109,13 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).setSendability(txn, messageId, 2); oneOf(database).getGroupMessageParent(txn, messageId); will(returnValue(null)); - // The batch needs to be acknowledged - oneOf(batch).getId(); - will(returnValue(batchId)); - oneOf(database).addBatchToAck(txn, contactId, batchId); + // The message must be acked + oneOf(database).addMessageToAck(txn, contactId, messageId); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); - db.receiveBatch(contactId, batch); + db.receiveMessage(contactId, message); context.assertIsSatisfied(); } @@ -1319,7 +1268,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { oneOf(database).setSendability(txn, messageId, 0); oneOf(database).commitTransaction(txn); // The message was added, so the listener should be called - oneOf(listener).eventOccurred(with(any(MessagesAddedEvent.class))); + oneOf(listener).eventOccurred(with(any(MessageAddedEvent.class))); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); @@ -1350,7 +1299,7 @@ public abstract class DatabaseComponentTest extends BriarTestCase { will(returnValue(true)); oneOf(database).setStatus(txn, contactId, messageId, Status.NEW); // The message was added, so the listener should be called - oneOf(listener).eventOccurred(with(any(MessagesAddedEvent.class))); + oneOf(listener).eventOccurred(with(any(MessageAddedEvent.class))); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner, shutdown, packetFactory); diff --git a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java index d31ac8a8fd..e9ba2d0b74 100644 --- a/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java +++ b/briar-tests/src/net/sf/briar/db/H2DatabaseTest.java @@ -1,7 +1,6 @@ package net.sf.briar.db; import static java.util.concurrent.TimeUnit.SECONDS; -import static net.sf.briar.db.DatabaseConstants.RETRANSMIT_THRESHOLD; import static org.junit.Assert.assertArrayEquals; import java.io.File; @@ -20,6 +19,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import net.sf.briar.BriarTestCase; import net.sf.briar.TestDatabaseConfig; +import net.sf.briar.TestMessage; import net.sf.briar.TestUtils; import net.sf.briar.api.ContactId; import net.sf.briar.api.Rating; @@ -29,7 +29,6 @@ import net.sf.briar.api.clock.SystemClock; import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.MessageHeader; import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; import net.sf.briar.api.protocol.Message; @@ -53,10 +52,9 @@ public class H2DatabaseTest extends BriarTestCase { private final Random random = new Random(); private final Group group; private final AuthorId authorId; - private final BatchId batchId; private final ContactId contactId; private final GroupId groupId; - private final MessageId messageId, privateMessageId; + private final MessageId messageId, messageId1; private final String subject; private final long timestamp; private final int size; @@ -67,11 +65,10 @@ public class H2DatabaseTest extends BriarTestCase { public H2DatabaseTest() throws Exception { super(); authorId = new AuthorId(TestUtils.getRandomId()); - batchId = new BatchId(TestUtils.getRandomId()); contactId = new ContactId(1); groupId = new GroupId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId()); - privateMessageId = new MessageId(TestUtils.getRandomId()); + messageId1 = new MessageId(TestUtils.getRandomId()); group = new Group(groupId, "Foo", null); subject = "Foo"; timestamp = System.currentTimeMillis(); @@ -80,7 +77,7 @@ public class H2DatabaseTest extends BriarTestCase { random.nextBytes(raw); message = new TestMessage(messageId, null, groupId, authorId, subject, timestamp, raw); - privateMessage = new TestMessage(privateMessageId, null, null, null, + privateMessage = new TestMessage(messageId1, null, null, null, subject, timestamp, raw); transportId = new TransportId(TestUtils.getRandomId()); } @@ -104,9 +101,9 @@ public class H2DatabaseTest extends BriarTestCase { assertFalse(db.containsMessage(txn, messageId)); db.addGroupMessage(txn, message); assertTrue(db.containsMessage(txn, messageId)); - assertFalse(db.containsMessage(txn, privateMessageId)); + assertFalse(db.containsMessage(txn, messageId1)); db.addPrivateMessage(txn, privateMessage, contactId); - assertTrue(db.containsMessage(txn, privateMessageId)); + assertTrue(db.containsMessage(txn, messageId1)); db.commitTransaction(txn); db.close(); @@ -118,12 +115,12 @@ public class H2DatabaseTest extends BriarTestCase { assertTrue(db.containsMessage(txn, messageId)); byte[] raw1 = db.getMessage(txn, messageId); assertArrayEquals(raw, raw1); - assertTrue(db.containsMessage(txn, privateMessageId)); - raw1 = db.getMessage(txn, privateMessageId); + assertTrue(db.containsMessage(txn, messageId1)); + raw1 = db.getMessage(txn, messageId1); assertArrayEquals(raw, raw1); // Delete the records db.removeMessage(txn, messageId); - db.removeMessage(txn, privateMessageId); + db.removeMessage(txn, messageId1); db.removeContact(txn, contactId); db.removeSubscription(txn, groupId); db.commitTransaction(txn); @@ -137,7 +134,7 @@ public class H2DatabaseTest extends BriarTestCase { db.getRemoteProperties(txn, transportId)); assertFalse(db.containsSubscription(txn, groupId)); assertFalse(db.containsMessage(txn, messageId)); - assertFalse(db.containsMessage(txn, privateMessageId)); + assertFalse(db.containsMessage(txn, messageId1)); db.commitTransaction(txn); db.close(); } @@ -216,9 +213,9 @@ public class H2DatabaseTest extends BriarTestCase { db.addPrivateMessage(txn, privateMessage, contactId); // Removing the contact should remove the message - assertTrue(db.containsMessage(txn, privateMessageId)); + assertTrue(db.containsMessage(txn, messageId1)); db.removeContact(txn, contactId); - assertFalse(db.containsMessage(txn, privateMessageId)); + assertFalse(db.containsMessage(txn, messageId1)); db.commitTransaction(txn); db.close(); @@ -241,21 +238,21 @@ public class H2DatabaseTest extends BriarTestCase { assertFalse(it.hasNext()); // Changing the status to NEW should make the message sendable - db.setStatus(txn, contactId, privateMessageId, Status.NEW); + db.setStatus(txn, contactId, messageId1, Status.NEW); assertTrue(db.hasSendableMessages(txn, contactId)); it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator(); assertTrue(it.hasNext()); - assertEquals(privateMessageId, it.next()); + assertEquals(messageId1, it.next()); assertFalse(it.hasNext()); // Changing the status to SENT should make the message unsendable - db.setStatus(txn, contactId, privateMessageId, Status.SENT); + db.setStatus(txn, contactId, messageId1, Status.SENT); assertFalse(db.hasSendableMessages(txn, contactId)); it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator(); assertFalse(it.hasNext()); // Changing the status to SEEN should also make the message unsendable - db.setStatus(txn, contactId, privateMessageId, Status.SEEN); + db.setStatus(txn, contactId, messageId1, Status.SEEN); it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator(); assertFalse(it.hasNext()); @@ -272,7 +269,7 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact and store a private message assertEquals(contactId, db.addContact(txn)); db.addPrivateMessage(txn, privateMessage, contactId); - db.setStatus(txn, contactId, privateMessageId, Status.NEW); + db.setStatus(txn, contactId, messageId1, Status.NEW); // The message is sendable, but too large to send assertTrue(db.hasSendableMessages(txn, contactId)); @@ -284,7 +281,7 @@ public class H2DatabaseTest extends BriarTestCase { assertTrue(db.hasSendableMessages(txn, contactId)); it = db.getSendableMessages(txn, contactId, size).iterator(); assertTrue(it.hasNext()); - assertEquals(privateMessageId, it.next()); + assertEquals(messageId1, it.next()); assertFalse(it.hasNext()); db.commitTransaction(txn); @@ -508,109 +505,58 @@ public class H2DatabaseTest extends BriarTestCase { } @Test - public void testBatchesToAck() throws Exception { - BatchId batchId1 = new BatchId(TestUtils.getRandomId()); + public void testMessagesToAck() throws Exception { Database<Connection> db = open(false); Connection txn = db.startTransaction(); - // Add a contact and some batches to ack + // Add a contact and some messages to ack assertEquals(contactId, db.addContact(txn)); - db.addBatchToAck(txn, contactId, batchId); - db.addBatchToAck(txn, contactId, batchId1); + db.addMessageToAck(txn, contactId, messageId); + db.addMessageToAck(txn, contactId, messageId1); - // Both batch IDs should be returned - Collection<BatchId> acks = db.getBatchesToAck(txn, contactId, 1234); - assertEquals(2, acks.size()); - assertTrue(acks.contains(batchId)); - assertTrue(acks.contains(batchId1)); + // Both message IDs should be returned + Collection<MessageId> ids = Arrays.asList(messageId, messageId1); + assertEquals(ids, db.getMessagesToAck(txn, contactId, 1234)); - // Remove the batch IDs - db.removeBatchesToAck(txn, contactId, acks); + // Remove both message IDs + db.removeMessagesToAck(txn, contactId, ids); - // Both batch IDs should have been removed - acks = db.getBatchesToAck(txn, contactId, 1234); - assertEquals(0, acks.size()); + // Both message IDs should have been removed + assertEquals(Collections.emptyList(), db.getMessagesToAck(txn, + contactId, 1234)); db.commitTransaction(txn); db.close(); } @Test - public void testDuplicateBatchesReceived() throws Exception { + public void testDuplicateMessageReceived() throws Exception { Database<Connection> db = open(false); Connection txn = db.startTransaction(); - // Add a contact and receive the same batch twice + // Add a contact and receive the same message twice assertEquals(contactId, db.addContact(txn)); - db.addBatchToAck(txn, contactId, batchId); - db.addBatchToAck(txn, contactId, batchId); - - // The batch ID should only be returned once - Collection<BatchId> acks = db.getBatchesToAck(txn, contactId, 1234); - assertEquals(1, acks.size()); - assertTrue(acks.contains(batchId)); - - // Remove the batch ID - db.removeBatchesToAck(txn, contactId, acks); - - // The batch ID should have been removed - acks = db.getBatchesToAck(txn, contactId, 1234); - assertEquals(0, acks.size()); - - db.commitTransaction(txn); - db.close(); - } + db.addMessageToAck(txn, contactId, messageId); + db.addMessageToAck(txn, contactId, messageId); - @Test - public void testSameBatchCannotBeSentTwice() throws Exception { - Database<Connection> db = open(false); - Connection txn = db.startTransaction(); + // The message ID should only be returned once + Collection<MessageId> ids = db.getMessagesToAck(txn, contactId, 1234); + assertEquals(Collections.singletonList(messageId), ids); - // Add a contact, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn)); - db.addSubscription(txn, group); - db.addGroupMessage(txn, message); - - // Add an outstanding batch - db.addOutstandingBatch(txn, contactId, batchId, + // Remove the message ID + db.removeMessagesToAck(txn, contactId, Collections.singletonList(messageId)); - // It should not be possible to add the same outstanding batch again - try { - db.addOutstandingBatch(txn, contactId, batchId, - Collections.singletonList(messageId)); - fail(); - } catch(DbException expected) {} - - db.abortTransaction(txn); - db.close(); - } - - @Test - public void testSameBatchCanBeSentToDifferentContacts() throws Exception { - Database<Connection> db = open(false); - Connection txn = db.startTransaction(); - - // Add two contacts, subscribe to a group and store a message - assertEquals(contactId, db.addContact(txn)); - ContactId contactId1 = db.addContact(txn); - db.addSubscription(txn, group); - db.addGroupMessage(txn, message); - - // Add an outstanding batch for the first contact - db.addOutstandingBatch(txn, contactId, batchId, - Collections.singletonList(messageId)); - - // Add the same outstanding batch for the second contact - db.addOutstandingBatch(txn, contactId1, batchId, - Collections.singletonList(messageId)); + // The message ID should have been removed + assertEquals(Collections.emptyList(), db.getMessagesToAck(txn, + contactId, 1234)); db.commitTransaction(txn); db.close(); } @Test - public void testRemoveAckedBatch() throws Exception { + public void testRemoveAckedMessage() throws Exception { Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -630,15 +576,16 @@ public class H2DatabaseTest extends BriarTestCase { assertEquals(messageId, it.next()); assertFalse(it.hasNext()); db.setStatus(txn, contactId, messageId, Status.SENT); - db.addOutstandingBatch(txn, contactId, batchId, + db.addOutstandingMessages(txn, contactId, Collections.singletonList(messageId)); // The message should no longer be sendable it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator(); assertFalse(it.hasNext()); - // Pretend that the batch was acked - db.removeAckedBatch(txn, contactId, batchId); + // Pretend that the message was acked + db.removeAckedMessages(txn, contactId, + Collections.singletonList(messageId)); // The message still should not be sendable it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator(); @@ -649,7 +596,7 @@ public class H2DatabaseTest extends BriarTestCase { } @Test - public void testRemoveLostBatch() throws Exception { + public void testRemoveLostMessage() throws Exception { Database<Connection> db = open(false); Connection txn = db.startTransaction(); @@ -669,15 +616,16 @@ public class H2DatabaseTest extends BriarTestCase { assertEquals(messageId, it.next()); assertFalse(it.hasNext()); db.setStatus(txn, contactId, messageId, Status.SENT); - db.addOutstandingBatch(txn, contactId, batchId, + db.addOutstandingMessages(txn, contactId, Collections.singletonList(messageId)); // The message should no longer be sendable it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator(); assertFalse(it.hasNext()); - // Pretend that the batch was lost - db.removeLostBatch(txn, contactId, batchId); + // Pretend that the message was lost + db.removeLostMessages(txn, contactId, + Collections.singletonList(messageId)); // The message should be sendable again it = db.getSendableMessages(txn, contactId, ONE_MEGABYTE).iterator(); @@ -689,77 +637,6 @@ public class H2DatabaseTest extends BriarTestCase { db.close(); } - @Test - public void testRetransmission() throws Exception { - BatchId[] ids = new BatchId[RETRANSMIT_THRESHOLD + 5]; - for(int i = 0; i < ids.length; i++) { - ids[i] = new BatchId(TestUtils.getRandomId()); - } - Database<Connection> db = open(false); - Connection txn = db.startTransaction(); - - // Add a contact - assertEquals(contactId, db.addContact(txn)); - - // Add some outstanding batches, a few ms apart - for(int i = 0; i < ids.length; i++) { - db.addOutstandingBatch(txn, contactId, ids[i], - Collections.<MessageId>emptyList()); - Thread.sleep(5); - } - - // The contact acks the batches in reverse order. The first - // RETRANSMIT_THRESHOLD - 1 acks should not trigger any retransmissions - for(int i = 0; i < RETRANSMIT_THRESHOLD - 1; i++) { - db.removeAckedBatch(txn, contactId, ids[ids.length - i - 1]); - Collection<BatchId> lost = db.getLostBatches(txn, contactId); - assertEquals(Collections.emptyList(), lost); - } - - // The next ack should trigger the retransmission of the remaining - // five outstanding batches - int index = ids.length - RETRANSMIT_THRESHOLD; - db.removeAckedBatch(txn, contactId, ids[index]); - Collection<BatchId> lost = db.getLostBatches(txn, contactId); - for(int i = 0; i < index; i++) { - assertTrue(lost.contains(ids[i])); - } - - db.commitTransaction(txn); - db.close(); - } - - @Test - public void testNoRetransmission() throws Exception { - BatchId[] ids = new BatchId[RETRANSMIT_THRESHOLD * 2]; - for(int i = 0; i < ids.length; i++) { - ids[i] = new BatchId(TestUtils.getRandomId()); - } - Database<Connection> db = open(false); - Connection txn = db.startTransaction(); - - // Add a contact - assertEquals(contactId, db.addContact(txn)); - - // Add some outstanding batches, a few ms apart - for(int i = 0; i < ids.length; i++) { - db.addOutstandingBatch(txn, contactId, ids[i], - Collections.<MessageId>emptyList()); - Thread.sleep(5); - } - - // The contact acks the batches in the order they were sent - nothing - // should be retransmitted - for(int i = 0; i < ids.length; i++) { - db.removeAckedBatch(txn, contactId, ids[i]); - Collection<BatchId> lost = db.getLostBatches(txn, contactId); - assertEquals(Collections.emptyList(), lost); - } - - db.commitTransaction(txn); - db.close(); - } - @Test public void testGetMessagesByAuthor() throws Exception { AuthorId authorId1 = new AuthorId(TestUtils.getRandomId()); @@ -1426,12 +1303,12 @@ public class H2DatabaseTest extends BriarTestCase { // A message with a private parent should return null MessageId childId = new MessageId(TestUtils.getRandomId()); - Message child = new TestMessage(childId, privateMessageId, groupId, + Message child = new TestMessage(childId, messageId1, groupId, null, subject, timestamp, raw); db.addGroupMessage(txn, child); db.addPrivateMessage(txn, privateMessage, contactId); assertTrue(db.containsMessage(txn, childId)); - assertTrue(db.containsMessage(txn, privateMessageId)); + assertTrue(db.containsMessage(txn, messageId1)); assertNull(db.getGroupMessageParent(txn, childId)); db.commitTransaction(txn); @@ -1477,7 +1354,7 @@ public class H2DatabaseTest extends BriarTestCase { int bodyLength = raw.length - 20; Message message1 = new TestMessage(messageId, null, groupId, null, subject, timestamp, raw, 5, bodyLength); - Message privateMessage1 = new TestMessage(privateMessageId, null, null, + Message privateMessage1 = new TestMessage(messageId1, null, null, null, subject, timestamp, raw, 10, bodyLength); db.addGroupMessage(txn, message1); db.addPrivateMessage(txn, privateMessage1, contactId); @@ -1492,12 +1369,12 @@ public class H2DatabaseTest extends BriarTestCase { // Retrieve the raw messages assertArrayEquals(raw, db.getMessage(txn, messageId)); - assertArrayEquals(raw, db.getMessage(txn, privateMessageId)); + assertArrayEquals(raw, db.getMessage(txn, messageId1)); // Retrieve the message bodies byte[] body = db.getMessageBody(txn, messageId); assertArrayEquals(expectedBody, body); - byte[] body1 = db.getMessageBody(txn, privateMessageId); + byte[] body1 = db.getMessageBody(txn, messageId1); assertArrayEquals(expectedBody1, body1); db.commitTransaction(txn); diff --git a/briar-tests/src/net/sf/briar/protocol/BatchReaderTest.java b/briar-tests/src/net/sf/briar/protocol/BatchReaderTest.java deleted file mode 100644 index 6323638b01..0000000000 --- a/briar-tests/src/net/sf/briar/protocol/BatchReaderTest.java +++ /dev/null @@ -1,137 +0,0 @@ -package net.sf.briar.protocol; - -import static net.sf.briar.api.protocol.ProtocolConstants.MAX_PACKET_LENGTH; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.util.Collections; - -import net.sf.briar.BriarTestCase; -import net.sf.briar.api.FormatException; -import net.sf.briar.api.protocol.Types; -import net.sf.briar.api.protocol.UnverifiedBatch; -import net.sf.briar.api.serial.Reader; -import net.sf.briar.api.serial.ReaderFactory; -import net.sf.briar.api.serial.StructReader; -import net.sf.briar.api.serial.Writer; -import net.sf.briar.api.serial.WriterFactory; -import net.sf.briar.serial.SerialModule; - -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.junit.Test; - -import com.google.inject.Guice; -import com.google.inject.Injector; - -public class BatchReaderTest extends BriarTestCase { - - // FIXME: This is an integration test, not a unit test - - private final ReaderFactory readerFactory; - private final WriterFactory writerFactory; - private final Mockery context; - private final UnverifiedMessage message; - private final StructReader<UnverifiedMessage> messageReader; - - public BatchReaderTest() throws Exception { - super(); - Injector i = Guice.createInjector(new SerialModule()); - readerFactory = i.getInstance(ReaderFactory.class); - writerFactory = i.getInstance(WriterFactory.class); - context = new Mockery(); - message = context.mock(UnverifiedMessage.class); - messageReader = new TestMessageReader(); - } - - @Test - public void testFormatExceptionIfBatchIsTooLarge() throws Exception { - UnverifiedBatchFactory batchFactory = - context.mock(UnverifiedBatchFactory.class); - BatchReader batchReader = new BatchReader(messageReader, batchFactory); - - byte[] b = createBatch(MAX_PACKET_LENGTH + 1); - ByteArrayInputStream in = new ByteArrayInputStream(b); - Reader reader = readerFactory.createReader(in); - reader.addStructReader(Types.BATCH, batchReader); - - try { - reader.readStruct(Types.BATCH, UnverifiedBatch.class); - fail(); - } catch(FormatException expected) {} - context.assertIsSatisfied(); - } - - @Test - public void testNoFormatExceptionIfBatchIsMaximumSize() throws Exception { - final UnverifiedBatchFactory batchFactory = - context.mock(UnverifiedBatchFactory.class); - BatchReader batchReader = new BatchReader(messageReader, batchFactory); - final UnverifiedBatch batch = context.mock(UnverifiedBatch.class); - context.checking(new Expectations() {{ - oneOf(batchFactory).createUnverifiedBatch( - Collections.singletonList(message)); - will(returnValue(batch)); - }}); - - byte[] b = createBatch(MAX_PACKET_LENGTH); - ByteArrayInputStream in = new ByteArrayInputStream(b); - Reader reader = readerFactory.createReader(in); - reader.addStructReader(Types.BATCH, batchReader); - - assertEquals(batch, reader.readStruct(Types.BATCH, - UnverifiedBatch.class)); - context.assertIsSatisfied(); - } - - @Test - public void testEmptyBatch() throws Exception { - final UnverifiedBatchFactory batchFactory = - context.mock(UnverifiedBatchFactory.class); - BatchReader batchReader = new BatchReader(messageReader, batchFactory); - - byte[] b = createEmptyBatch(); - ByteArrayInputStream in = new ByteArrayInputStream(b); - Reader reader = readerFactory.createReader(in); - reader.addStructReader(Types.BATCH, batchReader); - - try { - reader.readStruct(Types.BATCH, UnverifiedBatch.class); - fail(); - } catch(FormatException expected) {} - context.assertIsSatisfied(); - } - - private byte[] createBatch(int size) throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(size); - Writer w = writerFactory.createWriter(out); - w.writeStructId(Types.BATCH); - w.writeListStart(); - // We're using a fake message reader, so it's OK to use a fake message - w.writeStructId(Types.MESSAGE); - w.writeBytes(new byte[size - 10]); - w.writeListEnd(); - byte[] b = out.toByteArray(); - assertEquals(size, b.length); - return b; - } - - private byte[] createEmptyBatch() throws Exception { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - Writer w = writerFactory.createWriter(out); - w.writeStructId(Types.BATCH); - w.writeListStart(); - w.writeListEnd(); - return out.toByteArray(); - } - - private class TestMessageReader implements StructReader<UnverifiedMessage> { - - public UnverifiedMessage readStruct(Reader r) throws IOException { - r.readStructId(Types.MESSAGE); - r.readBytes(); - return message; - } - } -} diff --git a/briar-tests/src/net/sf/briar/protocol/ConstantsTest.java b/briar-tests/src/net/sf/briar/protocol/ConstantsTest.java index 5f3fee3fa4..94543fb5f7 100644 --- a/briar-tests/src/net/sf/briar/protocol/ConstantsTest.java +++ b/briar-tests/src/net/sf/briar/protocol/ConstantsTest.java @@ -14,7 +14,6 @@ import java.io.ByteArrayOutputStream; import java.security.PrivateKey; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Map; import net.sf.briar.BriarTestCase; @@ -23,7 +22,6 @@ 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; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupFactory; import net.sf.briar.api.protocol.Message; @@ -33,7 +31,6 @@ import net.sf.briar.api.protocol.Offer; import net.sf.briar.api.protocol.PacketFactory; import net.sf.briar.api.protocol.ProtocolWriter; import net.sf.briar.api.protocol.ProtocolWriterFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.Transport; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.TransportUpdate; @@ -69,24 +66,24 @@ public class ConstantsTest extends BriarTestCase { } @Test - public void testBatchesFitIntoLargeAck() throws Exception { - testBatchesFitIntoAck(MAX_PACKET_LENGTH); + public void testMessageIdsFitIntoLargeAck() throws Exception { + testMessageIdsFitIntoAck(MAX_PACKET_LENGTH); } @Test - public void testBatchesFitIntoSmallAck() throws Exception { - testBatchesFitIntoAck(1000); + public void testMessageIdsFitIntoSmallAck() throws Exception { + testMessageIdsFitIntoAck(1000); } - private void testBatchesFitIntoAck(int length) throws Exception { - // Create an ack with as many batch IDs as possible + private void testMessageIdsFitIntoAck(int length) throws Exception { + // Create an ack with as many message IDs as possible ByteArrayOutputStream out = new ByteArrayOutputStream(length); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out, true); - int maxBatches = writer.getMaxBatchesForAck(length); - Collection<BatchId> acked = new ArrayList<BatchId>(); - for(int i = 0; i < maxBatches; i++) { - acked.add(new BatchId(TestUtils.getRandomId())); + int maxMessages = writer.getMaxMessagesForAck(length); + Collection<MessageId> acked = new ArrayList<MessageId>(); + for(int i = 0; i < maxMessages; i++) { + acked.add(new MessageId(TestUtils.getRandomId())); } Ack a = packetFactory.createAck(acked); writer.writeAck(a); @@ -95,7 +92,7 @@ public class ConstantsTest extends BriarTestCase { } @Test - public void testMessageFitsIntoBatch() throws Exception { + public void testMessageFitsIntoPacket() throws Exception { // Create a maximum-length group String groupName = createRandomString(MAX_GROUP_NAME_LENGTH); byte[] groupPublic = new byte[MAX_PUBLIC_KEY_LENGTH]; @@ -111,32 +108,25 @@ public class ConstantsTest extends BriarTestCase { byte[] body = new byte[MAX_BODY_LENGTH]; Message message = messageFactory.createMessage(null, group, groupPrivate, author, authorPrivate, subject, body); - // Add the message to a batch - ByteArrayOutputStream out = - new ByteArrayOutputStream(MAX_PACKET_LENGTH); - ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out, - true); - RawBatch b = packetFactory.createBatch(Collections.singletonList( - message.getSerialised())); - writer.writeBatch(b); - // Check the size of the serialised batch - assertTrue(out.size() > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH + // Check the size of the serialised message + int length = message.getSerialised().length; + assertTrue(length > UniqueId.LENGTH + MAX_GROUP_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + MAX_BODY_LENGTH); - assertTrue(out.size() <= MAX_PACKET_LENGTH); + assertTrue(length <= MAX_PACKET_LENGTH); } @Test - public void testMessagesFitIntoLargeOffer() throws Exception { - testMessagesFitIntoOffer(MAX_PACKET_LENGTH); + public void testMessageIdsFitIntoLargeOffer() throws Exception { + testMessageIdsFitIntoOffer(MAX_PACKET_LENGTH); } @Test - public void testMessagesFitIntoSmallOffer() throws Exception { - testMessagesFitIntoOffer(1000); + public void testMessageIdsFitIntoSmallOffer() throws Exception { + testMessageIdsFitIntoOffer(1000); } - private void testMessagesFitIntoOffer(int length) throws Exception { + private void testMessageIdsFitIntoOffer(int length) throws Exception { // Create an offer with as many message IDs as possible ByteArrayOutputStream out = new ByteArrayOutputStream(length); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out, @@ -170,7 +160,7 @@ public class ConstantsTest extends BriarTestCase { } // Add the transports to an update ByteArrayOutputStream out = - new ByteArrayOutputStream(MAX_PACKET_LENGTH); + new ByteArrayOutputStream(MAX_PACKET_LENGTH); ProtocolWriter writer = protocolWriterFactory.createProtocolWriter(out, true); TransportUpdate t = packetFactory.createTransportUpdate(transports, diff --git a/briar-tests/src/net/sf/briar/protocol/ProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/protocol/ProtocolIntegrationTest.java deleted file mode 100644 index 6328c65358..0000000000 --- a/briar-tests/src/net/sf/briar/protocol/ProtocolIntegrationTest.java +++ /dev/null @@ -1,134 +0,0 @@ -package net.sf.briar.protocol; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.util.BitSet; -import java.util.Collection; -import java.util.Collections; -import java.util.Map; - -import net.sf.briar.BriarTestCase; -import net.sf.briar.TestUtils; -import net.sf.briar.api.protocol.Ack; -import net.sf.briar.api.protocol.Batch; -import net.sf.briar.api.protocol.BatchId; -import net.sf.briar.api.protocol.Group; -import net.sf.briar.api.protocol.GroupFactory; -import net.sf.briar.api.protocol.GroupId; -import net.sf.briar.api.protocol.Message; -import net.sf.briar.api.protocol.MessageFactory; -import net.sf.briar.api.protocol.Offer; -import net.sf.briar.api.protocol.PacketFactory; -import net.sf.briar.api.protocol.ProtocolReader; -import net.sf.briar.api.protocol.ProtocolReaderFactory; -import net.sf.briar.api.protocol.ProtocolWriter; -import net.sf.briar.api.protocol.ProtocolWriterFactory; -import net.sf.briar.api.protocol.RawBatch; -import net.sf.briar.api.protocol.Request; -import net.sf.briar.api.protocol.SubscriptionUpdate; -import net.sf.briar.api.protocol.Transport; -import net.sf.briar.api.protocol.TransportId; -import net.sf.briar.api.protocol.TransportUpdate; -import net.sf.briar.clock.ClockModule; -import net.sf.briar.crypto.CryptoModule; -import net.sf.briar.serial.SerialModule; - -import org.junit.Test; - -import com.google.inject.Guice; -import com.google.inject.Injector; - -public class ProtocolIntegrationTest extends BriarTestCase { - - private final ProtocolReaderFactory readerFactory; - private final ProtocolWriterFactory writerFactory; - private final PacketFactory packetFactory; - private final BatchId batchId; - private final Group group; - private final Message message; - private final String subject = "Hello"; - private final String messageBody = "Hello world"; - private final BitSet bitSet; - private final Map<Group, Long> subscriptions; - private final Collection<Transport> transports; - private final long timestamp = System.currentTimeMillis(); - - public ProtocolIntegrationTest() throws Exception { - super(); - Injector i = Guice.createInjector(new ClockModule(), new CryptoModule(), - new ProtocolModule(), new SerialModule()); - readerFactory = i.getInstance(ProtocolReaderFactory.class); - writerFactory = i.getInstance(ProtocolWriterFactory.class); - packetFactory = i.getInstance(PacketFactory.class); - batchId = new BatchId(TestUtils.getRandomId()); - GroupFactory groupFactory = i.getInstance(GroupFactory.class); - group = groupFactory.createGroup("Unrestricted group", null); - MessageFactory messageFactory = i.getInstance(MessageFactory.class); - message = messageFactory.createMessage(null, group, subject, - messageBody.getBytes("UTF-8")); - bitSet = new BitSet(); - bitSet.set(3); - bitSet.set(7); - subscriptions = Collections.singletonMap(group, 123L); - TransportId transportId = new TransportId(TestUtils.getRandomId()); - Transport transport = new Transport(transportId, - Collections.singletonMap("bar", "baz")); - transports = Collections.singletonList(transport); - } - - @Test - public void testWriteAndRead() throws Exception { - // Write - ByteArrayOutputStream out = new ByteArrayOutputStream(); - ProtocolWriter writer = writerFactory.createProtocolWriter(out, true); - - Ack a = packetFactory.createAck(Collections.singletonList(batchId)); - writer.writeAck(a); - - RawBatch b = packetFactory.createBatch(Collections.singletonList( - message.getSerialised())); - writer.writeBatch(b); - - Offer o = packetFactory.createOffer(Collections.singletonList( - message.getId())); - writer.writeOffer(o); - - Request r = packetFactory.createRequest(bitSet, 10); - writer.writeRequest(r); - - SubscriptionUpdate s = packetFactory.createSubscriptionUpdate( - Collections.<GroupId, GroupId>emptyMap(), subscriptions, 0L, - timestamp); - writer.writeSubscriptionUpdate(s); - - TransportUpdate t = packetFactory.createTransportUpdate(transports, - timestamp); - writer.writeTransportUpdate(t); - - // Read - ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - ProtocolReader reader = readerFactory.createProtocolReader(in); - - a = reader.readAck(); - assertEquals(Collections.singletonList(batchId), a.getBatchIds()); - - Batch b1 = reader.readBatch().verify(); - assertEquals(Collections.singletonList(message), b1.getMessages()); - - o = reader.readOffer(); - assertEquals(Collections.singletonList(message.getId()), - o.getMessageIds()); - - r = reader.readRequest(); - assertEquals(bitSet, r.getBitmap()); - assertEquals(10, r.getLength()); - - s = reader.readSubscriptionUpdate(); - assertEquals(subscriptions, s.getSubscriptions()); - assertEquals(timestamp, s.getTimestamp()); - - t = reader.readTransportUpdate(); - assertEquals(transports, t.getTransports()); - assertEquals(timestamp, t.getTimestamp()); - } -} diff --git a/briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java b/briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java deleted file mode 100644 index 08fdb3adbb..0000000000 --- a/briar-tests/src/net/sf/briar/protocol/UnverifiedBatchImplTest.java +++ /dev/null @@ -1,242 +0,0 @@ -package net.sf.briar.protocol; - -import java.security.GeneralSecurityException; -import java.security.KeyPair; -import java.security.Signature; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.Random; - -import net.sf.briar.BriarTestCase; -import net.sf.briar.TestUtils; -import net.sf.briar.api.crypto.CryptoComponent; -import net.sf.briar.api.crypto.MessageDigest; -import net.sf.briar.api.protocol.Author; -import net.sf.briar.api.protocol.AuthorId; -import net.sf.briar.api.protocol.Batch; -import net.sf.briar.api.protocol.BatchId; -import net.sf.briar.api.protocol.Group; -import net.sf.briar.api.protocol.GroupId; -import net.sf.briar.api.protocol.Message; -import net.sf.briar.api.protocol.MessageId; -import net.sf.briar.api.protocol.UnverifiedBatch; -import net.sf.briar.crypto.CryptoModule; - -import org.jmock.Expectations; -import org.jmock.Mockery; -import org.junit.Test; - -import com.google.inject.Guice; -import com.google.inject.Injector; - -public class UnverifiedBatchImplTest extends BriarTestCase { - - // FIXME: This is an integration test, not a unit test - - private final CryptoComponent crypto; - private final byte[] raw, raw1; - private final String subject; - private final long timestamp; - - public UnverifiedBatchImplTest() { - super(); - Injector i = Guice.createInjector(new CryptoModule()); - crypto = i.getInstance(CryptoComponent.class); - Random r = new Random(); - raw = new byte[123]; - r.nextBytes(raw); - raw1 = new byte[1234]; - r.nextBytes(raw1); - subject = "Unit tests are exciting"; - timestamp = System.currentTimeMillis(); - } - - @Test - public void testIds() throws Exception { - // Calculate the expected batch and message IDs - MessageDigest messageDigest = crypto.getMessageDigest(); - messageDigest.update(raw); - messageDigest.update(raw1); - BatchId batchId = new BatchId(messageDigest.digest()); - messageDigest.update(raw); - MessageId messageId = new MessageId(messageDigest.digest()); - messageDigest.update(raw1); - MessageId messageId1 = new MessageId(messageDigest.digest()); - // Verify the batch - Mockery context = new Mockery(); - final UnverifiedMessage message = - context.mock(UnverifiedMessage.class, "message"); - final UnverifiedMessage message1 = - context.mock(UnverifiedMessage.class, "message1"); - context.checking(new Expectations() {{ - // First message - oneOf(message).getRaw(); - will(returnValue(raw)); - oneOf(message).getAuthor(); - will(returnValue(null)); - oneOf(message).getGroup(); - will(returnValue(null)); - oneOf(message).getParent(); - will(returnValue(null)); - oneOf(message).getSubject(); - will(returnValue(subject)); - oneOf(message).getTimestamp(); - will(returnValue(timestamp)); - oneOf(message).getBodyStart(); - will(returnValue(10)); - oneOf(message).getBodyLength(); - will(returnValue(100)); - // Second message - oneOf(message1).getRaw(); - will(returnValue(raw1)); - oneOf(message1).getAuthor(); - will(returnValue(null)); - oneOf(message1).getGroup(); - will(returnValue(null)); - oneOf(message1).getParent(); - will(returnValue(null)); - oneOf(message1).getSubject(); - will(returnValue(subject)); - oneOf(message1).getTimestamp(); - will(returnValue(timestamp)); - oneOf(message1).getBodyStart(); - will(returnValue(10)); - oneOf(message1).getBodyLength(); - will(returnValue(1000)); - }}); - Collection<UnverifiedMessage> messages = Arrays.asList(message, - message1); - UnverifiedBatch batch = new UnverifiedBatchImpl(crypto, messages); - Batch verifiedBatch = batch.verify(); - // Check that the batch and message IDs match - assertEquals(batchId, verifiedBatch.getId()); - Collection<Message> verifiedMessages = verifiedBatch.getMessages(); - assertEquals(2, verifiedMessages.size()); - Iterator<Message> it = verifiedMessages.iterator(); - Message verifiedMessage = it.next(); - assertEquals(messageId, verifiedMessage.getId()); - Message verifiedMessage1 = it.next(); - assertEquals(messageId1, verifiedMessage1.getId()); - context.assertIsSatisfied(); - } - - @Test - public void testSignatures() throws Exception { - final int signedByAuthor = 100, signedByGroup = 110; - final KeyPair authorKeyPair = crypto.generateSignatureKeyPair(); - final KeyPair groupKeyPair = crypto.generateSignatureKeyPair(); - GroupId groupId = new GroupId(TestUtils.getRandomId()); - final Group group = new Group(groupId, "Group name", - groupKeyPair.getPublic().getEncoded()); - Signature signature = crypto.getSignature(); - // Calculate the expected author and group signatures - signature.initSign(authorKeyPair.getPrivate()); - signature.update(raw, 0, signedByAuthor); - final byte[] authorSignature = signature.sign(); - signature.initSign(groupKeyPair.getPrivate()); - signature.update(raw, 0, signedByGroup); - final byte[] groupSignature = signature.sign(); - // Verify the batch - Mockery context = new Mockery(); - final UnverifiedMessage message = - context.mock(UnverifiedMessage.class, "message"); - final Author author = context.mock(Author.class); - final UnverifiedMessage message1 = - context.mock(UnverifiedMessage.class, "message1"); - context.checking(new Expectations() {{ - // First message - oneOf(message).getRaw(); - will(returnValue(raw)); - oneOf(message).getAuthor(); - will(returnValue(author)); - oneOf(author).getPublicKey(); - will(returnValue(authorKeyPair.getPublic().getEncoded())); - oneOf(message).getLengthSignedByAuthor(); - will(returnValue(signedByAuthor)); - oneOf(message).getAuthorSignature(); - will(returnValue(authorSignature)); - oneOf(message).getGroup(); - will(returnValue(group)); - oneOf(message).getLengthSignedByGroup(); - will(returnValue(signedByGroup)); - oneOf(message).getGroupSignature(); - will(returnValue(groupSignature)); - oneOf(author).getId(); - will(returnValue(new AuthorId(TestUtils.getRandomId()))); - oneOf(message).getParent(); - will(returnValue(null)); - oneOf(message).getSubject(); - will(returnValue(subject)); - oneOf(message).getTimestamp(); - will(returnValue(timestamp)); - oneOf(message).getBodyStart(); - will(returnValue(10)); - oneOf(message).getBodyLength(); - will(returnValue(100)); - // Second message - oneOf(message1).getRaw(); - will(returnValue(raw1)); - oneOf(message1).getAuthor(); - will(returnValue(null)); - oneOf(message1).getGroup(); - will(returnValue(null)); - oneOf(message1).getParent(); - will(returnValue(null)); - oneOf(message1).getSubject(); - will(returnValue(subject)); - oneOf(message1).getTimestamp(); - will(returnValue(timestamp)); - oneOf(message1).getBodyStart(); - will(returnValue(10)); - oneOf(message1).getBodyLength(); - will(returnValue(1000)); - }}); - Collection<UnverifiedMessage> messages = Arrays.asList(message, - message1); - UnverifiedBatch batch = new UnverifiedBatchImpl(crypto, messages); - batch.verify(); - context.assertIsSatisfied(); - } - - @Test - public void testExceptionThrownIfMessageIsModified() throws Exception { - final int signedByAuthor = 100; - final KeyPair authorKeyPair = crypto.generateSignatureKeyPair(); - Signature signature = crypto.getSignature(); - // Calculate the expected author signature - signature.initSign(authorKeyPair.getPrivate()); - signature.update(raw, 0, signedByAuthor); - final byte[] authorSignature = signature.sign(); - // Modify the message - raw[signedByAuthor / 2] ^= 0xff; - // Verify the batch - Mockery context = new Mockery(); - final UnverifiedMessage message = - context.mock(UnverifiedMessage.class, "message"); - final Author author = context.mock(Author.class); - final UnverifiedMessage message1 = - context.mock(UnverifiedMessage.class, "message1"); - context.checking(new Expectations() {{ - // First message - verification will fail at the author's signature - oneOf(message).getRaw(); - will(returnValue(raw)); - oneOf(message).getAuthor(); - will(returnValue(author)); - oneOf(author).getPublicKey(); - will(returnValue(authorKeyPair.getPublic().getEncoded())); - oneOf(message).getLengthSignedByAuthor(); - will(returnValue(signedByAuthor)); - oneOf(message).getAuthorSignature(); - will(returnValue(authorSignature)); - }}); - Collection<UnverifiedMessage> messages = Arrays.asList(message, - message1); - UnverifiedBatch batch = new UnverifiedBatchImpl(crypto, messages); - try { - batch.verify(); - fail(); - } catch(GeneralSecurityException expected) {} - context.assertIsSatisfied(); - } -} diff --git a/briar-tests/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java b/briar-tests/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java index bc0491b2e0..fef1015b04 100644 --- a/briar-tests/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java +++ b/briar-tests/src/net/sf/briar/protocol/simplex/OutgoingSimplexConnectionTest.java @@ -17,9 +17,8 @@ import net.sf.briar.api.ContactId; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseExecutor; import net.sf.briar.api.protocol.Ack; -import net.sf.briar.api.protocol.BatchId; +import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.ProtocolWriterFactory; -import net.sf.briar.api.protocol.RawBatch; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.protocol.UniqueId; import net.sf.briar.api.transport.ConnectionContext; @@ -51,6 +50,7 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase { private final ConnectionWriterFactory connFactory; private final ProtocolWriterFactory protoFactory; private final ContactId contactId; + private final MessageId messageId; private final TransportId transportId; private final byte[] secret; @@ -75,6 +75,7 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase { connFactory = i.getInstance(ConnectionWriterFactory.class); protoFactory = i.getInstance(ProtocolWriterFactory.class); contactId = new ContactId(234); + messageId = new MessageId(TestUtils.getRandomId()); transportId = new TransportId(TestUtils.getRandomId()); secret = new byte[32]; } @@ -115,7 +116,7 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase { // No acks to send oneOf(db).generateAck(with(contactId), with(any(int.class))); will(returnValue(null)); - // No batches to send + // No messages to send oneOf(db).generateBatch(with(contactId), with(any(int.class))); will(returnValue(null)); }}); @@ -138,9 +139,7 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase { OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db, connRegistry, connFactory, protoFactory, ctx, transport); final Ack ack = context.mock(Ack.class); - final BatchId batchId = new BatchId(TestUtils.getRandomId()); - final RawBatch batch = context.mock(RawBatch.class); - final byte[] message = new byte[1234]; + final byte[] raw = new byte[1234]; context.checking(new Expectations() {{ // No transports to send oneOf(db).generateTransportUpdate(contactId); @@ -151,24 +150,22 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase { // One ack to send oneOf(db).generateAck(with(contactId), with(any(int.class))); will(returnValue(ack)); - oneOf(ack).getBatchIds(); - will(returnValue(Collections.singletonList(batchId))); + oneOf(ack).getMessageIds(); + will(returnValue(Collections.singletonList(messageId))); // No more acks oneOf(db).generateAck(with(contactId), with(any(int.class))); will(returnValue(null)); - // One batch to send + // One message to send oneOf(db).generateBatch(with(contactId), with(any(int.class))); - will(returnValue(batch)); - oneOf(batch).getMessages(); - will(returnValue(Collections.singletonList(message))); - // No more batches + will(returnValue(Collections.singletonList(raw))); + // No more messages oneOf(db).generateBatch(with(contactId), with(any(int.class))); will(returnValue(null)); }}); connection.write(); // Something should have been written int overhead = TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH; - assertTrue(out.size() > overhead + UniqueId.LENGTH + message.length); + assertTrue(out.size() > overhead + UniqueId.LENGTH + raw.length); // The transport should have been disposed with exception == false assertTrue(transport.getDisposed()); assertFalse(transport.getException()); diff --git a/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java b/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java index 302b37e3d0..cffd54b1e9 100644 --- a/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java +++ b/briar-tests/src/net/sf/briar/protocol/simplex/SimplexProtocolIntegrationTest.java @@ -17,9 +17,10 @@ import net.sf.briar.api.crypto.KeyManager; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.event.DatabaseEvent; import net.sf.briar.api.db.event.DatabaseListener; -import net.sf.briar.api.db.event.MessagesAddedEvent; +import net.sf.briar.api.db.event.MessageAddedEvent; import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageFactory; +import net.sf.briar.api.protocol.MessageVerifier; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.ProtocolWriterFactory; import net.sf.briar.api.protocol.Transport; @@ -181,6 +182,8 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase { ConnectionContext ctx = rec.acceptConnection(transportId, tag); assertNotNull(ctx); // Create an incoming simplex connection + MessageVerifier messageVerifier = + bob.getInstance(MessageVerifier.class); ConnectionRegistry connRegistry = bob.getInstance(ConnectionRegistry.class); ConnectionReaderFactory connFactory = @@ -190,8 +193,9 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase { TestSimplexTransportReader transport = new TestSimplexTransportReader(in); IncomingSimplexConnection simplex = new IncomingSimplexConnection( - new ImmediateExecutor(), new ImmediateExecutor(), db, - connRegistry, connFactory, protoFactory, ctx, transport); + new ImmediateExecutor(), new ImmediateExecutor(), + messageVerifier, db, connRegistry, connFactory, protoFactory, + ctx, transport); // No messages should have been added yet assertFalse(listener.messagesAdded); // Read whatever needs to be read @@ -216,8 +220,7 @@ public class SimplexProtocolIntegrationTest extends BriarTestCase { private boolean messagesAdded = false; public void eventOccurred(DatabaseEvent e) { - if(e instanceof MessagesAddedEvent) - messagesAdded = true; + if(e instanceof MessageAddedEvent) messagesAdded = true; } } } diff --git a/briar-tests/src/net/sf/briar/transport/ConnectionWriterImplTest.java b/briar-tests/src/net/sf/briar/transport/ConnectionWriterImplTest.java index 663700326d..c0c7437816 100644 --- a/briar-tests/src/net/sf/briar/transport/ConnectionWriterImplTest.java +++ b/briar-tests/src/net/sf/briar/transport/ConnectionWriterImplTest.java @@ -8,7 +8,6 @@ import org.jmock.Expectations; import org.jmock.Mockery; import org.junit.Test; - public class ConnectionWriterImplTest extends BriarTestCase { private static final int FRAME_LENGTH = 1024; diff --git a/briar-tests/src/net/sf/briar/transport/TransportIntegrationTest.java b/briar-tests/src/net/sf/briar/transport/TransportIntegrationTest.java index daa99b5b02..e2ec072e5e 100644 --- a/briar-tests/src/net/sf/briar/transport/TransportIntegrationTest.java +++ b/briar-tests/src/net/sf/briar/transport/TransportIntegrationTest.java @@ -18,19 +18,12 @@ import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.crypto.ErasableKey; import net.sf.briar.api.protocol.TransportId; import net.sf.briar.api.transport.ConnectionContext; -import net.sf.briar.api.transport.ConnectionReader; import net.sf.briar.api.transport.ConnectionWriter; import net.sf.briar.api.transport.ConnectionWriterFactory; import net.sf.briar.crypto.CryptoModule; -import net.sf.briar.transport.ConnectionReaderImpl; -import net.sf.briar.transport.ConnectionWriterFactoryImpl; -import net.sf.briar.transport.ConnectionWriterImpl; -import net.sf.briar.transport.IncomingEncryptionLayer; -import net.sf.briar.transport.OutgoingEncryptionLayer; import org.junit.Test; - import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; @@ -93,7 +86,7 @@ public class TransportIntegrationTest extends BriarTestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(); FrameWriter encryptionOut = new OutgoingEncryptionLayer(out, Long.MAX_VALUE, frameCipher, frameCopy, FRAME_LENGTH); - ConnectionWriter writer = new ConnectionWriterImpl(encryptionOut, + ConnectionWriterImpl writer = new ConnectionWriterImpl(encryptionOut, FRAME_LENGTH); OutputStream out1 = writer.getOutputStream(); out1.write(frame); @@ -106,7 +99,7 @@ public class TransportIntegrationTest extends BriarTestCase { ByteArrayInputStream in = new ByteArrayInputStream(output); FrameReader encryptionIn = new IncomingEncryptionLayer(in, frameCipher, frameKey, FRAME_LENGTH); - ConnectionReader reader = new ConnectionReaderImpl(encryptionIn, + ConnectionReaderImpl reader = new ConnectionReaderImpl(encryptionIn, FRAME_LENGTH); InputStream in1 = reader.getInputStream(); byte[] recovered = new byte[frame.length]; -- GitLab