From 941460e3bc52b2e83047428ee9cf73d5d2f7fb5a Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Sat, 23 Jul 2011 21:46:47 +0100 Subject: [PATCH] Readers, writers and factories for subscription and transport updates. --- api/net/sf/briar/api/protocol/Group.java | 4 +- .../sf/briar/api/protocol/GroupFactory.java | 3 +- .../sf/briar/api/protocol/Subscriptions.java | 6 ++ api/net/sf/briar/api/protocol/Tags.java | 11 +-- api/net/sf/briar/api/protocol/Transports.java | 6 ++ .../briar/api/protocol/writers/AckWriter.java | 2 +- .../api/protocol/writers/BatchWriter.java | 2 +- .../protocol/writers/SubscriptionWriter.java | 5 +- .../api/protocol/writers/TransportWriter.java | 4 +- .../db/ReadWriteLockDatabaseComponent.java | 8 +- .../db/SynchronizedDatabaseComponent.java | 8 +- .../net/sf/briar/protocol/AckReader.java | 6 +- .../sf/briar/protocol/GroupFactoryImpl.java | 10 +-- .../net/sf/briar/protocol/GroupImpl.java | 21 ++++- .../net/sf/briar/protocol/GroupReader.java | 38 +++++++++ .../sf/briar/protocol/MessageEncoderImpl.java | 3 + .../net/sf/briar/protocol/ProtocolModule.java | 2 + .../briar/protocol/SubscriptionFactory.java | 11 +++ .../protocol/SubscriptionFactoryImpl.java | 14 ++++ .../sf/briar/protocol/SubscriptionReader.java | 38 +++++++++ .../sf/briar/protocol/SubscriptionsImpl.java | 25 ++++++ .../sf/briar/protocol/TransportFactory.java | 10 +++ .../briar/protocol/TransportFactoryImpl.java | 13 ++++ .../sf/briar/protocol/TransportReader.java | 31 ++++++++ .../net/sf/briar/protocol/TransportsImpl.java | 24 ++++++ .../briar/protocol/writers/AckWriterImpl.java | 4 +- .../protocol/writers/BatchWriterImpl.java | 2 +- .../writers/PacketWriterFactoryImpl.java | 6 +- .../writers/SubscriptionWriterImpl.java | 33 ++++++++ .../protocol/writers/TransportWriterImpl.java | 33 ++++++++ .../sf/briar/db/DatabaseComponentTest.java | 4 +- test/net/sf/briar/db/H2DatabaseTest.java | 5 +- test/net/sf/briar/protocol/AckReaderTest.java | 6 +- .../sf/briar/protocol/FileReadWriteTest.java | 78 ++++++++++++++++--- 34 files changed, 423 insertions(+), 53 deletions(-) create mode 100644 components/net/sf/briar/protocol/GroupReader.java create mode 100644 components/net/sf/briar/protocol/SubscriptionFactory.java create mode 100644 components/net/sf/briar/protocol/SubscriptionFactoryImpl.java create mode 100644 components/net/sf/briar/protocol/SubscriptionReader.java create mode 100644 components/net/sf/briar/protocol/SubscriptionsImpl.java create mode 100644 components/net/sf/briar/protocol/TransportFactory.java create mode 100644 components/net/sf/briar/protocol/TransportFactoryImpl.java create mode 100644 components/net/sf/briar/protocol/TransportReader.java create mode 100644 components/net/sf/briar/protocol/TransportsImpl.java create mode 100644 components/net/sf/briar/protocol/writers/SubscriptionWriterImpl.java create mode 100644 components/net/sf/briar/protocol/writers/TransportWriterImpl.java diff --git a/api/net/sf/briar/api/protocol/Group.java b/api/net/sf/briar/api/protocol/Group.java index 43de430292..13e63a2b30 100644 --- a/api/net/sf/briar/api/protocol/Group.java +++ b/api/net/sf/briar/api/protocol/Group.java @@ -2,8 +2,10 @@ package net.sf.briar.api.protocol; import java.security.PublicKey; +import net.sf.briar.api.serial.Writable; + /** A group to which users may subscribe. */ -public interface Group { +public interface Group extends Writable { /** Returns the group's unique identifier. */ GroupId getId(); diff --git a/api/net/sf/briar/api/protocol/GroupFactory.java b/api/net/sf/briar/api/protocol/GroupFactory.java index 55a4f79e2e..d10ab913a5 100644 --- a/api/net/sf/briar/api/protocol/GroupFactory.java +++ b/api/net/sf/briar/api/protocol/GroupFactory.java @@ -2,5 +2,6 @@ package net.sf.briar.api.protocol; public interface GroupFactory { - Group createGroup(GroupId id, String name, boolean restricted, byte[] b); + Group createGroup(GroupId id, String name, boolean restricted, + byte[] saltOrKey); } diff --git a/api/net/sf/briar/api/protocol/Subscriptions.java b/api/net/sf/briar/api/protocol/Subscriptions.java index ce9fc892c0..28d670c086 100644 --- a/api/net/sf/briar/api/protocol/Subscriptions.java +++ b/api/net/sf/briar/api/protocol/Subscriptions.java @@ -5,6 +5,12 @@ import java.util.Collection; /** A packet updating the sender's subscriptions. */ public interface Subscriptions { + /** + * The maximum size of a serialized subscriptions update, excluding + * encryption and authentication. + */ + static final int MAX_SIZE = (1024 * 1024) - 100; + /** Returns the subscriptions contained in the update. */ Collection<Group> getSubscriptions(); diff --git a/api/net/sf/briar/api/protocol/Tags.java b/api/net/sf/briar/api/protocol/Tags.java index 982c1106c9..b8edfb5d0c 100644 --- a/api/net/sf/briar/api/protocol/Tags.java +++ b/api/net/sf/briar/api/protocol/Tags.java @@ -11,9 +11,10 @@ public interface Tags { static final int AUTHOR_ID = 1; static final int BATCH = 2; static final int BATCH_ID = 3; - static final int GROUP_ID = 4; - static final int MESSAGE = 5; - static final int MESSAGE_ID = 6; - static final int SUBSCRIPTIONS = 7; - static final int TRANSPORTS = 8; + static final int GROUP = 4; + static final int GROUP_ID = 5; + static final int MESSAGE = 6; + static final int MESSAGE_ID = 7; + static final int SUBSCRIPTIONS = 8; + static final int TRANSPORTS = 9; } diff --git a/api/net/sf/briar/api/protocol/Transports.java b/api/net/sf/briar/api/protocol/Transports.java index 1c27f921c2..d18f5ccd3b 100644 --- a/api/net/sf/briar/api/protocol/Transports.java +++ b/api/net/sf/briar/api/protocol/Transports.java @@ -5,6 +5,12 @@ import java.util.Map; /** A packet updating the sender's transports. */ public interface Transports { + /** + * The maximum size of a serialised transports update, excluding + * encryption and authentication. + */ + static final int MAX_SIZE = (1024 * 1024) - 100; + /** Returns the transports contained in the update. */ Map<String, String> getTransports(); diff --git a/api/net/sf/briar/api/protocol/writers/AckWriter.java b/api/net/sf/briar/api/protocol/writers/AckWriter.java index 846b36144c..c362a60577 100644 --- a/api/net/sf/briar/api/protocol/writers/AckWriter.java +++ b/api/net/sf/briar/api/protocol/writers/AckWriter.java @@ -11,7 +11,7 @@ public interface AckWriter { * Attempts to add the given BatchId to the ack and returns true if it * was added. */ - boolean addBatchId(BatchId b) throws IOException; + boolean writeBatchId(BatchId b) throws IOException; /** Finishes writing the ack. */ void finish() throws IOException; diff --git a/api/net/sf/briar/api/protocol/writers/BatchWriter.java b/api/net/sf/briar/api/protocol/writers/BatchWriter.java index 4b6ecc0e1a..62e150dedc 100644 --- a/api/net/sf/briar/api/protocol/writers/BatchWriter.java +++ b/api/net/sf/briar/api/protocol/writers/BatchWriter.java @@ -14,7 +14,7 @@ public interface BatchWriter { * Attempts to add the given raw message to the batch and returns true if * it was added. */ - boolean addMessage(byte[] raw) throws IOException; + boolean writeMessage(byte[] raw) throws IOException; /** Finishes writing the batch and returns its unique identifier. */ BatchId finish() throws IOException; diff --git a/api/net/sf/briar/api/protocol/writers/SubscriptionWriter.java b/api/net/sf/briar/api/protocol/writers/SubscriptionWriter.java index 7e7d340d0c..5bbf4b5065 100644 --- a/api/net/sf/briar/api/protocol/writers/SubscriptionWriter.java +++ b/api/net/sf/briar/api/protocol/writers/SubscriptionWriter.java @@ -1,12 +1,13 @@ package net.sf.briar.api.protocol.writers; import java.io.IOException; +import java.util.Collection; import net.sf.briar.api.protocol.Group; /** An interface for creating a subscription update. */ public interface SubscriptionWriter { - /** Sets the contents of the update. */ - void setSubscriptions(Iterable<Group> subs) throws IOException; + /** Writes the contents of the update. */ + void writeSubscriptions(Collection<Group> subs) throws IOException; } diff --git a/api/net/sf/briar/api/protocol/writers/TransportWriter.java b/api/net/sf/briar/api/protocol/writers/TransportWriter.java index 5caa756c42..6e03d2f562 100644 --- a/api/net/sf/briar/api/protocol/writers/TransportWriter.java +++ b/api/net/sf/briar/api/protocol/writers/TransportWriter.java @@ -6,6 +6,6 @@ import java.util.Map; /** An interface for creating a transports update. */ public interface TransportWriter { - /** Sets the contents of the update. */ - void setTransports(Map<String, String> transports) throws IOException; + /** Writes the contents of the update. */ + void writeTransports(Map<String, String> transports) throws IOException; } diff --git a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java index 15cee66876..41f38f6efb 100644 --- a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java +++ b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java @@ -259,7 +259,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { try { Collection<BatchId> acks = db.getBatchesToAck(txn, c); Collection<BatchId> sent = new ArrayList<BatchId>(); - for(BatchId b : acks) if(a.addBatchId(b)) sent.add(b); + for(BatchId b : acks) if(a.writeBatchId(b)) sent.add(b); a.finish(); db.removeBatchesToAck(txn, c, sent); if(LOG.isLoggable(Level.FINE)) @@ -300,7 +300,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { while(it.hasNext()) { MessageId m = it.next(); byte[] message = db.getMessage(txn, m); - if(!b.addMessage(message)) break; + if(!b.writeMessage(message)) break; bytesSent += message.length; sent.add(m); } @@ -349,7 +349,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Txn txn = db.startTransaction(); try { Collection<Group> subs = db.getSubscriptions(txn); - s.setSubscriptions(subs); + s.writeSubscriptions(subs); if(LOG.isLoggable(Level.FINE)) LOG.fine("Added " + subs.size() + " subscriptions"); db.commitTransaction(txn); @@ -378,7 +378,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Txn txn = db.startTransaction(); try { Map<String, String> transports = db.getTransports(txn); - t.setTransports(transports); + t.writeTransports(transports); if(LOG.isLoggable(Level.FINE)) LOG.fine("Added " + transports.size() + " transports"); db.commitTransaction(txn); diff --git a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java index 1377739517..dc9241d8ad 100644 --- a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java +++ b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java @@ -192,7 +192,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { try { Collection<BatchId> acks = db.getBatchesToAck(txn, c); Collection<BatchId> sent = new ArrayList<BatchId>(); - for(BatchId b : acks) if(a.addBatchId(b)) sent.add(b); + for(BatchId b : acks) if(a.writeBatchId(b)) sent.add(b); a.finish(); db.removeBatchesToAck(txn, c, sent); if(LOG.isLoggable(Level.FINE)) @@ -225,7 +225,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { while(it.hasNext()) { MessageId m = it.next(); byte[] message = db.getMessage(txn, m); - if(!b.addMessage(message)) break; + if(!b.writeMessage(message)) break; bytesSent += message.length; sent.add(m); } @@ -254,7 +254,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Txn txn = db.startTransaction(); try { Collection<Group> subs = db.getSubscriptions(txn); - s.setSubscriptions(subs); + s.writeSubscriptions(subs); if(LOG.isLoggable(Level.FINE)) LOG.fine("Added " + subs.size() + " subscriptions"); db.commitTransaction(txn); @@ -277,7 +277,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { Txn txn = db.startTransaction(); try { Map<String, String> transports = db.getTransports(txn); - t.setTransports(transports); + t.writeTransports(transports); if(LOG.isLoggable(Level.FINE)) LOG.fine("Added " + transports.size() + " transports"); db.commitTransaction(txn); diff --git a/components/net/sf/briar/protocol/AckReader.java b/components/net/sf/briar/protocol/AckReader.java index 270b29f508..93c88fc8ab 100644 --- a/components/net/sf/briar/protocol/AckReader.java +++ b/components/net/sf/briar/protocol/AckReader.java @@ -11,9 +11,11 @@ import net.sf.briar.api.serial.Reader; class AckReader implements ObjectReader<Ack> { + private final ObjectReader<BatchId> batchIdReader; private final AckFactory ackFactory; - AckReader(AckFactory ackFactory) { + AckReader(ObjectReader<BatchId> batchIdReader, AckFactory ackFactory) { + this.batchIdReader = batchIdReader; this.ackFactory = ackFactory; } @@ -23,7 +25,7 @@ class AckReader implements ObjectReader<Ack> { // Read and digest the data r.addConsumer(counting); r.readUserDefinedTag(Tags.ACK); - r.addObjectReader(Tags.BATCH_ID, new BatchIdReader()); + r.addObjectReader(Tags.BATCH_ID, batchIdReader); Collection<BatchId> batches = r.readList(BatchId.class); r.removeObjectReader(Tags.BATCH_ID); r.removeConsumer(counting); diff --git a/components/net/sf/briar/protocol/GroupFactoryImpl.java b/components/net/sf/briar/protocol/GroupFactoryImpl.java index d9b1941066..b76028565f 100644 --- a/components/net/sf/briar/protocol/GroupFactoryImpl.java +++ b/components/net/sf/briar/protocol/GroupFactoryImpl.java @@ -20,14 +20,14 @@ class GroupFactoryImpl implements GroupFactory { } public Group createGroup(GroupId id, String name, boolean restricted, - byte[] b) { + byte[] saltOrKey) { if(restricted) { try { - PublicKey key = keyParser.parsePublicKey(b); - return new GroupImpl(id, name, null, key); - } catch (InvalidKeySpecException e) { + PublicKey key = keyParser.parsePublicKey(saltOrKey); + return new GroupImpl(id, name, key); + } catch(InvalidKeySpecException e) { throw new IllegalArgumentException(e); } - } else return new GroupImpl(id, name, b, null); + } else return new GroupImpl(id, name, saltOrKey); } } diff --git a/components/net/sf/briar/protocol/GroupImpl.java b/components/net/sf/briar/protocol/GroupImpl.java index 3335ab98e9..b70a544035 100644 --- a/components/net/sf/briar/protocol/GroupImpl.java +++ b/components/net/sf/briar/protocol/GroupImpl.java @@ -1,9 +1,12 @@ package net.sf.briar.protocol; +import java.io.IOException; import java.security.PublicKey; import net.sf.briar.api.protocol.Group; import net.sf.briar.api.protocol.GroupId; +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.serial.Writer; class GroupImpl implements Group { @@ -12,12 +15,18 @@ class GroupImpl implements Group { private final byte[] salt; private final PublicKey publicKey; - GroupImpl(GroupId id, String name, byte[] salt, PublicKey publicKey) { - assert salt == null || publicKey == null; + GroupImpl(GroupId id, String name, byte[] salt) { this.id = id; this.name = name; this.salt = salt; + publicKey = null; + } + + GroupImpl(GroupId id, String name, PublicKey publicKey) { + this.id = id; + this.name = name; this.publicKey = publicKey; + salt = null; } public GroupId getId() { @@ -40,6 +49,14 @@ class GroupImpl implements Group { return publicKey; } + public void writeTo(Writer w) throws IOException { + w.writeUserDefinedTag(Tags.GROUP); + w.writeString(name); + w.writeBoolean(isRestricted()); + if(salt == null) w.writeRaw(publicKey.getEncoded()); + else w.writeRaw(salt); + } + @Override public boolean equals(Object o) { return o instanceof Group && id.equals(((Group) o).getId()); diff --git a/components/net/sf/briar/protocol/GroupReader.java b/components/net/sf/briar/protocol/GroupReader.java new file mode 100644 index 0000000000..af94f29440 --- /dev/null +++ b/components/net/sf/briar/protocol/GroupReader.java @@ -0,0 +1,38 @@ +package net.sf.briar.protocol; + +import java.io.IOException; +import java.security.MessageDigest; + +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.Tags; +import net.sf.briar.api.serial.ObjectReader; +import net.sf.briar.api.serial.Reader; + +class GroupReader implements ObjectReader<Group> { + + private final MessageDigest messageDigest; + private final GroupFactory groupFactory; + + GroupReader(MessageDigest messageDigest, GroupFactory groupFactory) { + this.messageDigest = messageDigest; + this.groupFactory = groupFactory; + } + + public Group readObject(Reader r) throws IOException { + // Initialise the consumer + DigestingConsumer digesting = new DigestingConsumer(messageDigest); + messageDigest.reset(); + // Read and digest the data + r.addConsumer(digesting); + r.readUserDefinedTag(Tags.GROUP); + String name = r.readString(); + boolean restricted = r.readBoolean(); + byte[] saltOrKey = r.readRaw(); + r.removeConsumer(digesting); + // Build and return the group + GroupId id = new GroupId(messageDigest.digest()); + return groupFactory.createGroup(id, name, restricted, saltOrKey); + } +} diff --git a/components/net/sf/briar/protocol/MessageEncoderImpl.java b/components/net/sf/briar/protocol/MessageEncoderImpl.java index 11a99d6f39..e945166ce0 100644 --- a/components/net/sf/briar/protocol/MessageEncoderImpl.java +++ b/components/net/sf/briar/protocol/MessageEncoderImpl.java @@ -16,12 +16,15 @@ import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.serial.Writer; import net.sf.briar.api.serial.WriterFactory; +import com.google.inject.Inject; + class MessageEncoderImpl implements MessageEncoder { private final Signature signature; private final MessageDigest messageDigest; private final WriterFactory writerFactory; + @Inject MessageEncoderImpl(Signature signature, MessageDigest messageDigest, WriterFactory writerFactory) { this.signature = signature; diff --git a/components/net/sf/briar/protocol/ProtocolModule.java b/components/net/sf/briar/protocol/ProtocolModule.java index 402d6af9ac..d7d2311c77 100644 --- a/components/net/sf/briar/protocol/ProtocolModule.java +++ b/components/net/sf/briar/protocol/ProtocolModule.java @@ -1,6 +1,7 @@ package net.sf.briar.protocol; import net.sf.briar.api.protocol.GroupFactory; +import net.sf.briar.api.protocol.MessageEncoder; import com.google.inject.AbstractModule; @@ -11,5 +12,6 @@ public class ProtocolModule extends AbstractModule { bind(AckFactory.class).to(AckFactoryImpl.class); bind(BatchFactory.class).to(BatchFactoryImpl.class); bind(GroupFactory.class).to(GroupFactoryImpl.class); + bind(MessageEncoder.class).to(MessageEncoderImpl.class); } } diff --git a/components/net/sf/briar/protocol/SubscriptionFactory.java b/components/net/sf/briar/protocol/SubscriptionFactory.java new file mode 100644 index 0000000000..d6be2b293a --- /dev/null +++ b/components/net/sf/briar/protocol/SubscriptionFactory.java @@ -0,0 +1,11 @@ +package net.sf.briar.protocol; + +import java.util.Collection; + +import net.sf.briar.api.protocol.Group; +import net.sf.briar.api.protocol.Subscriptions; + +interface SubscriptionFactory { + + Subscriptions createSubscriptions(Collection<Group> subs, long timestamp); +} diff --git a/components/net/sf/briar/protocol/SubscriptionFactoryImpl.java b/components/net/sf/briar/protocol/SubscriptionFactoryImpl.java new file mode 100644 index 0000000000..53c21e50c9 --- /dev/null +++ b/components/net/sf/briar/protocol/SubscriptionFactoryImpl.java @@ -0,0 +1,14 @@ +package net.sf.briar.protocol; + +import java.util.Collection; + +import net.sf.briar.api.protocol.Group; +import net.sf.briar.api.protocol.Subscriptions; + +class SubscriptionFactoryImpl implements SubscriptionFactory { + + public Subscriptions createSubscriptions(Collection<Group> subs, + long timestamp) { + return new SubscriptionsImpl(subs, timestamp); + } +} diff --git a/components/net/sf/briar/protocol/SubscriptionReader.java b/components/net/sf/briar/protocol/SubscriptionReader.java new file mode 100644 index 0000000000..e490213711 --- /dev/null +++ b/components/net/sf/briar/protocol/SubscriptionReader.java @@ -0,0 +1,38 @@ +package net.sf.briar.protocol; + +import java.io.IOException; +import java.util.Collection; + +import net.sf.briar.api.protocol.Group; +import net.sf.briar.api.protocol.Subscriptions; +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.serial.ObjectReader; +import net.sf.briar.api.serial.Reader; + +class SubscriptionReader implements ObjectReader<Subscriptions> { + + private final ObjectReader<Group> groupReader; + private final SubscriptionFactory subscriptionFactory; + + SubscriptionReader(ObjectReader<Group> groupReader, + SubscriptionFactory subscriptionFactory) { + this.groupReader = groupReader; + this.subscriptionFactory = subscriptionFactory; + } + + public Subscriptions readObject(Reader r) throws IOException { + // Initialise the consumer + CountingConsumer counting = + new CountingConsumer(Subscriptions.MAX_SIZE); + // Read the data + r.addConsumer(counting); + r.readUserDefinedTag(Tags.SUBSCRIPTIONS); + r.addObjectReader(Tags.GROUP, groupReader); + Collection<Group> subs = r.readList(Group.class); + r.removeObjectReader(Tags.GROUP); + long timestamp = r.readInt64(); + r.removeConsumer(counting); + // Build and return the subscriptions update + return subscriptionFactory.createSubscriptions(subs, timestamp); + } +} diff --git a/components/net/sf/briar/protocol/SubscriptionsImpl.java b/components/net/sf/briar/protocol/SubscriptionsImpl.java new file mode 100644 index 0000000000..c3967cfc89 --- /dev/null +++ b/components/net/sf/briar/protocol/SubscriptionsImpl.java @@ -0,0 +1,25 @@ +package net.sf.briar.protocol; + +import java.util.Collection; + +import net.sf.briar.api.protocol.Group; +import net.sf.briar.api.protocol.Subscriptions; + +class SubscriptionsImpl implements Subscriptions { + + private final Collection<Group> subs; + private final long timestamp; + + SubscriptionsImpl(Collection<Group> subs, long timestamp) { + this.subs = subs; + this.timestamp = timestamp; + } + + public Collection<Group> getSubscriptions() { + return subs; + } + + public long getTimestamp() { + return timestamp; + } +} diff --git a/components/net/sf/briar/protocol/TransportFactory.java b/components/net/sf/briar/protocol/TransportFactory.java new file mode 100644 index 0000000000..8a2b397259 --- /dev/null +++ b/components/net/sf/briar/protocol/TransportFactory.java @@ -0,0 +1,10 @@ +package net.sf.briar.protocol; + +import java.util.Map; + +import net.sf.briar.api.protocol.Transports; + +interface TransportFactory { + + Transports createTransports(Map<String, String> transports, long timestamp); +} diff --git a/components/net/sf/briar/protocol/TransportFactoryImpl.java b/components/net/sf/briar/protocol/TransportFactoryImpl.java new file mode 100644 index 0000000000..85ceefc19b --- /dev/null +++ b/components/net/sf/briar/protocol/TransportFactoryImpl.java @@ -0,0 +1,13 @@ +package net.sf.briar.protocol; + +import java.util.Map; + +import net.sf.briar.api.protocol.Transports; + +class TransportFactoryImpl implements TransportFactory { + + public Transports createTransports(Map<String, String> transports, + long timestamp) { + return new TransportsImpl(transports, timestamp); + } +} diff --git a/components/net/sf/briar/protocol/TransportReader.java b/components/net/sf/briar/protocol/TransportReader.java new file mode 100644 index 0000000000..580d0ffd47 --- /dev/null +++ b/components/net/sf/briar/protocol/TransportReader.java @@ -0,0 +1,31 @@ +package net.sf.briar.protocol; + +import java.io.IOException; +import java.util.Map; + +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.protocol.Transports; +import net.sf.briar.api.serial.ObjectReader; +import net.sf.briar.api.serial.Reader; + +class TransportReader implements ObjectReader<Transports> { + + private final TransportFactory transportFactory; + + TransportReader(TransportFactory transportFactory) { + this.transportFactory = transportFactory; + } + + public Transports readObject(Reader r) throws IOException { + // Initialise the consumer + CountingConsumer counting = new CountingConsumer(Transports.MAX_SIZE); + // Read the data + r.addConsumer(counting); + r.readUserDefinedTag(Tags.TRANSPORTS); + Map<String, String> transports = r.readMap(String.class, String.class); + long timestamp = r.readInt64(); + r.removeConsumer(counting); + // Build and return the transports update + return transportFactory.createTransports(transports, timestamp); + } +} diff --git a/components/net/sf/briar/protocol/TransportsImpl.java b/components/net/sf/briar/protocol/TransportsImpl.java new file mode 100644 index 0000000000..247f4aa5fd --- /dev/null +++ b/components/net/sf/briar/protocol/TransportsImpl.java @@ -0,0 +1,24 @@ +package net.sf.briar.protocol; + +import java.util.Map; + +import net.sf.briar.api.protocol.Transports; + +class TransportsImpl implements Transports { + + private final Map<String, String> transports; + private final long timestamp; + + TransportsImpl(Map<String, String> transports, long timestamp) { + this.transports = transports; + this.timestamp = timestamp; + } + + public Map<String, String> getTransports() { + return transports; + } + + public long getTimestamp() { + return timestamp; + } +} diff --git a/components/net/sf/briar/protocol/writers/AckWriterImpl.java b/components/net/sf/briar/protocol/writers/AckWriterImpl.java index ebb6f9fe86..fbc854f0fe 100644 --- a/components/net/sf/briar/protocol/writers/AckWriterImpl.java +++ b/components/net/sf/briar/protocol/writers/AckWriterImpl.java @@ -19,10 +19,10 @@ class AckWriterImpl implements AckWriter { AckWriterImpl(OutputStream out, WriterFactory writerFactory) { this.out = out; - this.w = writerFactory.createWriter(out); + w = writerFactory.createWriter(out); } - public boolean addBatchId(BatchId b) throws IOException { + public boolean writeBatchId(BatchId b) throws IOException { if(finished) throw new IllegalStateException(); if(!started) { w.writeUserDefinedTag(Tags.ACK); diff --git a/components/net/sf/briar/protocol/writers/BatchWriterImpl.java b/components/net/sf/briar/protocol/writers/BatchWriterImpl.java index 99a06fcf75..1c026127f0 100644 --- a/components/net/sf/briar/protocol/writers/BatchWriterImpl.java +++ b/components/net/sf/briar/protocol/writers/BatchWriterImpl.java @@ -31,7 +31,7 @@ class BatchWriterImpl implements BatchWriter { return Batch.MAX_SIZE - 3; } - public boolean addMessage(byte[] message) throws IOException { + public boolean writeMessage(byte[] message) throws IOException { if(finished) throw new IllegalStateException(); if(!started) { messageDigest.reset(); diff --git a/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java b/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java index 3b99500486..97294daa51 100644 --- a/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java +++ b/components/net/sf/briar/protocol/writers/PacketWriterFactoryImpl.java @@ -33,12 +33,10 @@ class PacketWriterFactoryImpl implements PacketWriterFactory { } public SubscriptionWriter createSubscriptionWriter(OutputStream out) { - // TODO Auto-generated method stub - return null; + return new SubscriptionWriterImpl(out, writerFactory); } public TransportWriter createTransportWriter(OutputStream out) { - // TODO Auto-generated method stub - return null; + return new TransportWriterImpl(out, writerFactory); } } diff --git a/components/net/sf/briar/protocol/writers/SubscriptionWriterImpl.java b/components/net/sf/briar/protocol/writers/SubscriptionWriterImpl.java new file mode 100644 index 0000000000..ad4f6081bd --- /dev/null +++ b/components/net/sf/briar/protocol/writers/SubscriptionWriterImpl.java @@ -0,0 +1,33 @@ +package net.sf.briar.protocol.writers; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Collection; + +import net.sf.briar.api.protocol.Group; +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.protocol.writers.SubscriptionWriter; +import net.sf.briar.api.serial.Writer; +import net.sf.briar.api.serial.WriterFactory; + +class SubscriptionWriterImpl implements SubscriptionWriter { + + private final OutputStream out; + private final Writer w; + + private boolean used = false; + + SubscriptionWriterImpl(OutputStream out, WriterFactory writerFactory) { + this.out = out; + w = writerFactory.createWriter(out); + } + + public void writeSubscriptions(Collection<Group> subs) throws IOException { + if(used) throw new IllegalStateException(); + w.writeUserDefinedTag(Tags.SUBSCRIPTIONS); + w.writeList(subs); + w.writeInt64(System.currentTimeMillis()); + out.flush(); + used = true; + } +} diff --git a/components/net/sf/briar/protocol/writers/TransportWriterImpl.java b/components/net/sf/briar/protocol/writers/TransportWriterImpl.java new file mode 100644 index 0000000000..0bcca53c54 --- /dev/null +++ b/components/net/sf/briar/protocol/writers/TransportWriterImpl.java @@ -0,0 +1,33 @@ +package net.sf.briar.protocol.writers; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.protocol.writers.TransportWriter; +import net.sf.briar.api.serial.Writer; +import net.sf.briar.api.serial.WriterFactory; + +class TransportWriterImpl implements TransportWriter { + + private final OutputStream out; + private final Writer w; + + private boolean used = false; + + TransportWriterImpl(OutputStream out, WriterFactory writerFactory) { + this.out = out; + w = writerFactory.createWriter(out); + } + + public void writeTransports(Map<String, String> transports) + throws IOException { + if(used) throw new IllegalStateException(); + w.writeUserDefinedTag(Tags.TRANSPORTS); + w.writeMap(transports); + w.writeInt64(System.currentTimeMillis()); + out.flush(); + used = true; + } +} diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index c46107aad5..e389c37da4 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -464,9 +464,9 @@ public abstract class DatabaseComponentTest extends TestCase { oneOf(database).getBatchesToAck(txn, contactId); will(returnValue(twoAcks)); // Try to add both batches to the writer - only manage to add one - oneOf(ackWriter).addBatchId(batchId); + oneOf(ackWriter).writeBatchId(batchId); will(returnValue(true)); - oneOf(ackWriter).addBatchId(batchId1); + oneOf(ackWriter).writeBatchId(batchId1); will(returnValue(false)); oneOf(ackWriter).finish(); // Record the batch that was acked diff --git a/test/net/sf/briar/db/H2DatabaseTest.java b/test/net/sf/briar/db/H2DatabaseTest.java index 2ca8f09637..25fa730d4f 100644 --- a/test/net/sf/briar/db/H2DatabaseTest.java +++ b/test/net/sf/briar/db/H2DatabaseTest.java @@ -28,6 +28,7 @@ import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.crypto.CryptoModule; import net.sf.briar.protocol.ProtocolModule; +import net.sf.briar.serial.SerialModule; import org.apache.commons.io.FileSystemUtils; import org.junit.After; @@ -62,8 +63,8 @@ public class H2DatabaseTest extends TestCase { public H2DatabaseTest() throws Exception { super(); - Injector i = Guice.createInjector(new ProtocolModule(), - new CryptoModule()); + Injector i = Guice.createInjector(new CryptoModule(), + new ProtocolModule(), new SerialModule()); groupFactory = i.getInstance(GroupFactory.class); authorId = new AuthorId(TestUtils.getRandomId()); batchId = new BatchId(TestUtils.getRandomId()); diff --git a/test/net/sf/briar/protocol/AckReaderTest.java b/test/net/sf/briar/protocol/AckReaderTest.java index e3c7259c05..4c793e218f 100644 --- a/test/net/sf/briar/protocol/AckReaderTest.java +++ b/test/net/sf/briar/protocol/AckReaderTest.java @@ -42,7 +42,7 @@ public class AckReaderTest extends TestCase { @Test public void testFormatExceptionIfAckIsTooLarge() throws Exception { AckFactory ackFactory = context.mock(AckFactory.class); - AckReader ackReader = new AckReader(ackFactory); + AckReader ackReader = new AckReader(new BatchIdReader(), ackFactory); byte[] b = createAck(true); ByteArrayInputStream in = new ByteArrayInputStream(b); @@ -60,7 +60,7 @@ public class AckReaderTest extends TestCase { @SuppressWarnings("unchecked") public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception { final AckFactory ackFactory = context.mock(AckFactory.class); - AckReader ackReader = new AckReader(ackFactory); + AckReader ackReader = new AckReader(new BatchIdReader(), ackFactory); final Ack ack = context.mock(Ack.class); context.checking(new Expectations() {{ oneOf(ackFactory).createAck(with(any(Collection.class))); @@ -79,7 +79,7 @@ public class AckReaderTest extends TestCase { @Test public void testEmptyAck() throws Exception { final AckFactory ackFactory = context.mock(AckFactory.class); - AckReader ackReader = new AckReader(ackFactory); + AckReader ackReader = new AckReader(new BatchIdReader(), ackFactory); final Ack ack = context.mock(Ack.class); context.checking(new Expectations() {{ oneOf(ackFactory).createAck( diff --git a/test/net/sf/briar/protocol/FileReadWriteTest.java b/test/net/sf/briar/protocol/FileReadWriteTest.java index f355d01e37..27a180459d 100644 --- a/test/net/sf/briar/protocol/FileReadWriteTest.java +++ b/test/net/sf/briar/protocol/FileReadWriteTest.java @@ -1,5 +1,6 @@ package net.sf.briar.protocol; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -16,22 +17,31 @@ import net.sf.briar.api.crypto.KeyParser; 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.MessageEncoder; import net.sf.briar.api.protocol.MessageId; +import net.sf.briar.api.protocol.Subscriptions; import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.protocol.Transports; import net.sf.briar.api.protocol.UniqueId; import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.PacketWriterFactory; +import net.sf.briar.api.protocol.writers.SubscriptionWriter; +import net.sf.briar.api.protocol.writers.TransportWriter; +import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; import net.sf.briar.api.serial.ReaderFactory; +import net.sf.briar.api.serial.Writer; import net.sf.briar.api.serial.WriterFactory; import net.sf.briar.crypto.CryptoModule; import net.sf.briar.protocol.writers.WritersModule; import net.sf.briar.serial.SerialModule; +import org.apache.commons.io.output.ByteArrayOutputStream; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -48,6 +58,7 @@ public class FileReadWriteTest extends TestCase { private final GroupId sub = new GroupId(TestUtils.getRandomId()); private final String nick = "Foo Bar"; private final String messageBody = "This is the message body! Wooooooo!"; + private final long start = System.currentTimeMillis(); private final ReaderFactory readerFactory; private final WriterFactory writerFactory; @@ -56,11 +67,13 @@ public class FileReadWriteTest extends TestCase { private final MessageDigest messageDigest, batchDigest; private final KeyParser keyParser; private final Message message; + private final Group group; public FileReadWriteTest() throws Exception { super(); - Injector i = Guice.createInjector(new SerialModule(), - new CryptoModule(), new WritersModule()); + Injector i = Guice.createInjector(new CryptoModule(), + new ProtocolModule(), new SerialModule(), + new WritersModule()); readerFactory = i.getInstance(ReaderFactory.class); writerFactory = i.getInstance(WriterFactory.class); packetWriterFactory = i.getInstance(PacketWriterFactory.class); @@ -71,11 +84,23 @@ public class FileReadWriteTest extends TestCase { assertEquals(messageDigest.getDigestLength(), UniqueId.LENGTH); assertEquals(batchDigest.getDigestLength(), UniqueId.LENGTH); // Create and encode a test message - MessageEncoder messageEncoder = new MessageEncoderImpl(signature, - messageDigest, writerFactory); + MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); KeyPair keyPair = i.getInstance(KeyPair.class); message = messageEncoder.encodeMessage(MessageId.NONE, sub, nick, keyPair, messageBody.getBytes("UTF-8")); + // Create a test group, then write and read it to calculate its ID + GroupFactory groupFactory = i.getInstance(GroupFactory.class); + Group noId = groupFactory.createGroup( + new GroupId(new byte[UniqueId.LENGTH]), "Group name", false, + TestUtils.getRandomId()); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + Writer w = writerFactory.createWriter(out); + noId.writeTo(w); + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + Reader r = readerFactory.createReader(in); + ObjectReader<Group> groupReader = new GroupReader(batchDigest, + groupFactory); + group = groupReader.readObject(r); } @Before @@ -88,13 +113,20 @@ public class FileReadWriteTest extends TestCase { FileOutputStream out = new FileOutputStream(file); AckWriter a = packetWriterFactory.createAckWriter(out); - a.addBatchId(ack); + assertTrue(a.writeBatchId(ack)); a.finish(); BatchWriter b = packetWriterFactory.createBatchWriter(out); - b.addMessage(message.getBytes()); + assertTrue(b.writeMessage(message.getBytes())); b.finish(); + SubscriptionWriter s = + packetWriterFactory.createSubscriptionWriter(out); + s.writeSubscriptions(Collections.singleton(group)); + + TransportWriter t = packetWriterFactory.createTransportWriter(out); + t.writeTransports(Collections.singletonMap("foo", "bar")); + out.close(); assertTrue(file.exists()); assertTrue(file.length() > message.getSize()); @@ -107,18 +139,30 @@ public class FileReadWriteTest extends TestCase { MessageReader messageReader = new MessageReader(keyParser, signature, messageDigest); - AckReader ackReader = new AckReader(new AckFactoryImpl()); - BatchReader batchReader = new BatchReader(batchDigest, messageReader, - new BatchFactoryImpl()); + ObjectReader<Ack> ackReader = new AckReader(new BatchIdReader(), + new AckFactoryImpl()); + ObjectReader<Batch> batchReader = new BatchReader(batchDigest, + messageReader, new BatchFactoryImpl()); + ObjectReader<Group> groupReader = new GroupReader(batchDigest, + new GroupFactoryImpl(keyParser)); + ObjectReader<Subscriptions> subscriptionReader = + new SubscriptionReader(groupReader, new SubscriptionFactoryImpl()); + ObjectReader<Transports> transportReader = + new TransportReader(new TransportFactoryImpl()); + FileInputStream in = new FileInputStream(file); Reader reader = readerFactory.createReader(in); reader.addObjectReader(Tags.ACK, ackReader); reader.addObjectReader(Tags.BATCH, batchReader); + reader.addObjectReader(Tags.SUBSCRIPTIONS, subscriptionReader); + reader.addObjectReader(Tags.TRANSPORTS, transportReader); + // Read the ack assertTrue(reader.hasUserDefined(Tags.ACK)); Ack a = reader.readUserDefined(Tags.ACK, Ack.class); assertEquals(Collections.singletonList(ack), a.getBatches()); + // Read the batch assertTrue(reader.hasUserDefined(Tags.BATCH)); Batch b = reader.readUserDefined(Tags.BATCH, Batch.class); Iterator<Message> i = b.getMessages().iterator(); @@ -132,6 +176,22 @@ public class FileReadWriteTest extends TestCase { assertTrue(Arrays.equals(message.getBytes(), m.getBytes())); assertFalse(i.hasNext()); + // Read the subscriptions update + assertTrue(reader.hasUserDefined(Tags.SUBSCRIPTIONS)); + Subscriptions s = reader.readUserDefined(Tags.SUBSCRIPTIONS, + Subscriptions.class); + assertEquals(Collections.singletonList(group), s.getSubscriptions()); + assertTrue(s.getTimestamp() > start); + assertTrue(s.getTimestamp() <= System.currentTimeMillis()); + + // Read the transports update + assertTrue(reader.hasUserDefined(Tags.TRANSPORTS)); + Transports t = reader.readUserDefined(Tags.TRANSPORTS, + Transports.class); + assertEquals(Collections.singletonMap("foo", "bar"), t.getTransports()); + assertTrue(t.getTimestamp() > start); + assertTrue(t.getTimestamp() <= System.currentTimeMillis()); + assertTrue(reader.eof()); } -- GitLab