mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-20 14:49:53 +01:00
Use generic record reader/writer for sync.
This commit is contained in:
@@ -2,6 +2,8 @@ package org.briarproject.bramble.api.sync;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.UniqueId;
|
import org.briarproject.bramble.api.UniqueId;
|
||||||
|
|
||||||
|
import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES;
|
||||||
|
|
||||||
public interface SyncConstants {
|
public interface SyncConstants {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -9,16 +11,6 @@ public interface SyncConstants {
|
|||||||
*/
|
*/
|
||||||
byte PROTOCOL_VERSION = 0;
|
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.
|
* 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.
|
* 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
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_MESSAGE_IDS;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An outgoing {@link SyncSession} suitable for duplex transports. The session
|
* An outgoing {@link SyncSession} suitable for duplex transports. The session
|
||||||
@@ -273,7 +273,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
b = db.generateRequestedBatch(txn, contactId,
|
b = db.generateRequestedBatch(txn, contactId,
|
||||||
MAX_RECORD_PAYLOAD_LENGTH, maxLatency);
|
MAX_RECORD_PAYLOAD_BYTES, maxLatency);
|
||||||
setNextSendTime(db.getNextSendTime(txn, contactId));
|
setNextSendTime(db.getNextSendTime(txn, contactId));
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -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.BLOCK_LABEL;
|
||||||
import static org.briarproject.bramble.api.sync.MessageId.ID_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_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.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.util.ByteUtils.INT_64_BYTES;
|
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) {
|
public Message createMessage(MessageId m, byte[] raw) {
|
||||||
if (raw.length < MESSAGE_HEADER_LENGTH)
|
if (raw.length < MESSAGE_HEADER_LENGTH)
|
||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
|
if (raw.length > MAX_MESSAGE_LENGTH)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
byte[] groupId = new byte[UniqueId.LENGTH];
|
byte[] groupId = new byte[UniqueId.LENGTH];
|
||||||
System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH);
|
System.arraycopy(raw, 0, groupId, 0, UniqueId.LENGTH);
|
||||||
long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH);
|
long timestamp = ByteUtils.readUint64(raw, UniqueId.LENGTH);
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.bramble.api.lifecycle.LifecycleManager.LifecycleState.STOPPING;
|
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_MESSAGE_IDS;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD_LENGTH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An outgoing {@link SyncSession} suitable for simplex transports. The session
|
* An outgoing {@link SyncSession} suitable for simplex transports. The session
|
||||||
@@ -171,7 +171,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
try {
|
try {
|
||||||
b = db.generateBatch(txn, contactId,
|
b = db.generateBatch(txn, contactId,
|
||||||
MAX_RECORD_PAYLOAD_LENGTH, maxLatency);
|
MAX_RECORD_PAYLOAD_BYTES, maxLatency);
|
||||||
db.commitTransaction(txn);
|
db.commitTransaction(txn);
|
||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
|
|||||||
@@ -58,8 +58,9 @@ public class SyncModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
SyncRecordWriterFactory provideRecordWriterFactory() {
|
SyncRecordWriterFactory provideRecordWriterFactory(
|
||||||
return new SyncRecordWriterFactoryImpl();
|
SyncRecordWriterFactoryImpl recordWriterFactory) {
|
||||||
|
return recordWriterFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
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.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordReader;
|
import org.briarproject.bramble.api.sync.SyncRecordReader;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordReaderFactory;
|
import org.briarproject.bramble.api.sync.SyncRecordReaderFactory;
|
||||||
@@ -15,14 +17,18 @@ import javax.inject.Inject;
|
|||||||
class SyncRecordReaderFactoryImpl implements SyncRecordReaderFactory {
|
class SyncRecordReaderFactoryImpl implements SyncRecordReaderFactory {
|
||||||
|
|
||||||
private final MessageFactory messageFactory;
|
private final MessageFactory messageFactory;
|
||||||
|
private final RecordReaderFactory recordReaderFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
SyncRecordReaderFactoryImpl(MessageFactory messageFactory) {
|
SyncRecordReaderFactoryImpl(MessageFactory messageFactory,
|
||||||
|
RecordReaderFactory recordReaderFactory) {
|
||||||
this.messageFactory = messageFactory;
|
this.messageFactory = messageFactory;
|
||||||
|
this.recordReaderFactory = recordReaderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncRecordReader createRecordReader(InputStream in) {
|
public SyncRecordReader createRecordReader(InputStream in) {
|
||||||
return new SyncRecordReaderImpl(messageFactory, in);
|
RecordReader reader = recordReaderFactory.createRecordReader(in);
|
||||||
|
return new SyncRecordReaderImpl(messageFactory, reader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package org.briarproject.bramble.sync;
|
|||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.UniqueId;
|
import org.briarproject.bramble.api.UniqueId;
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
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.Ack;
|
||||||
import org.briarproject.bramble.api.sync.GroupId;
|
import org.briarproject.bramble.api.sync.GroupId;
|
||||||
import org.briarproject.bramble.api.sync.Message;
|
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.api.sync.SyncRecordReader;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
|
|
||||||
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
|
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.MESSAGE;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
|
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.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.MESSAGE_HEADER_LENGTH;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.RECORD_HEADER_LENGTH;
|
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SyncRecordReaderImpl implements SyncRecordReader {
|
class SyncRecordReaderImpl implements SyncRecordReader {
|
||||||
|
|
||||||
private enum State {BUFFER_EMPTY, BUFFER_FULL, EOF}
|
|
||||||
|
|
||||||
private final MessageFactory messageFactory;
|
private final MessageFactory messageFactory;
|
||||||
private final InputStream in;
|
private final RecordReader reader;
|
||||||
private final byte[] header, payload;
|
|
||||||
|
|
||||||
private State state = State.BUFFER_EMPTY;
|
@Nullable
|
||||||
private int payloadLength = 0;
|
private Record nextRecord = null;
|
||||||
|
private boolean eof = false;
|
||||||
|
|
||||||
SyncRecordReaderImpl(MessageFactory messageFactory, InputStream in) {
|
SyncRecordReaderImpl(MessageFactory messageFactory, RecordReader reader) {
|
||||||
this.messageFactory = messageFactory;
|
this.messageFactory = messageFactory;
|
||||||
this.in = in;
|
this.reader = reader;
|
||||||
header = new byte[RECORD_HEADER_LENGTH];
|
|
||||||
payload = new byte[MAX_RECORD_PAYLOAD_LENGTH];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void readRecord() throws IOException {
|
private void readRecord() throws IOException {
|
||||||
if (state != State.BUFFER_EMPTY) throw new IllegalStateException();
|
assert nextRecord == null;
|
||||||
while (true) {
|
while (true) {
|
||||||
// Read the header
|
nextRecord = reader.readRecord();
|
||||||
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);
|
|
||||||
// Check the protocol version
|
// Check the protocol version
|
||||||
|
byte version = nextRecord.getProtocolVersion();
|
||||||
if (version != PROTOCOL_VERSION) throw new FormatException();
|
if (version != PROTOCOL_VERSION) throw new FormatException();
|
||||||
// Check the payload length
|
byte type = nextRecord.getRecordType();
|
||||||
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;
|
|
||||||
// Return if this is a known record type, otherwise continue
|
// Return if this is a known record type, otherwise continue
|
||||||
if (type == ACK || type == MESSAGE || type == OFFER ||
|
if (type == ACK || type == MESSAGE || type == OFFER ||
|
||||||
type == REQUEST) {
|
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
|
* Returns true if there's another record available or false if we've
|
||||||
* reached the end of the input stream.
|
* reached the end of the input stream.
|
||||||
@@ -97,14 +77,21 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean eof() throws IOException {
|
public boolean eof() throws IOException {
|
||||||
if (state == State.BUFFER_EMPTY) readRecord();
|
if (nextRecord != null) return false;
|
||||||
if (state == State.BUFFER_EMPTY) throw new IllegalStateException();
|
if (eof) return true;
|
||||||
return state == State.EOF;
|
try {
|
||||||
|
readRecord();
|
||||||
|
return false;
|
||||||
|
} catch (EOFException e) {
|
||||||
|
nextRecord = null;
|
||||||
|
eof = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAck() throws IOException {
|
public boolean hasAck() throws IOException {
|
||||||
return !eof() && header[1] == ACK;
|
return !eof() && getNextRecordType() == ACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -114,27 +101,31 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<MessageId> readMessageIds() throws IOException {
|
private List<MessageId> readMessageIds() throws IOException {
|
||||||
if (payloadLength == 0) throw new FormatException();
|
assert nextRecord != null;
|
||||||
if (payloadLength % UniqueId.LENGTH != 0) throw new FormatException();
|
byte[] payload = nextRecord.getPayload();
|
||||||
List<MessageId> ids = new ArrayList<>();
|
if (payload.length == 0) throw new FormatException();
|
||||||
for (int off = 0; off < payloadLength; off += UniqueId.LENGTH) {
|
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];
|
byte[] id = new byte[UniqueId.LENGTH];
|
||||||
System.arraycopy(payload, off, id, 0, UniqueId.LENGTH);
|
System.arraycopy(payload, off, id, 0, UniqueId.LENGTH);
|
||||||
ids.add(new MessageId(id));
|
ids.add(new MessageId(id));
|
||||||
}
|
}
|
||||||
state = State.BUFFER_EMPTY;
|
nextRecord = null;
|
||||||
return ids;
|
return ids;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasMessage() throws IOException {
|
public boolean hasMessage() throws IOException {
|
||||||
return !eof() && header[1] == MESSAGE;
|
return !eof() && getNextRecordType() == MESSAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Message readMessage() throws IOException {
|
public Message readMessage() throws IOException {
|
||||||
if (!hasMessage()) throw new FormatException();
|
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
|
// Group ID
|
||||||
byte[] id = new byte[UniqueId.LENGTH];
|
byte[] id = new byte[UniqueId.LENGTH];
|
||||||
System.arraycopy(payload, 0, id, 0, 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);
|
long timestamp = ByteUtils.readUint64(payload, UniqueId.LENGTH);
|
||||||
if (timestamp < 0) throw new FormatException();
|
if (timestamp < 0) throw new FormatException();
|
||||||
// Body
|
// 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,
|
System.arraycopy(payload, MESSAGE_HEADER_LENGTH, body, 0,
|
||||||
payloadLength - MESSAGE_HEADER_LENGTH);
|
payload.length - MESSAGE_HEADER_LENGTH);
|
||||||
state = State.BUFFER_EMPTY;
|
nextRecord = null;
|
||||||
|
// TODO: Add a method that reuses the raw message
|
||||||
return messageFactory.createMessage(groupId, timestamp, body);
|
return messageFactory.createMessage(groupId, timestamp, body);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasOffer() throws IOException {
|
public boolean hasOffer() throws IOException {
|
||||||
return !eof() && header[1] == OFFER;
|
return !eof() && getNextRecordType() == OFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -163,7 +155,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasRequest() throws IOException {
|
public boolean hasRequest() throws IOException {
|
||||||
return !eof() && header[1] == REQUEST;
|
return !eof() && getNextRecordType() == REQUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
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.SyncRecordWriter;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
import org.briarproject.bramble.api.sync.SyncRecordWriterFactory;
|
||||||
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
|
class SyncRecordWriterFactoryImpl implements SyncRecordWriterFactory {
|
||||||
|
|
||||||
|
private final RecordWriterFactory recordWriterFactory;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
SyncRecordWriterFactoryImpl(RecordWriterFactory recordWriterFactory) {
|
||||||
|
this.recordWriterFactory = recordWriterFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SyncRecordWriter createRecordWriter(OutputStream out) {
|
public SyncRecordWriter createRecordWriter(OutputStream out) {
|
||||||
return new SyncRecordWriterImpl(out);
|
RecordWriter writer = recordWriterFactory.createRecordWriter(out);
|
||||||
|
return new SyncRecordWriterImpl(writer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,81 +1,67 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
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.Ack;
|
||||||
import org.briarproject.bramble.api.sync.MessageId;
|
import org.briarproject.bramble.api.sync.MessageId;
|
||||||
import org.briarproject.bramble.api.sync.Offer;
|
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.Request;
|
||||||
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
import org.briarproject.bramble.api.sync.SyncRecordWriter;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
|
||||||
|
|
||||||
import javax.annotation.concurrent.NotThreadSafe;
|
import javax.annotation.concurrent.NotThreadSafe;
|
||||||
|
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.ACK;
|
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.OFFER;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.REQUEST;
|
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.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.RECORD_HEADER_LENGTH;
|
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class SyncRecordWriterImpl implements SyncRecordWriter {
|
class SyncRecordWriterImpl implements SyncRecordWriter {
|
||||||
|
|
||||||
private final OutputStream out;
|
private final RecordWriter writer;
|
||||||
private final byte[] header;
|
private final ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
||||||
private final ByteArrayOutputStream payload;
|
|
||||||
|
|
||||||
SyncRecordWriterImpl(OutputStream out) {
|
SyncRecordWriterImpl(RecordWriter writer) {
|
||||||
this.out = out;
|
this.writer = writer;
|
||||||
header = new byte[RECORD_HEADER_LENGTH];
|
|
||||||
header[0] = PROTOCOL_VERSION;
|
|
||||||
payload = new ByteArrayOutputStream(MAX_RECORD_PAYLOAD_LENGTH);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeRecord(byte recordType) throws IOException {
|
private void writeRecord(byte recordType) throws IOException {
|
||||||
header[1] = recordType;
|
writer.writeRecord(new Record(PROTOCOL_VERSION, recordType,
|
||||||
ByteUtils.writeUint16(payload.size(), header, 2);
|
payload.toByteArray()));
|
||||||
out.write(header);
|
|
||||||
payload.writeTo(out);
|
|
||||||
payload.reset();
|
payload.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeAck(Ack a) throws IOException {
|
public void writeAck(Ack a) throws IOException {
|
||||||
if (payload.size() != 0) throw new IllegalStateException();
|
|
||||||
for (MessageId m : a.getMessageIds()) payload.write(m.getBytes());
|
for (MessageId m : a.getMessageIds()) payload.write(m.getBytes());
|
||||||
writeRecord(ACK);
|
writeRecord(ACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeMessage(byte[] raw) throws IOException {
|
public void writeMessage(byte[] raw) throws IOException {
|
||||||
header[1] = RecordTypes.MESSAGE;
|
writer.writeRecord(new Record(PROTOCOL_VERSION, MESSAGE, raw));
|
||||||
ByteUtils.writeUint16(raw.length, header, 2);
|
|
||||||
out.write(header);
|
|
||||||
out.write(raw);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeOffer(Offer o) throws IOException {
|
public void writeOffer(Offer o) throws IOException {
|
||||||
if (payload.size() != 0) throw new IllegalStateException();
|
|
||||||
for (MessageId m : o.getMessageIds()) payload.write(m.getBytes());
|
for (MessageId m : o.getMessageIds()) payload.write(m.getBytes());
|
||||||
writeRecord(OFFER);
|
writeRecord(OFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeRequest(Request r) throws IOException {
|
public void writeRequest(Request r) throws IOException {
|
||||||
if (payload.size() != 0) throw new IllegalStateException();
|
|
||||||
for (MessageId m : r.getMessageIds()) payload.write(m.getBytes());
|
for (MessageId m : r.getMessageIds()) payload.write(m.getBytes());
|
||||||
writeRecord(REQUEST);
|
writeRecord(REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
out.flush();
|
writer.flush();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ public class SyncIntegrationTest extends BrambleTestCase {
|
|||||||
recordWriter.writeMessage(message1.getRaw());
|
recordWriter.writeMessage(message1.getRaw());
|
||||||
recordWriter.writeOffer(new Offer(messageIds));
|
recordWriter.writeOffer(new Offer(messageIds));
|
||||||
recordWriter.writeRequest(new Request(messageIds));
|
recordWriter.writeRequest(new Request(messageIds));
|
||||||
|
recordWriter.flush();
|
||||||
|
|
||||||
streamWriter.flush();
|
|
||||||
return out.toByteArray();
|
return out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.crypto.CryptoModule;
|
import org.briarproject.bramble.crypto.CryptoModule;
|
||||||
|
import org.briarproject.bramble.record.RecordModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.test.TestSecureRandomModule;
|
import org.briarproject.bramble.test.TestSecureRandomModule;
|
||||||
import org.briarproject.bramble.transport.TransportModule;
|
import org.briarproject.bramble.transport.TransportModule;
|
||||||
@@ -13,6 +14,7 @@ import dagger.Component;
|
|||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
TestSecureRandomModule.class,
|
TestSecureRandomModule.class,
|
||||||
CryptoModule.class,
|
CryptoModule.class,
|
||||||
|
RecordModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
SystemModule.class,
|
SystemModule.class,
|
||||||
TransportModule.class
|
TransportModule.class
|
||||||
|
|||||||
@@ -2,23 +2,28 @@ package org.briarproject.bramble.sync;
|
|||||||
|
|
||||||
import org.briarproject.bramble.api.FormatException;
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.UniqueId;
|
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.Ack;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
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.BrambleMockTestCase;
|
||||||
import org.briarproject.bramble.test.TestUtils;
|
import org.jmock.Expectations;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.ByteArrayOutputStream;
|
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.ACK;
|
||||||
import static org.briarproject.bramble.api.sync.RecordTypes.OFFER;
|
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.RecordTypes.REQUEST;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS;
|
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.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.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
@@ -27,209 +32,164 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
|
|
||||||
private final MessageFactory messageFactory =
|
private final MessageFactory messageFactory =
|
||||||
context.mock(MessageFactory.class);
|
context.mock(MessageFactory.class);
|
||||||
|
private final RecordReader recordReader = context.mock(RecordReader.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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
|
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
|
||||||
byte[] b = createAck(false);
|
expectReadRecord(createAck());
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
SyncRecordReader reader =
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
reader.readAck();
|
Ack ack = reader.readAck();
|
||||||
|
assertEquals(MAX_MESSAGE_IDS, ack.getMessageIds().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testFormatExceptionIfAckIsEmpty() throws Exception {
|
public void testFormatExceptionIfAckIsEmpty() throws Exception {
|
||||||
byte[] b = createEmptyAck();
|
expectReadRecord(createEmptyAck());
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
|
||||||
reader.readAck();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
SyncRecordReader reader =
|
||||||
public void testFormatExceptionIfOfferIsTooLarge() throws Exception {
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
byte[] b = createOffer(true);
|
reader.readAck();
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
|
||||||
reader.readOffer();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception {
|
public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception {
|
||||||
byte[] b = createOffer(false);
|
expectReadRecord(createOffer());
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
SyncRecordReader reader =
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
reader.readOffer();
|
Offer offer = reader.readOffer();
|
||||||
|
assertEquals(MAX_MESSAGE_IDS, offer.getMessageIds().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testFormatExceptionIfOfferIsEmpty() throws Exception {
|
public void testFormatExceptionIfOfferIsEmpty() throws Exception {
|
||||||
byte[] b = createEmptyOffer();
|
expectReadRecord(createEmptyOffer());
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
|
||||||
reader.readOffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
SyncRecordReader reader =
|
||||||
public void testFormatExceptionIfRequestIsTooLarge() throws Exception {
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
byte[] b = createRequest(true);
|
reader.readOffer();
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
|
||||||
reader.readRequest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception {
|
public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception {
|
||||||
byte[] b = createRequest(false);
|
expectReadRecord(createRequest());
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
SyncRecordReader reader =
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
reader.readRequest();
|
Request request = reader.readRequest();
|
||||||
|
assertEquals(MAX_MESSAGE_IDS, request.getMessageIds().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testFormatExceptionIfRequestIsEmpty() throws Exception {
|
public void testFormatExceptionIfRequestIsEmpty() throws Exception {
|
||||||
byte[] b = createEmptyRequest();
|
expectReadRecord(createEmptyRequest());
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
SyncRecordReader reader =
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
reader.readRequest();
|
reader.readRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEofReturnsTrueWhenAtEndOfStream() throws Exception {
|
public void testEofReturnsTrueWhenAtEndOfStream() throws Exception {
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(new byte[0]);
|
context.checking(new Expectations() {{
|
||||||
SyncRecordReaderImpl
|
oneOf(recordReader).readRecord();
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
will(throwException(new EOFException()));
|
||||||
|
}});
|
||||||
|
|
||||||
|
SyncRecordReader reader =
|
||||||
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
|
assertTrue(reader.eof());
|
||||||
assertTrue(reader.eof());
|
assertTrue(reader.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEofReturnsFalseWhenNotAtEndOfStream() throws Exception {
|
public void testEofReturnsFalseWhenNotAtEndOfStream() throws Exception {
|
||||||
byte[] b = createAck(false);
|
expectReadRecord(createAck());
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
SyncRecordReader reader =
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
|
assertFalse(reader.eof());
|
||||||
assertFalse(reader.eof());
|
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
@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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
@Test(expected = FormatException.class)
|
||||||
public void testThrowsExceptionIfProtocolVersionIsUnrecognised()
|
public void testThrowsExceptionIfProtocolVersionIsUnrecognised()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
byte version = (byte) (PROTOCOL_VERSION + 1);
|
byte version = (byte) (PROTOCOL_VERSION + 1);
|
||||||
byte[] b = createRecord(version, ACK, new byte[0]);
|
byte[] payload = getRandomId();
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
|
||||||
reader.eof();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = FormatException.class)
|
expectReadRecord(new Record(version, ACK, payload));
|
||||||
public void testThrowsExceptionIfPayloadIsTooLong() throws Exception {
|
|
||||||
byte[] payload = new byte[MAX_RECORD_PAYLOAD_LENGTH + 1];
|
SyncRecordReader reader =
|
||||||
byte[] b = createRecord(PROTOCOL_VERSION, ACK, payload);
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(b);
|
|
||||||
SyncRecordReaderImpl
|
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
|
||||||
reader.eof();
|
reader.eof();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipsUnrecognisedRecordTypes() throws Exception {
|
public void testSkipsUnrecognisedRecordTypes() throws Exception {
|
||||||
byte[] skip1 = createRecord(PROTOCOL_VERSION, (byte) (REQUEST + 1),
|
byte type1 = (byte) (REQUEST + 1);
|
||||||
new byte[123]);
|
byte[] payload1 = getRandomBytes(123);
|
||||||
byte[] skip2 = createRecord(PROTOCOL_VERSION, (byte) (REQUEST + 2),
|
Record unknownRecord1 = new Record(PROTOCOL_VERSION, type1, payload1);
|
||||||
new byte[0]);
|
byte type2 = (byte) (REQUEST + 2);
|
||||||
byte[] ack = createAck(false);
|
byte[] payload2 = new byte[0];
|
||||||
ByteArrayOutputStream input = new ByteArrayOutputStream();
|
Record unknownRecord2 = new Record(PROTOCOL_VERSION, type2, payload2);
|
||||||
input.write(skip1);
|
Record ackRecord = createAck();
|
||||||
input.write(skip2);
|
|
||||||
input.write(ack);
|
context.checking(new Expectations() {{
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(input.toByteArray());
|
oneOf(recordReader).readRecord();
|
||||||
SyncRecordReaderImpl
|
will(returnValue(unknownRecord1));
|
||||||
reader = new SyncRecordReaderImpl(messageFactory, in);
|
oneOf(recordReader).readRecord();
|
||||||
|
will(returnValue(unknownRecord2));
|
||||||
|
oneOf(recordReader).readRecord();
|
||||||
|
will(returnValue(ackRecord));
|
||||||
|
|
||||||
|
}});
|
||||||
|
|
||||||
|
SyncRecordReader reader =
|
||||||
|
new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
assertTrue(reader.hasAck());
|
assertTrue(reader.hasAck());
|
||||||
Ack a = reader.readAck();
|
Ack a = reader.readAck();
|
||||||
assertEquals(MAX_MESSAGE_IDS, a.getMessageIds().size());
|
assertEquals(MAX_MESSAGE_IDS, a.getMessageIds().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createAck(boolean tooBig) throws Exception {
|
private void expectReadRecord(Record record) throws Exception {
|
||||||
return createRecord(PROTOCOL_VERSION, ACK, createPayload(tooBig));
|
context.checking(new Expectations() {{
|
||||||
|
oneOf(recordReader).readRecord();
|
||||||
|
will(returnValue(record));
|
||||||
|
}});
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createEmptyAck() throws Exception {
|
private Record createAck() throws Exception {
|
||||||
return createRecord(PROTOCOL_VERSION, ACK, new byte[0]);
|
return new Record(PROTOCOL_VERSION, ACK, createPayload());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createOffer(boolean tooBig) throws Exception {
|
private Record createEmptyAck() throws Exception {
|
||||||
return createRecord(PROTOCOL_VERSION, OFFER, createPayload(tooBig));
|
return new Record(PROTOCOL_VERSION, ACK, new byte[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createEmptyOffer() throws Exception {
|
private Record createOffer() throws Exception {
|
||||||
return createRecord(PROTOCOL_VERSION, OFFER, new byte[0]);
|
return new Record(PROTOCOL_VERSION, OFFER, createPayload());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createRequest(boolean tooBig) throws Exception {
|
private Record createEmptyOffer() throws Exception {
|
||||||
return createRecord(PROTOCOL_VERSION, REQUEST, createPayload(tooBig));
|
return new Record(PROTOCOL_VERSION, OFFER, new byte[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createEmptyRequest() throws Exception {
|
private Record createRequest() throws Exception {
|
||||||
return createRecord(PROTOCOL_VERSION, REQUEST, new byte[0]);
|
return new Record(PROTOCOL_VERSION, REQUEST, createPayload());
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createRecord(byte version, byte type, byte[] payload) {
|
private Record createEmptyRequest() throws Exception {
|
||||||
byte[] b = new byte[RECORD_HEADER_LENGTH + payload.length];
|
return new Record(PROTOCOL_VERSION, REQUEST, new byte[0]);
|
||||||
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 byte[] createPayload(boolean tooBig) throws Exception {
|
private byte[] createPayload() throws Exception {
|
||||||
ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
||||||
while (payload.size() + UniqueId.LENGTH <= MAX_RECORD_PAYLOAD_LENGTH) {
|
while (payload.size() + UniqueId.LENGTH <= MAX_RECORD_PAYLOAD_BYTES) {
|
||||||
payload.write(TestUtils.getRandomId());
|
payload.write(getRandomId());
|
||||||
}
|
}
|
||||||
if (tooBig) payload.write(TestUtils.getRandomId());
|
|
||||||
assertEquals(tooBig, payload.size() > MAX_RECORD_PAYLOAD_LENGTH);
|
|
||||||
return payload.toByteArray();
|
return payload.toByteArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.briarproject.bramble.event.EventModule;
|
|||||||
import org.briarproject.bramble.identity.IdentityModule;
|
import org.briarproject.bramble.identity.IdentityModule;
|
||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.bramble.properties.PropertiesModule;
|
import org.briarproject.bramble.properties.PropertiesModule;
|
||||||
|
import org.briarproject.bramble.record.RecordModule;
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.test.TestDatabaseModule;
|
import org.briarproject.bramble.test.TestDatabaseModule;
|
||||||
@@ -52,6 +53,7 @@ import dagger.Component;
|
|||||||
MessagingModule.class,
|
MessagingModule.class,
|
||||||
PrivateGroupModule.class,
|
PrivateGroupModule.class,
|
||||||
PropertiesModule.class,
|
PropertiesModule.class,
|
||||||
|
RecordModule.class,
|
||||||
SharingModule.class,
|
SharingModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
SystemModule.class,
|
SystemModule.class,
|
||||||
|
|||||||
@@ -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_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_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.test.TestUtils.getRandomId;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
import static org.briarproject.bramble.util.StringUtils.getRandomString;
|
||||||
import static org.briarproject.briar.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH;
|
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;
|
int length = message.getMessage().getRaw().length;
|
||||||
assertTrue(
|
assertTrue(
|
||||||
length > UniqueId.LENGTH + 8 + MAX_PRIVATE_MESSAGE_BODY_LENGTH);
|
length > UniqueId.LENGTH + 8 + MAX_PRIVATE_MESSAGE_BODY_LENGTH);
|
||||||
assertTrue(length <= MAX_RECORD_PAYLOAD_LENGTH);
|
assertTrue(length <= MAX_RECORD_PAYLOAD_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -87,7 +87,7 @@ public class MessageSizeIntegrationTest extends BriarTestCase {
|
|||||||
assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH + 4
|
assertTrue(length > UniqueId.LENGTH + 8 + UniqueId.LENGTH + 4
|
||||||
+ MAX_AUTHOR_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH
|
+ MAX_AUTHOR_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH
|
||||||
+ MAX_FORUM_POST_BODY_LENGTH);
|
+ MAX_FORUM_POST_BODY_LENGTH);
|
||||||
assertTrue(length <= MAX_RECORD_PAYLOAD_LENGTH);
|
assertTrue(length <= MAX_RECORD_PAYLOAD_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void injectEagerSingletons(
|
private static void injectEagerSingletons(
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.briarproject.bramble.db.DatabaseModule;
|
|||||||
import org.briarproject.bramble.event.EventModule;
|
import org.briarproject.bramble.event.EventModule;
|
||||||
import org.briarproject.bramble.identity.IdentityModule;
|
import org.briarproject.bramble.identity.IdentityModule;
|
||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
|
import org.briarproject.bramble.record.RecordModule;
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.test.TestCryptoExecutorModule;
|
import org.briarproject.bramble.test.TestCryptoExecutorModule;
|
||||||
@@ -48,6 +49,7 @@ import dagger.Component;
|
|||||||
IdentityModule.class,
|
IdentityModule.class,
|
||||||
LifecycleModule.class,
|
LifecycleModule.class,
|
||||||
MessagingModule.class,
|
MessagingModule.class,
|
||||||
|
RecordModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
SystemModule.class,
|
SystemModule.class,
|
||||||
TransportModule.class,
|
TransportModule.class,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import org.briarproject.bramble.event.EventModule;
|
|||||||
import org.briarproject.bramble.identity.IdentityModule;
|
import org.briarproject.bramble.identity.IdentityModule;
|
||||||
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
import org.briarproject.bramble.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.bramble.properties.PropertiesModule;
|
import org.briarproject.bramble.properties.PropertiesModule;
|
||||||
|
import org.briarproject.bramble.record.RecordModule;
|
||||||
import org.briarproject.bramble.sync.SyncModule;
|
import org.briarproject.bramble.sync.SyncModule;
|
||||||
import org.briarproject.bramble.system.SystemModule;
|
import org.briarproject.bramble.system.SystemModule;
|
||||||
import org.briarproject.bramble.test.TestDatabaseModule;
|
import org.briarproject.bramble.test.TestDatabaseModule;
|
||||||
@@ -73,6 +74,7 @@ import dagger.Component;
|
|||||||
MessagingModule.class,
|
MessagingModule.class,
|
||||||
PrivateGroupModule.class,
|
PrivateGroupModule.class,
|
||||||
PropertiesModule.class,
|
PropertiesModule.class,
|
||||||
|
RecordModule.class,
|
||||||
SharingModule.class,
|
SharingModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
SystemModule.class,
|
SystemModule.class,
|
||||||
|
|||||||
Reference in New Issue
Block a user