diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/SyncConstants.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/SyncConstants.java index 5f196f147060a08fee698f2e4747c6f0609dc074..a6e3474f30453b24d06b0b4aaeeb72a96d0a89bd 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/SyncConstants.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/SyncConstants.java @@ -2,6 +2,8 @@ package org.briarproject.bramble.api.sync; import org.briarproject.bramble.api.UniqueId; +import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; + public interface SyncConstants { /** @@ -9,16 +11,6 @@ public interface SyncConstants { */ byte PROTOCOL_VERSION = 0; - /** - * The length of the record header in bytes. - */ - int RECORD_HEADER_LENGTH = 4; - - /** - * The maximum length of the record payload in bytes. - */ - int MAX_RECORD_PAYLOAD_LENGTH = 48 * 1024; // 48 KiB - /** * The maximum length of a group descriptor in bytes. */ @@ -42,5 +34,5 @@ public interface SyncConstants { /** * The maximum number of message IDs in an ack, offer or request record. */ - int MAX_MESSAGE_IDS = MAX_RECORD_PAYLOAD_LENGTH / UniqueId.LENGTH; + int MAX_MESSAGE_IDS = MAX_RECORD_PAYLOAD_BYTES / UniqueId.LENGTH; } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java index 8831ae4719c7ccc3da6a1758b852178662fb52cb..c2b54f5a9722fe2e8378f0421df6f45e16a7a805 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/DuplexOutgoingSession.java @@ -39,8 +39,8 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING; +import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS; -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH; /** * An outgoing {@link SyncSession} suitable for duplex transports. The session @@ -273,7 +273,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener { Transaction txn = db.startTransaction(false); try { b = db.generateRequestedBatch(txn, contactId, - MAX_RECORD_PAYLOAD_LENGTH, maxLatency); + MAX_RECORD_PAYLOAD_BYTES, maxLatency); setNextSendTime(db.getNextSendTime(txn, contactId)); db.commitTransaction(txn); } finally { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java index 7f92045fcbbf6984308bc0246ddd529e79d26827..8e8151079fcbd3f3a71c4ca3efd5090708ab1d67 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/MessageFactoryImpl.java @@ -16,6 +16,7 @@ import static org.briarproject.bramble.api.sync.Message.FORMAT_VERSION; import static org.briarproject.bramble.api.sync.MessageId.BLOCK_LABEL; import static org.briarproject.bramble.api.sync.MessageId.ID_LABEL; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_BODY_LENGTH; +import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES; @@ -53,6 +54,8 @@ class MessageFactoryImpl implements MessageFactory { public Message createMessage(MessageId m, byte[] raw) { if (raw.length < MESSAGE_HEADER_LENGTH) throw new IllegalArgumentException(); + if (raw.length > MAX_MESSAGE_LENGTH) + throw new IllegalArgumentException(); byte[] groupId = new byte[UniqueId.LENGTH]; System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH); long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java index 86f8a833be9defeadebd2d2cbb05a8a2e52fcee2..b0645dc5125880882a7777cbfb188c23deb364a5 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/SimplexOutgoingSession.java @@ -29,8 +29,8 @@ import javax.annotation.concurrent.ThreadSafe; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING; +import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS; -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH; /** * An outgoing {@link SyncSession} suitable for simplex transports. The session @@ -171,7 +171,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener { Transaction txn = db.startTransaction(false); try { b = db.generateBatch(txn, contactId, - MAX_RECORD_PAYLOAD_LENGTH, maxLatency); + MAX_RECORD_PAYLOAD_BYTES, maxLatency); db.commitTransaction(txn); } finally { db.endTransaction(txn); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncModule.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncModule.java index 042103fbec0e0341197d4e66b5d881ab7c695dcb..0034289e7ddfcf73bcf6291264c8557079cceec2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncModule.java @@ -58,8 +58,9 @@ public class SyncModule { } @Provides - SyncRecordWriterFactory provideRecordWriterFactory() { - return new SyncRecordWriterFactoryImpl(); + SyncRecordWriterFactory provideRecordWriterFactory( + SyncRecordWriterFactoryImpl recordWriterFactory) { + return recordWriterFactory; } @Provides diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderFactoryImpl.java index 2c816d6fd7802e5ec5b1f512264e10a29ebb7266..7124f8810f20498c6af3273effe1707a7b1bde7e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderFactoryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderFactoryImpl.java @@ -1,6 +1,8 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.record.RecordReader; +import org.briarproject.bramble.api.record.RecordReaderFactory; import org.briarproject.bramble.api.sync.MessageFactory; import org.briarproject.bramble.api.sync.SyncRecordReader; import org.briarproject.bramble.api.sync.SyncRecordReaderFactory; @@ -15,14 +17,18 @@ import javax.inject.Inject; class SyncRecordReaderFactoryImpl implements SyncRecordReaderFactory { private final MessageFactory messageFactory; + private final RecordReaderFactory recordReaderFactory; @Inject - SyncRecordReaderFactoryImpl(MessageFactory messageFactory) { + SyncRecordReaderFactoryImpl(MessageFactory messageFactory, + RecordReaderFactory recordReaderFactory) { this.messageFactory = messageFactory; + this.recordReaderFactory = recordReaderFactory; } @Override public SyncRecordReader createRecordReader(InputStream in) { - return new SyncRecordReaderImpl(messageFactory, in); + RecordReader reader = recordReaderFactory.createRecordReader(in); + return new SyncRecordReaderImpl(messageFactory, reader); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderImpl.java index fec79b214cd3a70dc982150dc98e76d43ca96b2e..d7566979d218dd1f7c595568c60a619ce6a26685 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordReaderImpl.java @@ -3,6 +3,8 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.UniqueId; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.record.Record; +import org.briarproject.bramble.api.record.RecordReader; import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; @@ -13,72 +15,45 @@ import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.SyncRecordReader; import org.briarproject.bramble.util.ByteUtils; +import java.io.EOFException; import java.io.IOException; -import java.io.InputStream; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nullable; import javax.annotation.concurrent.NotThreadSafe; import static org.briarproject.bramble.api.sync.RecordTypes.ACK; import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE; import static org.briarproject.bramble.api.sync.RecordTypes.OFFER; import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST; -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION; -import static org.briarproject.bramble.api.sync.SyncConstants.RECORD_HEADER_LENGTH; @NotThreadSafe @NotNullByDefault class SyncRecordReaderImpl implements SyncRecordReader { - private enum State {BUFFER_EMPTY, BUFFER_FULL, EOF} - private final MessageFactory messageFactory; - private final InputStream in; - private final byte[] header, payload; + private final RecordReader reader; - private State state = State.BUFFER_EMPTY; - private int payloadLength = 0; + @Nullable + private Record nextRecord = null; + private boolean eof = false; - SyncRecordReaderImpl(MessageFactory messageFactory, InputStream in) { + SyncRecordReaderImpl(MessageFactory messageFactory, RecordReader reader) { this.messageFactory = messageFactory; - this.in = in; - header = new byte[RECORD_HEADER_LENGTH]; - payload = new byte[MAX_RECORD_PAYLOAD_LENGTH]; + this.reader = reader; } private void readRecord() throws IOException { - if (state != State.BUFFER_EMPTY) throw new IllegalStateException(); + assert nextRecord == null; while (true) { - // Read the header - int offset = 0; - while (offset < RECORD_HEADER_LENGTH) { - int read = - in.read(header, offset, RECORD_HEADER_LENGTH - offset); - if (read == -1) { - if (offset > 0) throw new FormatException(); - state = State.EOF; - return; - } - offset += read; - } - byte version = header[0], type = header[1]; - payloadLength = ByteUtils.readUint16(header, 2); + nextRecord = reader.readRecord(); // Check the protocol version + byte version = nextRecord.getProtocolVersion(); if (version != PROTOCOL_VERSION) throw new FormatException(); - // Check the payload length - if (payloadLength > MAX_RECORD_PAYLOAD_LENGTH) - throw new FormatException(); - // Read the payload - offset = 0; - while (offset < payloadLength) { - int read = in.read(payload, offset, payloadLength - offset); - if (read == -1) throw new FormatException(); - offset += read; - } - state = State.BUFFER_FULL; + byte type = nextRecord.getRecordType(); // Return if this is a known record type, otherwise continue if (type == ACK || type == MESSAGE || type == OFFER || type == REQUEST) { @@ -87,6 +62,11 @@ class SyncRecordReaderImpl implements SyncRecordReader { } } + private byte getNextRecordType() { + assert nextRecord != null; + return nextRecord.getRecordType(); + } + /** * Returns true if there's another record available or false if we've * reached the end of the input stream. @@ -97,14 +77,21 @@ class SyncRecordReaderImpl implements SyncRecordReader { */ @Override public boolean eof() throws IOException { - if (state == State.BUFFER_EMPTY) readRecord(); - if (state == State.BUFFER_EMPTY) throw new IllegalStateException(); - return state == State.EOF; + if (nextRecord != null) return false; + if (eof) return true; + try { + readRecord(); + return false; + } catch (EOFException e) { + nextRecord = null; + eof = true; + return true; + } } @Override public boolean hasAck() throws IOException { - return !eof() && header[1] == ACK; + return !eof() && getNextRecordType() == ACK; } @Override @@ -114,27 +101,31 @@ class SyncRecordReaderImpl implements SyncRecordReader { } private List<MessageId> readMessageIds() throws IOException { - if (payloadLength == 0) throw new FormatException(); - if (payloadLength % UniqueId.LENGTH != 0) throw new FormatException(); - List<MessageId> ids = new ArrayList<>(); - for (int off = 0; off < payloadLength; off += UniqueId.LENGTH) { + assert nextRecord != null; + byte[] payload = nextRecord.getPayload(); + if (payload.length == 0) throw new FormatException(); + if (payload.length % UniqueId.LENGTH != 0) throw new FormatException(); + List<MessageId> ids = new ArrayList<>(payload.length / UniqueId.LENGTH); + for (int off = 0; off < payload.length; off += UniqueId.LENGTH) { byte[] id = new byte[UniqueId.LENGTH]; System.arraycopy(payload, off, id, 0, UniqueId.LENGTH); ids.add(new MessageId(id)); } - state = State.BUFFER_EMPTY; + nextRecord = null; return ids; } @Override public boolean hasMessage() throws IOException { - return !eof() && header[1] == MESSAGE; + return !eof() && getNextRecordType() == MESSAGE; } @Override public Message readMessage() throws IOException { if (!hasMessage()) throw new FormatException(); - if (payloadLength <= MESSAGE_HEADER_LENGTH) throw new FormatException(); + assert nextRecord != null; + byte[] payload = nextRecord.getPayload(); + if (payload.length < MESSAGE_HEADER_LENGTH) throw new FormatException(); // Group ID byte[] id = new byte[UniqueId.LENGTH]; System.arraycopy(payload, 0, id, 0, UniqueId.LENGTH); @@ -143,16 +134,17 @@ class SyncRecordReaderImpl implements SyncRecordReader { long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH); if (timestamp < 0) throw new FormatException(); // Body - byte[] body = new byte[payloadLength - MESSAGE_HEADER_LENGTH]; + byte[] body = new byte[payload.length - MESSAGE_HEADER_LENGTH]; System.arraycopy(payload, MESSAGE_HEADER_LENGTH, body, 0, - payloadLength - MESSAGE_HEADER_LENGTH); - state = State.BUFFER_EMPTY; + payload.length - MESSAGE_HEADER_LENGTH); + nextRecord = null; + // TODO: Add a method that reuses the raw message return messageFactory.createMessage(groupId, timestamp, body); } @Override public boolean hasOffer() throws IOException { - return !eof() && header[1] == OFFER; + return !eof() && getNextRecordType() == OFFER; } @Override @@ -163,7 +155,7 @@ class SyncRecordReaderImpl implements SyncRecordReader { @Override public boolean hasRequest() throws IOException { - return !eof() && header[1] == REQUEST; + return !eof() && getNextRecordType() == REQUEST; } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterFactoryImpl.java index b715edd08a65f278c241d7388cb3e58b556e8b16..0d6a762863e3b75e0a2b28525765e75fe2c4ae18 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterFactoryImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterFactoryImpl.java @@ -1,16 +1,28 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.record.RecordWriter; +import org.briarproject.bramble.api.record.RecordWriterFactory; import org.briarproject.bramble.api.sync.SyncRecordWriter; import org.briarproject.bramble.api.sync.SyncRecordWriterFactory; import java.io.OutputStream; +import javax.inject.Inject; + @NotNullByDefault class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory { + private final RecordWriterFactory recordWriterFactory; + + @Inject + SyncRecordWriterFactoryImpl(RecordWriterFactory recordWriterFactory) { + this.recordWriterFactory = recordWriterFactory; + } + @Override public SyncRecordWriter createRecordWriter(OutputStream out) { - return new SyncRecordWriterImpl(out); + RecordWriter writer = recordWriterFactory.createRecordWriter(out); + return new SyncRecordWriterImpl(writer); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterImpl.java index 6c41945c6a1b059e4bbd2e204f11431efda227d9..d5e59f78dfbd03d439080e7499ad611212cbf394 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/SyncRecordWriterImpl.java @@ -1,81 +1,67 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.record.Record; +import org.briarproject.bramble.api.record.RecordWriter; import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.Offer; -import org.briarproject.bramble.api.sync.RecordTypes; import org.briarproject.bramble.api.sync.Request; import org.briarproject.bramble.api.sync.SyncRecordWriter; -import org.briarproject.bramble.util.ByteUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.io.OutputStream; import javax.annotation.concurrent.NotThreadSafe; import static org.briarproject.bramble.api.sync.RecordTypes.ACK; +import static org.briarproject.bramble.api.sync.RecordTypes.MESSAGE; import static org.briarproject.bramble.api.sync.RecordTypes.OFFER; import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST; -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION; -import static org.briarproject.bramble.api.sync.SyncConstants.RECORD_HEADER_LENGTH; @NotThreadSafe @NotNullByDefault class SyncRecordWriterImpl implements SyncRecordWriter { - private final OutputStream out; - private final byte[] header; - private final ByteArrayOutputStream payload; + private final RecordWriter writer; + private final ByteArrayOutputStream payload = new ByteArrayOutputStream(); - SyncRecordWriterImpl(OutputStream out) { - this.out = out; - header = new byte[RECORD_HEADER_LENGTH]; - header[0] = PROTOCOL_VERSION; - payload = new ByteArrayOutputStream(MAX_RECORD_PAYLOAD_LENGTH); + SyncRecordWriterImpl(RecordWriter writer) { + this.writer = writer; } private void writeRecord(byte recordType) throws IOException { - header[1] = recordType; - ByteUtils.writeUint16(payload.size(), header, 2); - out.write(header); - payload.writeTo(out); + writer.writeRecord(new Record(PROTOCOL_VERSION, recordType, + payload.toByteArray())); payload.reset(); } @Override public void writeAck(Ack a) throws IOException { - if (payload.size() != 0) throw new IllegalStateException(); for (MessageId m : a.getMessageIds()) payload.write(m.getBytes()); writeRecord(ACK); } @Override public void writeMessage(byte[] raw) throws IOException { - header[1] = RecordTypes.MESSAGE; - ByteUtils.writeUint16(raw.length, header, 2); - out.write(header); - out.write(raw); + writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw)); } @Override public void writeOffer(Offer o) throws IOException { - if (payload.size() != 0) throw new IllegalStateException(); for (MessageId m : o.getMessageIds()) payload.write(m.getBytes()); writeRecord(OFFER); } @Override public void writeRequest(Request r) throws IOException { - if (payload.size() != 0) throw new IllegalStateException(); for (MessageId m : r.getMessageIds()) payload.write(m.getBytes()); writeRecord(REQUEST); } @Override public void flush() throws IOException { - out.flush(); + writer.flush(); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java index 00fa90f434f2718e73fd8c4e73a3d1612a5c31bd..1504da9eb48cfcd038d724c04c4fa5398e8d954e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTest.java @@ -112,8 +112,8 @@ public class SyncIntegrationTest extends BrambleTestCase { recordWriter.writeMessage(message1.getRaw()); recordWriter.writeOffer(new Offer(messageIds)); recordWriter.writeRequest(new Request(messageIds)); + recordWriter.flush(); - streamWriter.flush(); return out.toByteArray(); } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java index a714520dd5df088f882a160d33b3d7c6a48be117..0397f549fd72b8291396c3d4a0d8f7d03212b2d5 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncIntegrationTestComponent.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.crypto.CryptoModule; +import org.briarproject.bramble.record.RecordModule; import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.test.TestSecureRandomModule; import org.briarproject.bramble.transport.TransportModule; @@ -13,6 +14,7 @@ import dagger.Component; @Component(modules = { TestSecureRandomModule.class, CryptoModule.class, + RecordModule.class, SyncModule.class, SystemModule.class, TransportModule.class diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncRecordReaderImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncRecordReaderImplTest.java index 4b46a12988018f4fc0658b3a07bfa58f808c340a..ccd1207ffa0e2c60457fea5fccbb4da97c37e13e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncRecordReaderImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/SyncRecordReaderImplTest.java @@ -2,23 +2,28 @@ package org.briarproject.bramble.sync; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.UniqueId; +import org.briarproject.bramble.api.record.Record; +import org.briarproject.bramble.api.record.RecordReader; import org.briarproject.bramble.api.sync.Ack; import org.briarproject.bramble.api.sync.MessageFactory; +import org.briarproject.bramble.api.sync.Offer; +import org.briarproject.bramble.api.sync.Request; +import org.briarproject.bramble.api.sync.SyncRecordReader; import org.briarproject.bramble.test.BrambleMockTestCase; -import org.briarproject.bramble.test.TestUtils; -import org.briarproject.bramble.util.ByteUtils; +import org.jmock.Expectations; import org.junit.Test; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; +import java.io.EOFException; +import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; import static org.briarproject.bramble.api.sync.RecordTypes.ACK; import static org.briarproject.bramble.api.sync.RecordTypes.OFFER; import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS; -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH; import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION; -import static org.briarproject.bramble.api.sync.SyncConstants.RECORD_HEADER_LENGTH; +import static org.briarproject.bramble.test.TestUtils.getRandomBytes; +import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -27,209 +32,164 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase { private final MessageFactory messageFactory = context.mock(MessageFactory.class); - - @Test(expected = FormatException.class) - public void testFormatExceptionIfAckIsTooLarge() throws Exception { - byte[] b = createAck(true); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readAck(); - } + private final RecordReader recordReader = context.mock(RecordReader.class); @Test public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception { - byte[] b = createAck(false); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readAck(); + expectReadRecord(createAck()); + + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); + Ack ack = reader.readAck(); + assertEquals(MAX_MESSAGE_IDS, ack.getMessageIds().size()); } @Test(expected = FormatException.class) public void testFormatExceptionIfAckIsEmpty() throws Exception { - byte[] b = createEmptyAck(); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readAck(); - } + expectReadRecord(createEmptyAck()); - @Test(expected = FormatException.class) - public void testFormatExceptionIfOfferIsTooLarge() throws Exception { - byte[] b = createOffer(true); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readOffer(); + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); + reader.readAck(); } @Test public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception { - byte[] b = createOffer(false); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readOffer(); + expectReadRecord(createOffer()); + + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); + Offer offer = reader.readOffer(); + assertEquals(MAX_MESSAGE_IDS, offer.getMessageIds().size()); } @Test(expected = FormatException.class) public void testFormatExceptionIfOfferIsEmpty() throws Exception { - byte[] b = createEmptyOffer(); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readOffer(); - } + expectReadRecord(createEmptyOffer()); - @Test(expected = FormatException.class) - public void testFormatExceptionIfRequestIsTooLarge() throws Exception { - byte[] b = createRequest(true); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readRequest(); + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); + reader.readOffer(); } @Test public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception { - byte[] b = createRequest(false); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.readRequest(); + expectReadRecord(createRequest()); + + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); + Request request = reader.readRequest(); + assertEquals(MAX_MESSAGE_IDS, request.getMessageIds().size()); } @Test(expected = FormatException.class) public void testFormatExceptionIfRequestIsEmpty() throws Exception { - byte[] b = createEmptyRequest(); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); + expectReadRecord(createEmptyRequest()); + + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); reader.readRequest(); } @Test public void testEofReturnsTrueWhenAtEndOfStream() throws Exception { - ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); + context.checking(new Expectations() {{ + oneOf(recordReader).readRecord(); + will(throwException(new EOFException())); + }}); + + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); + assertTrue(reader.eof()); assertTrue(reader.eof()); } @Test public void testEofReturnsFalseWhenNotAtEndOfStream() throws Exception { - byte[] b = createAck(false); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - assertFalse(reader.eof()); - } - - @Test(expected = FormatException.class) - public void testThrowsExceptionIfHeaderIsTooShort() throws Exception { - byte[] b = new byte[RECORD_HEADER_LENGTH - 1]; - b[0] = PROTOCOL_VERSION; - b[1] = ACK; - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.eof(); - } + expectReadRecord(createAck()); - @Test(expected = FormatException.class) - public void testThrowsExceptionIfPayloadIsTooShort() throws Exception { - int payloadLength = 123; - byte[] b = new byte[RECORD_HEADER_LENGTH + payloadLength - 1]; - b[0] = PROTOCOL_VERSION; - b[1] = ACK; - ByteUtils.writeUint16(payloadLength, b, 2); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.eof(); + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); + assertFalse(reader.eof()); + assertFalse(reader.eof()); } @Test(expected = FormatException.class) public void testThrowsExceptionIfProtocolVersionIsUnrecognised() throws Exception { byte version = (byte) (PROTOCOL_VERSION + 1); - byte[] b = createRecord(version, ACK, new byte[0]); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); - reader.eof(); - } + byte[] payload = getRandomId(); - @Test(expected = FormatException.class) - public void testThrowsExceptionIfPayloadIsTooLong() throws Exception { - byte[] payload = new byte[MAX_RECORD_PAYLOAD_LENGTH + 1]; - byte[] b = createRecord(PROTOCOL_VERSION, ACK, payload); - ByteArrayInputStream in = new ByteArrayInputStream(b); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); + expectReadRecord(new Record(version, ACK, payload)); + + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); reader.eof(); } @Test public void testSkipsUnrecognisedRecordTypes() throws Exception { - byte[] skip1 = createRecord(PROTOCOL_VERSION, (byte) (REQUEST + 1), - new byte[123]); - byte[] skip2 = createRecord(PROTOCOL_VERSION, (byte) (REQUEST + 2), - new byte[0]); - byte[] ack = createAck(false); - ByteArrayOutputStream input = new ByteArrayOutputStream(); - input.write(skip1); - input.write(skip2); - input.write(ack); - ByteArrayInputStream in = new ByteArrayInputStream(input.toByteArray()); - SyncRecordReaderImpl - reader = new SyncRecordReaderImpl(messageFactory, in); + byte type1 = (byte) (REQUEST + 1); + byte[] payload1 = getRandomBytes(123); + Record unknownRecord1 = new Record(PROTOCOL_VERSION, type1, payload1); + byte type2 = (byte) (REQUEST + 2); + byte[] payload2 = new byte[0]; + Record unknownRecord2 = new Record(PROTOCOL_VERSION, type2, payload2); + Record ackRecord = createAck(); + + context.checking(new Expectations() {{ + oneOf(recordReader).readRecord(); + will(returnValue(unknownRecord1)); + oneOf(recordReader).readRecord(); + will(returnValue(unknownRecord2)); + oneOf(recordReader).readRecord(); + will(returnValue(ackRecord)); + + }}); + + SyncRecordReader reader = + new SyncRecordReaderImpl(messageFactory, recordReader); assertTrue(reader.hasAck()); Ack a = reader.readAck(); assertEquals(MAX_MESSAGE_IDS, a.getMessageIds().size()); } - private byte[] createAck(boolean tooBig) throws Exception { - return createRecord(PROTOCOL_VERSION, ACK, createPayload(tooBig)); + private void expectReadRecord(Record record) throws Exception { + context.checking(new Expectations() {{ + oneOf(recordReader).readRecord(); + will(returnValue(record)); + }}); } - private byte[] createEmptyAck() throws Exception { - return createRecord(PROTOCOL_VERSION, ACK, new byte[0]); + private Record createAck() throws Exception { + return new Record(PROTOCOL_VERSION, ACK, createPayload()); } - private byte[] createOffer(boolean tooBig) throws Exception { - return createRecord(PROTOCOL_VERSION, OFFER, createPayload(tooBig)); + private Record createEmptyAck() throws Exception { + return new Record(PROTOCOL_VERSION, ACK, new byte[0]); } - private byte[] createEmptyOffer() throws Exception { - return createRecord(PROTOCOL_VERSION, OFFER, new byte[0]); + private Record createOffer() throws Exception { + return new Record(PROTOCOL_VERSION, OFFER, createPayload()); } - private byte[] createRequest(boolean tooBig) throws Exception { - return createRecord(PROTOCOL_VERSION, REQUEST, createPayload(tooBig)); + private Record createEmptyOffer() throws Exception { + return new Record(PROTOCOL_VERSION, OFFER, new byte[0]); } - private byte[] createEmptyRequest() throws Exception { - return createRecord(PROTOCOL_VERSION, REQUEST, new byte[0]); + private Record createRequest() throws Exception { + return new Record(PROTOCOL_VERSION, REQUEST, createPayload()); } - private byte[] createRecord(byte version, byte type, byte[] payload) { - byte[] b = new byte[RECORD_HEADER_LENGTH + payload.length]; - b[0] = version; - b[1] = type; - ByteUtils.writeUint16(payload.length, b, 2); - System.arraycopy(payload, 0, b, RECORD_HEADER_LENGTH, payload.length); - return b; + private Record createEmptyRequest() throws Exception { + return new Record(PROTOCOL_VERSION, REQUEST, new byte[0]); } - private byte[] createPayload(boolean tooBig) throws Exception { + private byte[] createPayload() throws Exception { ByteArrayOutputStream payload = new ByteArrayOutputStream(); - while (payload.size() + UniqueId.LENGTH <= MAX_RECORD_PAYLOAD_LENGTH) { - payload.write(TestUtils.getRandomId()); + while (payload.size() + UniqueId.LENGTH <= MAX_RECORD_PAYLOAD_BYTES) { + payload.write(getRandomId()); } - if (tooBig) payload.write(TestUtils.getRandomId()); - assertEquals(tooBig, payload.size() > MAX_RECORD_PAYLOAD_LENGTH); return payload.toByteArray(); } } diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java index 160d80e534c9d3b234835ad0f08b8293c4724056..20a59f21a1f4cb0a0aea7a4f82c00025da6e869d 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTestComponent.java @@ -10,6 +10,7 @@ import org.briarproject.bramble.event.EventModule; import org.briarproject.bramble.identity.IdentityModule; import org.briarproject.bramble.lifecycle.LifecycleModule; import org.briarproject.bramble.properties.PropertiesModule; +import org.briarproject.bramble.record.RecordModule; import org.briarproject.bramble.sync.SyncModule; import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.test.TestDatabaseModule; @@ -52,6 +53,7 @@ import dagger.Component; MessagingModule.class, PrivateGroupModule.class, PropertiesModule.class, + RecordModule.class, SharingModule.class, SyncModule.class, SystemModule.class, diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java index c5a1f1851cb99e3acf668e9d400cd6d031e465c1..9e828d722ddae2caa5dd137c800057f4e81dc90c 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/MessageSizeIntegrationTest.java @@ -26,7 +26,7 @@ import javax.inject.Inject; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; -import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH; +import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH; @@ -63,7 +63,7 @@ public class MessageSizeIntegrationTest extends BriarTestCase { int length = message.getMessage().getRaw().length; assertTrue( length > UniqueId.LENGTH + 8 + MAX_PRIVATE_MESSAGE_BODY_LENGTH); - assertTrue(length <= MAX_RECORD_PAYLOAD_LENGTH); + assertTrue(length <= MAX_RECORD_PAYLOAD_BYTES); } @Test @@ -87,7 +87,7 @@ public class MessageSizeIntegrationTest extends BriarTestCase { assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH + 4 + MAX_AUTHOR_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + MAX_FORUM_POST_BODY_LENGTH); - assertTrue(length <= MAX_RECORD_PAYLOAD_LENGTH); + assertTrue(length <= MAX_RECORD_PAYLOAD_BYTES); } private static void injectEagerSingletons( diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java index f3d6f039977361459b26333f5ade3d6538db3657..7dade1ed198f8223971bf55255ed03ecb2a79ff7 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTestComponent.java @@ -16,6 +16,7 @@ import org.briarproject.bramble.db.DatabaseModule; import org.briarproject.bramble.event.EventModule; import org.briarproject.bramble.identity.IdentityModule; import org.briarproject.bramble.lifecycle.LifecycleModule; +import org.briarproject.bramble.record.RecordModule; import org.briarproject.bramble.sync.SyncModule; import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.test.TestCryptoExecutorModule; @@ -48,6 +49,7 @@ import dagger.Component; IdentityModule.class, LifecycleModule.class, MessagingModule.class, + RecordModule.class, SyncModule.class, SystemModule.class, TransportModule.class, diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java index 131f92ea8b8b910ab7f49ca9f00466900fd9c15c..9d86e58d97f841cf01cd1339f8749bc71eeb448f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTestComponent.java @@ -19,6 +19,7 @@ import org.briarproject.bramble.event.EventModule; import org.briarproject.bramble.identity.IdentityModule; import org.briarproject.bramble.lifecycle.LifecycleModule; import org.briarproject.bramble.properties.PropertiesModule; +import org.briarproject.bramble.record.RecordModule; import org.briarproject.bramble.sync.SyncModule; import org.briarproject.bramble.system.SystemModule; import org.briarproject.bramble.test.TestDatabaseModule; @@ -73,6 +74,7 @@ import dagger.Component; MessagingModule.class, PrivateGroupModule.class, PropertiesModule.class, + RecordModule.class, SharingModule.class, SyncModule.class, SystemModule.class,