diff --git a/api/net/sf/briar/api/protocol/Offer.java b/api/net/sf/briar/api/protocol/Offer.java index e62f05d56aac13afa2bcf3863f6340f665d8512f..fbeda85080afe92ed2667dcd94cc89da3d208fea 100644 --- a/api/net/sf/briar/api/protocol/Offer.java +++ b/api/net/sf/briar/api/protocol/Offer.java @@ -11,6 +11,9 @@ public interface Offer { */ static final int MAX_SIZE = (1024 * 1024) - 100; + /** Returns the offer's unique identifier. */ + OfferId getId(); + /** Returns the message IDs contained in the offer. */ Collection<MessageId> getMessageIds(); } diff --git a/api/net/sf/briar/api/protocol/OfferId.java b/api/net/sf/briar/api/protocol/OfferId.java new file mode 100644 index 0000000000000000000000000000000000000000..1d235cfe71815f2d49c53b4e59d0cf54ca2866c7 --- /dev/null +++ b/api/net/sf/briar/api/protocol/OfferId.java @@ -0,0 +1,26 @@ +package net.sf.briar.api.protocol; + +import java.io.IOException; +import java.util.Arrays; + +import net.sf.briar.api.serial.Writer; + +/** Type-safe wrapper for a byte array that uniquely identifies an offer. */ +public class OfferId extends UniqueId { + + public OfferId(byte[] id) { + super(id); + } + + public void writeTo(Writer w) throws IOException { + w.writeUserDefinedTag(Tags.OFFER_ID); + w.writeBytes(id); + } + + @Override + public boolean equals(Object o) { + if(o instanceof OfferId) + return Arrays.equals(id, ((OfferId) o).id); + return false; + } +} diff --git a/api/net/sf/briar/api/protocol/Request.java b/api/net/sf/briar/api/protocol/Request.java index ea3f461f3f01180739904fd438c13edf1feb4a0f..bc21df77ccb26b1b87e6ea68db54e042e67655cc 100644 --- a/api/net/sf/briar/api/protocol/Request.java +++ b/api/net/sf/briar/api/protocol/Request.java @@ -11,6 +11,12 @@ public interface Request { */ static final int MAX_SIZE = (1024 * 1024) - 100; + /** + * Returns the unique identifier of the offer to which this request + * responds. + */ + OfferId getOfferId(); + /** * Returns a sequence of bits corresponding to the sequence of messages in * the offer, where the i^th bit is set if the i^th message should be sent. diff --git a/api/net/sf/briar/api/protocol/Tags.java b/api/net/sf/briar/api/protocol/Tags.java index 3b0071d4cae947cc6d5c4a486ac6f8f12cbd30eb..101b1e6577017ecb940230243c266cc99edc5feb 100644 --- a/api/net/sf/briar/api/protocol/Tags.java +++ b/api/net/sf/briar/api/protocol/Tags.java @@ -17,7 +17,8 @@ public interface Tags { static final int MESSAGE = 7; static final int MESSAGE_ID = 8; static final int OFFER = 9; - static final int REQUEST = 10; - static final int SUBSCRIPTIONS = 11; - static final int TRANSPORTS = 12; + static final int OFFER_ID = 10; + static final int REQUEST = 11; + static final int SUBSCRIPTIONS = 12; + static final int TRANSPORTS = 13; } diff --git a/api/net/sf/briar/api/protocol/writers/OfferWriter.java b/api/net/sf/briar/api/protocol/writers/OfferWriter.java index 5ad5ddd2e5195c6f5a6d4dbfc335d3d045b5a94f..6f89b3b87fe9304608f4e8677c05a0847190334b 100644 --- a/api/net/sf/briar/api/protocol/writers/OfferWriter.java +++ b/api/net/sf/briar/api/protocol/writers/OfferWriter.java @@ -3,6 +3,7 @@ package net.sf.briar.api.protocol.writers; import java.io.IOException; import net.sf.briar.api.protocol.MessageId; +import net.sf.briar.api.protocol.OfferId; /** An interface for creating a have notification. */ public interface OfferWriter { @@ -13,6 +14,6 @@ public interface OfferWriter { */ boolean writeMessageId(MessageId m) throws IOException; - /** Finishes writing the offer. */ - void finish() throws IOException; + /** Finishes writing the offer and returns its unique identifier. */ + OfferId finish() throws IOException; } diff --git a/api/net/sf/briar/api/protocol/writers/RequestWriter.java b/api/net/sf/briar/api/protocol/writers/RequestWriter.java index 335753f6c2ddcf2f7b4625e3deb427c99a3dbc4d..d284f5c0c17e521fd67fe08b90bf6f5a9c8906d2 100644 --- a/api/net/sf/briar/api/protocol/writers/RequestWriter.java +++ b/api/net/sf/briar/api/protocol/writers/RequestWriter.java @@ -3,9 +3,11 @@ package net.sf.briar.api.protocol.writers; import java.io.IOException; import java.util.BitSet; +import net.sf.briar.api.protocol.OfferId; + /** An interface for creating a request packet. */ public interface RequestWriter { /** Writes the contents of the request. */ - void writeBitmap(BitSet b, int length) throws IOException; + void writeRequest(OfferId offerId, BitSet b, int length) throws IOException; } diff --git a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java index 2eb0dde3880619bcb066010efcd5221276545db7..eb8e93375e0425c26e2fa318685f3a8b09c736be 100644 --- a/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java +++ b/components/net/sf/briar/db/ReadWriteLockDatabaseComponent.java @@ -815,7 +815,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { db.abortTransaction(txn); throw e; } - r.writeBitmap(request, offered.size()); + r.writeRequest(o.getId(), request, offered.size()); } finally { subscriptionLock.readLock().unlock(); } diff --git a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java index d99f65f4ed7fc4d616ad3eaf3a4cdcc2aaf5a7f9..466efead756b2c75674443ed1fe9316cf4cdef00 100644 --- a/components/net/sf/briar/db/SynchronizedDatabaseComponent.java +++ b/components/net/sf/briar/db/SynchronizedDatabaseComponent.java @@ -627,7 +627,7 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { db.abortTransaction(txn); throw e; } - r.writeBitmap(request, offered.size()); + r.writeRequest(o.getId(), request, offered.size()); } } } diff --git a/components/net/sf/briar/protocol/AckReader.java b/components/net/sf/briar/protocol/AckReader.java index 77ba91d23d1212333d4c5380c2792de84e241631..96c74d70db08fd6d1b5d5ece38ea575d7f47eb90 100644 --- a/components/net/sf/briar/protocol/AckReader.java +++ b/components/net/sf/briar/protocol/AckReader.java @@ -10,14 +10,11 @@ import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class AckReader implements ObjectReader<Ack> { private final ObjectReader<BatchId> batchIdReader; private final AckFactory ackFactory; - @Inject AckReader(ObjectReader<BatchId> batchIdReader, AckFactory ackFactory) { this.batchIdReader = batchIdReader; this.ackFactory = ackFactory; diff --git a/components/net/sf/briar/protocol/AuthorReader.java b/components/net/sf/briar/protocol/AuthorReader.java index e0d73ed3ba2d0b91a3e32d99f991f950cbe193cf..4ce4cc8e405dd2bbd24516ce81f4fd5d83fc197b 100644 --- a/components/net/sf/briar/protocol/AuthorReader.java +++ b/components/net/sf/briar/protocol/AuthorReader.java @@ -11,14 +11,11 @@ import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class AuthorReader implements ObjectReader<Author> { private final MessageDigest messageDigest; private final AuthorFactory authorFactory; - @Inject AuthorReader(CryptoComponent crypto, AuthorFactory authorFactory) { messageDigest = crypto.getMessageDigest(); this.authorFactory = authorFactory; diff --git a/components/net/sf/briar/protocol/BatchReader.java b/components/net/sf/briar/protocol/BatchReader.java index 15ccb655cd310cd41be88130a5459f90727ca49d..bc41e694e8e7284ded8d25661a53c1e1cfa4b002 100644 --- a/components/net/sf/briar/protocol/BatchReader.java +++ b/components/net/sf/briar/protocol/BatchReader.java @@ -13,15 +13,12 @@ import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class BatchReader implements ObjectReader<Batch> { private final MessageDigest messageDigest; private final ObjectReader<Message> messageReader; private final BatchFactory batchFactory; - @Inject BatchReader(CryptoComponent crypto, ObjectReader<Message> messageReader, BatchFactory batchFactory) { messageDigest = crypto.getMessageDigest(); diff --git a/components/net/sf/briar/protocol/GroupReader.java b/components/net/sf/briar/protocol/GroupReader.java index dd61419a0347e0c4d8884f3d73b5706379a6ab46..d855850dd437ee345ba6012e9e3711647b5d9eaf 100644 --- a/components/net/sf/briar/protocol/GroupReader.java +++ b/components/net/sf/briar/protocol/GroupReader.java @@ -11,14 +11,11 @@ import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class GroupReader implements ObjectReader<Group> { private final MessageDigest messageDigest; private final GroupFactory groupFactory; - @Inject GroupReader(CryptoComponent crypto, GroupFactory groupFactory) { messageDigest = crypto.getMessageDigest(); this.groupFactory = groupFactory; diff --git a/components/net/sf/briar/protocol/MessageReader.java b/components/net/sf/briar/protocol/MessageReader.java index 96b6824c5d2cc21473375411ece6b9d747e007c1..5319c11710b781d641950ad5592e142df07038f7 100644 --- a/components/net/sf/briar/protocol/MessageReader.java +++ b/components/net/sf/briar/protocol/MessageReader.java @@ -18,8 +18,6 @@ import net.sf.briar.api.serial.FormatException; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class MessageReader implements ObjectReader<Message> { private final ObjectReader<MessageId> messageIdReader; @@ -29,7 +27,6 @@ class MessageReader implements ObjectReader<Message> { private final Signature signature; private final MessageDigest messageDigest; - @Inject MessageReader(CryptoComponent crypto, ObjectReader<MessageId> messageIdReader, ObjectReader<Group> groupReader, diff --git a/components/net/sf/briar/protocol/OfferFactory.java b/components/net/sf/briar/protocol/OfferFactory.java index 6f19d4e29192edd0eadd298b67d398f050391337..c9a1c33cc790be75f19dc6cf93a607dc18196762 100644 --- a/components/net/sf/briar/protocol/OfferFactory.java +++ b/components/net/sf/briar/protocol/OfferFactory.java @@ -4,8 +4,9 @@ import java.util.Collection; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; interface OfferFactory { - Offer createOffer(Collection<MessageId> offered); + Offer createOffer(OfferId id, Collection<MessageId> offered); } diff --git a/components/net/sf/briar/protocol/OfferFactoryImpl.java b/components/net/sf/briar/protocol/OfferFactoryImpl.java index 075527d14768faa86d022cfe308f8f7eda203b4b..f76802c2053216a7fb36830afd499dab595b5071 100644 --- a/components/net/sf/briar/protocol/OfferFactoryImpl.java +++ b/components/net/sf/briar/protocol/OfferFactoryImpl.java @@ -4,10 +4,11 @@ import java.util.Collection; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; class OfferFactoryImpl implements OfferFactory { - public Offer createOffer(Collection<MessageId> offered) { - return new OfferImpl(offered); + public Offer createOffer(OfferId id, Collection<MessageId> offered) { + return new OfferImpl(id, offered); } } diff --git a/components/net/sf/briar/protocol/OfferIdReader.java b/components/net/sf/briar/protocol/OfferIdReader.java new file mode 100644 index 0000000000000000000000000000000000000000..52485760cfbb327948b0a6057ed824b15f6f1054 --- /dev/null +++ b/components/net/sf/briar/protocol/OfferIdReader.java @@ -0,0 +1,20 @@ +package net.sf.briar.protocol; + +import java.io.IOException; + +import net.sf.briar.api.protocol.OfferId; +import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.protocol.UniqueId; +import net.sf.briar.api.serial.FormatException; +import net.sf.briar.api.serial.ObjectReader; +import net.sf.briar.api.serial.Reader; + +class OfferIdReader implements ObjectReader<OfferId> { + + public OfferId readObject(Reader r) throws IOException { + r.readUserDefinedTag(Tags.OFFER_ID); + byte[] b = r.readBytes(UniqueId.LENGTH); + if(b.length != UniqueId.LENGTH) throw new FormatException(); + return new OfferId(b); + } +} diff --git a/components/net/sf/briar/protocol/OfferImpl.java b/components/net/sf/briar/protocol/OfferImpl.java index de892202e64c2fc1fe435767993734920aeda5cf..0ce2e6bfe943e60c55e0e8e95739b1e82557c84b 100644 --- a/components/net/sf/briar/protocol/OfferImpl.java +++ b/components/net/sf/briar/protocol/OfferImpl.java @@ -4,15 +4,22 @@ import java.util.Collection; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; class OfferImpl implements Offer { + private final OfferId id; private final Collection<MessageId> offered; - OfferImpl(Collection<MessageId> offered) { + OfferImpl(OfferId id, Collection<MessageId> offered) { + this.id = id; this.offered = offered; } + public OfferId getId() { + return id; + } + public Collection<MessageId> getMessageIds() { return offered; } diff --git a/components/net/sf/briar/protocol/OfferReader.java b/components/net/sf/briar/protocol/OfferReader.java index 459310dec1f056b9521266603794a390990c6b83..e269e865a6048bc768cc8a2a15c9277ab0add702 100644 --- a/components/net/sf/briar/protocol/OfferReader.java +++ b/components/net/sf/briar/protocol/OfferReader.java @@ -1,40 +1,47 @@ package net.sf.briar.protocol; import java.io.IOException; +import java.security.MessageDigest; import java.util.Collection; +import net.sf.briar.api.crypto.CryptoComponent; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class OfferReader implements ObjectReader<Offer> { + private final MessageDigest messageDigest; private final ObjectReader<MessageId> messageIdReader; private final OfferFactory offerFactory; - @Inject - OfferReader(ObjectReader<MessageId> messageIdReader, + OfferReader(CryptoComponent crypto, ObjectReader<MessageId> messageIdReader, OfferFactory offerFactory) { + messageDigest = crypto.getMessageDigest(); this.messageIdReader = messageIdReader; this.offerFactory = offerFactory; } public Offer readObject(Reader r) throws IOException { - // Initialise the consumer + // Initialise the consumers Consumer counting = new CountingConsumer(Offer.MAX_SIZE); + DigestingConsumer digesting = new DigestingConsumer(messageDigest); + messageDigest.reset(); // Read the data r.addConsumer(counting); + r.addConsumer(digesting); r.readUserDefinedTag(Tags.OFFER); r.addObjectReader(Tags.MESSAGE_ID, messageIdReader); Collection<MessageId> messages = r.readList(MessageId.class); r.removeObjectReader(Tags.MESSAGE_ID); + r.removeConsumer(digesting); r.removeConsumer(counting); // Build and return the offer - return offerFactory.createOffer(messages); + OfferId id = new OfferId(messageDigest.digest()); + return offerFactory.createOffer(id, messages); } } diff --git a/components/net/sf/briar/protocol/ProtocolModule.java b/components/net/sf/briar/protocol/ProtocolModule.java index 6d36d8efb38cc18522aa7a1f9d5a7f83dcb95c53..79d4bac5867c3dae02210951d8c2b7194e535492 100644 --- a/components/net/sf/briar/protocol/ProtocolModule.java +++ b/components/net/sf/briar/protocol/ProtocolModule.java @@ -12,6 +12,7 @@ import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageEncoder; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.SubscriptionUpdate; @@ -81,14 +82,21 @@ public class ProtocolModule extends AbstractModule { } @Provides - ObjectReader<Offer> getOfferReader(ObjectReader<MessageId> messageIdReader, + ObjectReader<OfferId> getOfferIdReader() { + return new OfferIdReader(); + } + + @Provides + ObjectReader<Offer> getOfferReader(CryptoComponent crypto, + ObjectReader<MessageId> messageIdReader, OfferFactory offerFactory) { - return new OfferReader(messageIdReader, offerFactory); + return new OfferReader(crypto, messageIdReader, offerFactory); } @Provides - ObjectReader<Request> getRequestReader(RequestFactory requestFactory) { - return new RequestReader(requestFactory); + ObjectReader<Request> getRequestReader(ObjectReader<OfferId> offerIdReader, + RequestFactory requestFactory) { + return new RequestReader(offerIdReader, requestFactory); } @Provides diff --git a/components/net/sf/briar/protocol/RequestFactory.java b/components/net/sf/briar/protocol/RequestFactory.java index 005982b826a5c32ae72efceb1fe563d24d6406ec..09459765a69e7c3a9eaa7ee57944ef6e865c5df7 100644 --- a/components/net/sf/briar/protocol/RequestFactory.java +++ b/components/net/sf/briar/protocol/RequestFactory.java @@ -2,9 +2,10 @@ package net.sf.briar.protocol; import java.util.BitSet; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Request; interface RequestFactory { - Request createRequest(BitSet requested); + Request createRequest(OfferId offerId, BitSet requested); } diff --git a/components/net/sf/briar/protocol/RequestFactoryImpl.java b/components/net/sf/briar/protocol/RequestFactoryImpl.java index 0c2c77cb1cd324c4f292adeba8da1125dfbd21f2..68cce91c54c76c5a595490d3a09f4337cfbd6bd4 100644 --- a/components/net/sf/briar/protocol/RequestFactoryImpl.java +++ b/components/net/sf/briar/protocol/RequestFactoryImpl.java @@ -2,11 +2,12 @@ package net.sf.briar.protocol; import java.util.BitSet; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Request; class RequestFactoryImpl implements RequestFactory { - public Request createRequest(BitSet requested) { - return new RequestImpl(requested); + public Request createRequest(OfferId offerId, BitSet requested) { + return new RequestImpl(offerId, requested); } } diff --git a/components/net/sf/briar/protocol/RequestImpl.java b/components/net/sf/briar/protocol/RequestImpl.java index ddb31898aeb2f4f02ae581ce889eaebf22894d09..42d3247ee94965b0eb7bac502198322831436575 100644 --- a/components/net/sf/briar/protocol/RequestImpl.java +++ b/components/net/sf/briar/protocol/RequestImpl.java @@ -2,16 +2,23 @@ package net.sf.briar.protocol; import java.util.BitSet; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Request; class RequestImpl implements Request { + private final OfferId offerId; private final BitSet requested; - RequestImpl(BitSet requested) { + RequestImpl(OfferId offerId, BitSet requested) { + this.offerId = offerId; this.requested = requested; } + public OfferId getOfferId() { + return offerId; + } + public BitSet getBitmap() { return requested; } diff --git a/components/net/sf/briar/protocol/RequestReader.java b/components/net/sf/briar/protocol/RequestReader.java index 567779007613ce62d383f52e009f43239574d3ab..901a557564f04c107510c9d875bbb368ac0e02a0 100644 --- a/components/net/sf/briar/protocol/RequestReader.java +++ b/components/net/sf/briar/protocol/RequestReader.java @@ -3,20 +3,21 @@ package net.sf.briar.protocol; import java.io.IOException; import java.util.BitSet; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class RequestReader implements ObjectReader<Request> { + private final ObjectReader<OfferId> offerIdReader; private final RequestFactory requestFactory; - @Inject - RequestReader(RequestFactory requestFactory) { + RequestReader(ObjectReader<OfferId> offerIdReader, + RequestFactory requestFactory) { + this.offerIdReader = offerIdReader; this.requestFactory = requestFactory; } @@ -26,6 +27,8 @@ class RequestReader implements ObjectReader<Request> { // Read the data r.addConsumer(counting); r.readUserDefinedTag(Tags.REQUEST); + r.addObjectReader(Tags.OFFER_ID, offerIdReader); + OfferId offerId = r.readUserDefined(Tags.OFFER_ID, OfferId.class); byte[] bitmap = r.readBytes(Request.MAX_SIZE); r.removeConsumer(counting); // Convert the bitmap into a BitSet @@ -36,6 +39,6 @@ class RequestReader implements ObjectReader<Request> { if((bitmap[i] & bit) != 0) b.set(i * 8 + j); } } - return requestFactory.createRequest(b); + return requestFactory.createRequest(offerId, b); } } diff --git a/components/net/sf/briar/protocol/SubscriptionReader.java b/components/net/sf/briar/protocol/SubscriptionReader.java index 6c31dad6fb663c1dab24ef81c9d347e8e16dc28d..8faaf647e1b9283f7f2f791575e26f51a0295c45 100644 --- a/components/net/sf/briar/protocol/SubscriptionReader.java +++ b/components/net/sf/briar/protocol/SubscriptionReader.java @@ -10,14 +10,11 @@ import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class SubscriptionReader implements ObjectReader<SubscriptionUpdate> { private final ObjectReader<Group> groupReader; private final SubscriptionFactory subscriptionFactory; - @Inject SubscriptionReader(ObjectReader<Group> groupReader, SubscriptionFactory subscriptionFactory) { this.groupReader = groupReader; diff --git a/components/net/sf/briar/protocol/TransportReader.java b/components/net/sf/briar/protocol/TransportReader.java index 92a2a479050265a53a98928d7af46d58dc42f459..2ea5e61b3bc548e8615af0ad3ae9a23d186c9986 100644 --- a/components/net/sf/briar/protocol/TransportReader.java +++ b/components/net/sf/briar/protocol/TransportReader.java @@ -10,13 +10,10 @@ import net.sf.briar.api.serial.Consumer; import net.sf.briar.api.serial.ObjectReader; import net.sf.briar.api.serial.Reader; -import com.google.inject.Inject; - class TransportReader implements ObjectReader<TransportUpdate> { private final TransportFactory transportFactory; - @Inject TransportReader(TransportFactory transportFactory) { this.transportFactory = transportFactory; } diff --git a/components/net/sf/briar/protocol/writers/OfferWriterImpl.java b/components/net/sf/briar/protocol/writers/OfferWriterImpl.java index c0ec46fe94dbd01d5c6f43845fc5fbe35f5ee761..7bbac598dfa6f1135954a7d54aa4f7bb9a948160 100644 --- a/components/net/sf/briar/protocol/writers/OfferWriterImpl.java +++ b/components/net/sf/briar/protocol/writers/OfferWriterImpl.java @@ -2,9 +2,12 @@ package net.sf.briar.protocol.writers; import java.io.IOException; import java.io.OutputStream; +import java.security.DigestOutputStream; +import java.security.MessageDigest; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.protocol.writers.OfferWriter; import net.sf.briar.api.serial.Writer; @@ -14,17 +17,20 @@ class OfferWriterImpl implements OfferWriter { private final OutputStream out; private final Writer w; + private final MessageDigest messageDigest; - private boolean started = false, finished = false; + private boolean started = false; - OfferWriterImpl(OutputStream out, WriterFactory writerFactory) { - this.out = out; + OfferWriterImpl(OutputStream out, WriterFactory writerFactory, + MessageDigest messageDigest) { + this.out = new DigestOutputStream(out, messageDigest); w = writerFactory.createWriter(out); + this.messageDigest = messageDigest; } public boolean writeMessageId(MessageId m) throws IOException { - if(finished) throw new IllegalStateException(); if(!started) { + messageDigest.reset(); w.writeUserDefinedTag(Tags.OFFER); w.writeListStart(); started = true; @@ -35,15 +41,16 @@ class OfferWriterImpl implements OfferWriter { return true; } - public void finish() throws IOException { - if(finished) throw new IllegalStateException(); + public OfferId finish() throws IOException { if(!started) { + messageDigest.reset(); w.writeUserDefinedTag(Tags.OFFER); w.writeListStart(); started = true; } w.writeListEnd(); out.flush(); - finished = true; + started = false; + return new OfferId(messageDigest.digest()); } } diff --git a/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java b/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java index 25999403679a4406a1246f38cb61ebd77d4035c9..ce14908f1caee20b48565609407d37cf2af20950 100644 --- a/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java +++ b/components/net/sf/briar/protocol/writers/ProtocolWriterFactoryImpl.java @@ -36,7 +36,7 @@ class ProtocolWriterFactoryImpl implements ProtocolWriterFactory { } public OfferWriter createOfferWriter(OutputStream out) { - return new OfferWriterImpl(out, writerFactory); + return new OfferWriterImpl(out, writerFactory, messageDigest); } public RequestWriter createRequestWriter(OutputStream out) { diff --git a/components/net/sf/briar/protocol/writers/RequestWriterImpl.java b/components/net/sf/briar/protocol/writers/RequestWriterImpl.java index 28bce226a28ac08e43d0eac325d98deffe3a613d..d50909dabb849489df723087de4f26a77a5f2813 100644 --- a/components/net/sf/briar/protocol/writers/RequestWriterImpl.java +++ b/components/net/sf/briar/protocol/writers/RequestWriterImpl.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.OutputStream; import java.util.BitSet; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Tags; import net.sf.briar.api.protocol.writers.RequestWriter; import net.sf.briar.api.serial.Writer; @@ -19,8 +20,11 @@ class RequestWriterImpl implements RequestWriter { w = writerFactory.createWriter(out); } - public void writeBitmap(BitSet b, int length) throws IOException { + public void writeRequest(OfferId offerId, BitSet b, int length) + throws IOException { w.writeUserDefinedTag(Tags.REQUEST); + w.writeUserDefinedTag(Tags.OFFER_ID); + w.writeBytes(offerId.getBytes()); // If the number of bits isn't a multiple of 8, round up to a byte int bytes = length % 8 == 0 ? length / 8 : length / 8 + 1; byte[] bitmap = new byte[bytes]; diff --git a/test/net/sf/briar/FileReadWriteTest.java b/test/net/sf/briar/FileReadWriteTest.java index 490c0d08b0c93680d030254b80c2186324725708..4988507957df41291d9977927d801662c90d2488 100644 --- a/test/net/sf/briar/FileReadWriteTest.java +++ b/test/net/sf/briar/FileReadWriteTest.java @@ -27,6 +27,7 @@ import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageEncoder; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.ProtocolReader; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.Request; @@ -78,6 +79,7 @@ public class FileReadWriteTest extends TestCase { private final Message message, message1, message2, message3; private final String authorName = "Alice"; private final String messageBody = "Hello world"; + private final OfferId offerId; private final Map<String, Map<String, String>> transports; public FileReadWriteTest() throws Exception { @@ -114,6 +116,7 @@ public class FileReadWriteTest extends TestCase { message3 = messageEncoder.encodeMessage(MessageId.NONE, group1, groupKeyPair.getPrivate(), author, authorKeyPair.getPrivate(), messageBody.getBytes("UTF-8")); + offerId = new OfferId(TestUtils.getRandomId()); transports = Collections.singletonMap("foo", Collections.singletonMap("bar", "baz")); } @@ -155,7 +158,7 @@ public class FileReadWriteTest extends TestCase { BitSet requested = new BitSet(4); requested.set(1); requested.set(3); - r.writeBitmap(requested, 4); + r.writeRequest(offerId, requested, 4); packetWriter.finishPacket(); SubscriptionWriter s = @@ -231,6 +234,7 @@ public class FileReadWriteTest extends TestCase { assertTrue(protocolReader.hasRequest()); Request r = protocolReader.readRequest(); packetReader.finishPacket(); + assertEquals(offerId, r.getOfferId()); BitSet requested = r.getBitmap(); assertFalse(requested.get(0)); assertTrue(requested.get(1)); diff --git a/test/net/sf/briar/db/DatabaseCleanerImplTest.java b/test/net/sf/briar/db/DatabaseCleanerImplTest.java index 691574da04a4f598616c3ae9a61ee5968fe55c66..1042338aea4e5afb3cac0dbbfcf5d934545f8b76 100644 --- a/test/net/sf/briar/db/DatabaseCleanerImplTest.java +++ b/test/net/sf/briar/db/DatabaseCleanerImplTest.java @@ -12,7 +12,7 @@ import org.junit.Test; public class DatabaseCleanerImplTest extends TestCase { @Test - public void testStoppingCleanerWakesItUp() throws DbException { + public void testStoppingCleanerWakesItUp() throws Exception { final CountDownLatch latch = new CountDownLatch(1); Callback callback = new Callback() { @@ -31,11 +31,7 @@ public class DatabaseCleanerImplTest extends TestCase { long start = System.currentTimeMillis(); // Start the cleaner and check that shouldCheckFreeSpace() is called cleaner.startCleaning(); - try { - assertTrue(latch.await(5, TimeUnit.SECONDS)); - } catch(InterruptedException e) { - fail(); - } + assertTrue(latch.await(5, TimeUnit.SECONDS)); // Stop the cleaner (it should be waiting between sweeps) cleaner.stopCleaning(); long end = System.currentTimeMillis(); diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index 193f4392ea419bddd0daee58d2db8844f09e192e..f49ce59077b5458545c7e4cd47b9b228564fcbf4 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -12,10 +12,10 @@ import net.sf.briar.api.ContactId; import net.sf.briar.api.Rating; import net.sf.briar.api.db.DatabaseComponent; import net.sf.briar.api.db.DatabaseListener; +import net.sf.briar.api.db.DatabaseListener.Event; import net.sf.briar.api.db.DbException; import net.sf.briar.api.db.NoSuchContactException; import net.sf.briar.api.db.Status; -import net.sf.briar.api.db.DatabaseListener.Event; import net.sf.briar.api.protocol.Ack; import net.sf.briar.api.protocol.AuthorId; import net.sf.briar.api.protocol.Batch; @@ -25,6 +25,7 @@ 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.OfferId; import net.sf.briar.api.protocol.SubscriptionUpdate; import net.sf.briar.api.protocol.TransportUpdate; import net.sf.briar.api.protocol.writers.AckWriter; @@ -49,6 +50,7 @@ public abstract class DatabaseComponentTest extends TestCase { protected final ContactId contactId; protected final GroupId groupId; protected final MessageId messageId, parentId; + protected final OfferId offerId; private final long timestamp; private final int size; private final byte[] raw; @@ -65,6 +67,7 @@ public abstract class DatabaseComponentTest extends TestCase { groupId = new GroupId(TestUtils.getRandomId()); messageId = new MessageId(TestUtils.getRandomId()); parentId = new MessageId(TestUtils.getRandomId()); + offerId = new OfferId(TestUtils.getRandomId()); timestamp = System.currentTimeMillis(); size = 1234; raw = new byte[size]; @@ -1031,7 +1034,9 @@ public abstract class DatabaseComponentTest extends TestCase { will(returnValue(true)); // Visible - do not request message # 1 oneOf(database).setStatusSeenIfVisible(txn, contactId, messageId2); will(returnValue(false)); // Not visible - request message # 2 - oneOf(requestWriter).writeBitmap(expectedRequest, 3); + oneOf(offer).getId(); + will(returnValue(offerId)); + oneOf(requestWriter).writeRequest(offerId, expectedRequest, 3); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); diff --git a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java index cee401bc54703235fd196a718978a87731876cc3..3757ad9f04f19b04a7fd47e8ff24ca79031f2417 100644 --- a/test/net/sf/briar/protocol/ProtocolReadWriteTest.java +++ b/test/net/sf/briar/protocol/ProtocolReadWriteTest.java @@ -17,6 +17,7 @@ import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.MessageEncoder; import net.sf.briar.api.protocol.MessageId; import net.sf.briar.api.protocol.Offer; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.ProtocolReader; import net.sf.briar.api.protocol.ProtocolReaderFactory; import net.sf.briar.api.protocol.Request; @@ -46,6 +47,7 @@ public class ProtocolReadWriteTest extends TestCase { private final Group group; private final Message message; private final String messageBody = "Hello world"; + private final OfferId offerId; private final BitSet bitSet; private final Map<Group, Long> subscriptions; private final Map<String, Map<String, String>> transports; @@ -62,6 +64,7 @@ public class ProtocolReadWriteTest extends TestCase { MessageEncoder messageEncoder = i.getInstance(MessageEncoder.class); message = messageEncoder.encodeMessage(MessageId.NONE, group, messageBody.getBytes("UTF-8")); + offerId = new OfferId(TestUtils.getRandomId()); bitSet = new BitSet(); bitSet.set(3); bitSet.set(7); @@ -90,7 +93,7 @@ public class ProtocolReadWriteTest extends TestCase { o.finish(); RequestWriter r = writerFactory.createRequestWriter(out); - r.writeBitmap(bitSet, 10); + r.writeRequest(offerId, bitSet, 10); SubscriptionWriter s = writerFactory.createSubscriptionWriter(out); s.writeSubscriptions(subscriptions); diff --git a/test/net/sf/briar/protocol/RequestReaderTest.java b/test/net/sf/briar/protocol/RequestReaderTest.java index 4ff8865903419225eeb0af96adb74b3e176beb07..b9c2be3ef866801ac3907a4cf6bdcd4491a8ccf3 100644 --- a/test/net/sf/briar/protocol/RequestReaderTest.java +++ b/test/net/sf/briar/protocol/RequestReaderTest.java @@ -5,8 +5,10 @@ import java.io.ByteArrayOutputStream; import java.util.BitSet; import junit.framework.TestCase; +import net.sf.briar.api.protocol.OfferId; import net.sf.briar.api.protocol.Request; import net.sf.briar.api.protocol.Tags; +import net.sf.briar.api.protocol.UniqueId; import net.sf.briar.api.serial.FormatException; import net.sf.briar.api.serial.Reader; import net.sf.briar.api.serial.ReaderFactory; @@ -38,7 +40,8 @@ public class RequestReaderTest extends TestCase { @Test public void testFormatExceptionIfRequestIsTooLarge() throws Exception { RequestFactory requestFactory = context.mock(RequestFactory.class); - RequestReader requestReader = new RequestReader(requestFactory); + RequestReader requestReader = + new RequestReader(new OfferIdReader(), requestFactory); byte[] b = createRequest(true); ByteArrayInputStream in = new ByteArrayInputStream(b); @@ -56,10 +59,12 @@ public class RequestReaderTest extends TestCase { public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception { final RequestFactory requestFactory = context.mock(RequestFactory.class); - RequestReader requestReader = new RequestReader(requestFactory); + RequestReader requestReader = + new RequestReader(new OfferIdReader(), requestFactory); final Request request = context.mock(Request.class); context.checking(new Expectations() {{ - oneOf(requestFactory).createRequest(with(any(BitSet.class))); + oneOf(requestFactory).createRequest(with(any(OfferId.class)), + with(any(BitSet.class))); will(returnValue(request)); }}); @@ -95,8 +100,8 @@ public class RequestReaderTest extends TestCase { // Deserialise the request ByteArrayInputStream in = new ByteArrayInputStream(b); Reader reader = readerFactory.createReader(in); - RequestReader requestReader = - new RequestReader(new RequestFactoryImpl()); + RequestReader requestReader = new RequestReader(new OfferIdReader(), + new RequestFactoryImpl()); reader.addObjectReader(Tags.REQUEST, requestReader); Request r = reader.readUserDefined(Tags.REQUEST, Request.class); BitSet decoded = r.getBitmap(); @@ -115,10 +120,15 @@ public class RequestReaderTest extends TestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); w.writeUserDefinedTag(Tags.REQUEST); - // Allow one byte for the REQUEST tag, one byte for the BYTES tag, and - // five bytes for the length as an int32 - if(tooBig) w.writeBytes(new byte[Request.MAX_SIZE - 6]); - else w.writeBytes(new byte[Request.MAX_SIZE - 7]); + w.writeUserDefinedTag(Tags.OFFER_ID); + w.writeBytes(new byte[UniqueId.LENGTH]); + // Allow one byte for the REQUEST tag, one byte for the OFFER_ID tag, + // one byte for the BYTES tag, one byte for the length as a uint7, + // UniqueID.LENGTH bytes for the offer ID, one byte for the BYTES tag, + // and five bytes for the length as an int32 + int overhead = UniqueId.LENGTH + 10; + if(tooBig) w.writeBytes(new byte[Request.MAX_SIZE - overhead + 1]); + else w.writeBytes(new byte[Request.MAX_SIZE - overhead]); assertEquals(tooBig, out.size() > Request.MAX_SIZE); return out.toByteArray(); } @@ -127,6 +137,8 @@ public class RequestReaderTest extends TestCase { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); w.writeUserDefinedTag(Tags.REQUEST); + w.writeUserDefinedTag(Tags.OFFER_ID); + w.writeBytes(new byte[UniqueId.LENGTH]); w.writeBytes(bitmap); return out.toByteArray(); } diff --git a/test/net/sf/briar/protocol/writers/RequestWriterImplTest.java b/test/net/sf/briar/protocol/writers/RequestWriterImplTest.java index b612f95bb14873d902898a81ebf568b7caea1226..e7e5d7e73f3577cc18fba3bad26003a6a3efa749 100644 --- a/test/net/sf/briar/protocol/writers/RequestWriterImplTest.java +++ b/test/net/sf/briar/protocol/writers/RequestWriterImplTest.java @@ -5,6 +5,8 @@ import java.io.IOException; import java.util.BitSet; import junit.framework.TestCase; +import net.sf.briar.api.protocol.OfferId; +import net.sf.briar.api.protocol.UniqueId; import net.sf.briar.api.protocol.writers.RequestWriter; import net.sf.briar.api.serial.WriterFactory; import net.sf.briar.serial.SerialModule; @@ -18,11 +20,13 @@ import com.google.inject.Injector; public class RequestWriterImplTest extends TestCase { private final WriterFactory writerFactory; + private final OfferId offerId; public RequestWriterImplTest() { super(); Injector i = Guice.createInjector(new SerialModule()); writerFactory = i.getInstance(WriterFactory.class); + offerId = new OfferId(new byte[UniqueId.LENGTH]); } @Test @@ -41,10 +45,14 @@ public class RequestWriterImplTest extends TestCase { b.set(11); b.set(12); b.set(15); - r.writeBitmap(b, 16); - // Short user tag 10, short bytes with length 2, 0xD959 + r.writeRequest(offerId, b, 16); + // Short user tag 11, short user tag 10, bytes with length 32 as a + // uint7, 32 zero bytes, short bytes with length 2, 0xD959 byte[] output = out.toByteArray(); - assertEquals("CA" + "92" + "D959", StringUtils.toHexString(output)); + assertEquals("CB" + "CA" + "F6" + "20" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "92" + "D959", StringUtils.toHexString(output)); } @Test @@ -62,9 +70,13 @@ public class RequestWriterImplTest extends TestCase { b.set(9); b.set(11); b.set(12); - r.writeBitmap(b, 13); - // Short user tag 10, short bytes with length 2, 0x59D8 + r.writeRequest(offerId, b, 13); + // Short user tag 11, short user tag 10, bytes with length 32 as a + // uint7, 32 zero bytes, short bytes with length 2, 0x59D8 byte[] output = out.toByteArray(); - assertEquals("CA" + "92" + "59D8", StringUtils.toHexString(output)); + assertEquals("CB" + "CA" + "F6" + "20" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "92" + "59D8", StringUtils.toHexString(output)); } }