mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 22:29:53 +01:00
Add versions record to sync protocol.
This commit is contained in:
@@ -9,5 +9,5 @@ public interface RecordTypes {
|
|||||||
byte MESSAGE = 1;
|
byte MESSAGE = 1;
|
||||||
byte OFFER = 2;
|
byte OFFER = 2;
|
||||||
byte REQUEST = 3;
|
byte REQUEST = 3;
|
||||||
|
byte VERSIONS = 4;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,4 +35,10 @@ 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_BYTES / UniqueId.LENGTH;
|
int MAX_MESSAGE_IDS = MAX_RECORD_PAYLOAD_BYTES / UniqueId.LENGTH;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum number of versions of the sync protocol a peer may support
|
||||||
|
* simultaneously.
|
||||||
|
*/
|
||||||
|
int MAX_SUPPORTED_VERSIONS = 10;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,4 +25,7 @@ public interface SyncRecordReader {
|
|||||||
|
|
||||||
Request readRequest() throws IOException;
|
Request readRequest() throws IOException;
|
||||||
|
|
||||||
|
boolean hasVersions() throws IOException;
|
||||||
|
|
||||||
|
Versions readVersions() throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,5 +15,7 @@ public interface SyncRecordWriter {
|
|||||||
|
|
||||||
void writeRequest(Request r) throws IOException;
|
void writeRequest(Request r) throws IOException;
|
||||||
|
|
||||||
|
void writeVersions(Versions v) throws IOException;
|
||||||
|
|
||||||
void flush() throws IOException;
|
void flush() throws IOException;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package org.briarproject.bramble.api.sync;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A record telling the recipient which versions of the sync protocol the
|
||||||
|
* sender supports.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
@NotNullByDefault
|
||||||
|
public class Versions {
|
||||||
|
|
||||||
|
private final List<Byte> supported;
|
||||||
|
|
||||||
|
public Versions(List<Byte> supported) {
|
||||||
|
this.supported = supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Byte> getSupportedVersions() {
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,6 +13,7 @@ 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.Request;
|
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.api.sync.Versions;
|
||||||
import org.briarproject.bramble.util.ByteUtils;
|
import org.briarproject.bramble.util.ByteUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -26,6 +27,8 @@ 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.RecordTypes.VERSIONS;
|
||||||
|
import static org.briarproject.bramble.api.sync.SyncConstants.MAX_SUPPORTED_VERSIONS;
|
||||||
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;
|
||||||
|
|
||||||
@@ -45,7 +48,7 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
|
|
||||||
private static boolean isKnownRecordType(byte type) {
|
private static boolean isKnownRecordType(byte type) {
|
||||||
return type == ACK || type == MESSAGE || type == OFFER ||
|
return type == ACK || type == MESSAGE || type == OFFER ||
|
||||||
type == REQUEST;
|
type == REQUEST || type == VERSIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final MessageFactory messageFactory;
|
private final MessageFactory messageFactory;
|
||||||
@@ -148,4 +151,27 @@ class SyncRecordReaderImpl implements SyncRecordReader {
|
|||||||
if (!hasRequest()) throw new FormatException();
|
if (!hasRequest()) throw new FormatException();
|
||||||
return new Request(readMessageIds());
|
return new Request(readMessageIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasVersions() throws IOException {
|
||||||
|
return !eof() && getNextRecordType() == VERSIONS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Versions readVersions() throws IOException {
|
||||||
|
if (!hasVersions()) throw new FormatException();
|
||||||
|
return new Versions(readSupportedVersions());
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Byte> readSupportedVersions() throws IOException {
|
||||||
|
if (nextRecord == null) throw new AssertionError();
|
||||||
|
byte[] payload = nextRecord.getPayload();
|
||||||
|
if (payload.length == 0) throw new FormatException();
|
||||||
|
if (payload.length > MAX_SUPPORTED_VERSIONS)
|
||||||
|
throw new FormatException();
|
||||||
|
List<Byte> supported = new ArrayList<>(payload.length);
|
||||||
|
for (byte b : payload) supported.add(b);
|
||||||
|
nextRecord = null;
|
||||||
|
return supported;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ 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.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.api.sync.Versions;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -20,6 +21,7 @@ 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.RecordTypes.VERSIONS;
|
||||||
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
import static org.briarproject.bramble.api.sync.SyncConstants.PROTOCOL_VERSION;
|
||||||
|
|
||||||
@NotThreadSafe
|
@NotThreadSafe
|
||||||
@@ -65,6 +67,12 @@ class SyncRecordWriterImpl implements SyncRecordWriter {
|
|||||||
writeRecord(REQUEST);
|
writeRecord(REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void writeVersions(Versions v) throws IOException {
|
||||||
|
for (byte b : v.getSupportedVersions()) payload.write(b);
|
||||||
|
writeRecord(VERSIONS);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
writer.flush();
|
writer.flush();
|
||||||
|
|||||||
@@ -10,11 +10,14 @@ import org.briarproject.bramble.api.sync.MessageFactory;
|
|||||||
import org.briarproject.bramble.api.sync.Offer;
|
import org.briarproject.bramble.api.sync.Offer;
|
||||||
import org.briarproject.bramble.api.sync.Request;
|
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.api.sync.Versions;
|
||||||
import org.briarproject.bramble.test.BrambleMockTestCase;
|
import org.briarproject.bramble.test.BrambleMockTestCase;
|
||||||
import org.jmock.Expectations;
|
import org.jmock.Expectations;
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
@@ -22,7 +25,9 @@ import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTE
|
|||||||
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.RecordTypes.VERSIONS;
|
||||||
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_SUPPORTED_VERSIONS;
|
||||||
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.test.TestUtils.getRandomId;
|
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
@@ -35,12 +40,17 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
context.mock(MessageFactory.class);
|
context.mock(MessageFactory.class);
|
||||||
private final RecordReader recordReader = context.mock(RecordReader.class);
|
private final RecordReader recordReader = context.mock(RecordReader.class);
|
||||||
|
|
||||||
|
private SyncRecordReader reader;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
reader = new SyncRecordReaderImpl(messageFactory, recordReader);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
|
public void testNoFormatExceptionIfAckIsMaximumSize() throws Exception {
|
||||||
expectReadRecord(createAck());
|
expectReadRecord(createAck());
|
||||||
|
|
||||||
SyncRecordReader reader =
|
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
|
||||||
Ack ack = reader.readAck();
|
Ack ack = reader.readAck();
|
||||||
assertEquals(MAX_MESSAGE_IDS, ack.getMessageIds().size());
|
assertEquals(MAX_MESSAGE_IDS, ack.getMessageIds().size());
|
||||||
}
|
}
|
||||||
@@ -49,8 +59,6 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
public void testFormatExceptionIfAckIsEmpty() throws Exception {
|
public void testFormatExceptionIfAckIsEmpty() throws Exception {
|
||||||
expectReadRecord(createEmptyAck());
|
expectReadRecord(createEmptyAck());
|
||||||
|
|
||||||
SyncRecordReader reader =
|
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
|
||||||
reader.readAck();
|
reader.readAck();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,8 +66,6 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception {
|
public void testNoFormatExceptionIfOfferIsMaximumSize() throws Exception {
|
||||||
expectReadRecord(createOffer());
|
expectReadRecord(createOffer());
|
||||||
|
|
||||||
SyncRecordReader reader =
|
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
|
||||||
Offer offer = reader.readOffer();
|
Offer offer = reader.readOffer();
|
||||||
assertEquals(MAX_MESSAGE_IDS, offer.getMessageIds().size());
|
assertEquals(MAX_MESSAGE_IDS, offer.getMessageIds().size());
|
||||||
}
|
}
|
||||||
@@ -68,8 +74,6 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
public void testFormatExceptionIfOfferIsEmpty() throws Exception {
|
public void testFormatExceptionIfOfferIsEmpty() throws Exception {
|
||||||
expectReadRecord(createEmptyOffer());
|
expectReadRecord(createEmptyOffer());
|
||||||
|
|
||||||
SyncRecordReader reader =
|
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
|
||||||
reader.readOffer();
|
reader.readOffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,8 +81,6 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception {
|
public void testNoFormatExceptionIfRequestIsMaximumSize() throws Exception {
|
||||||
expectReadRecord(createRequest());
|
expectReadRecord(createRequest());
|
||||||
|
|
||||||
SyncRecordReader reader =
|
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
|
||||||
Request request = reader.readRequest();
|
Request request = reader.readRequest();
|
||||||
assertEquals(MAX_MESSAGE_IDS, request.getMessageIds().size());
|
assertEquals(MAX_MESSAGE_IDS, request.getMessageIds().size());
|
||||||
}
|
}
|
||||||
@@ -87,11 +89,36 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
public void testFormatExceptionIfRequestIsEmpty() throws Exception {
|
public void testFormatExceptionIfRequestIsEmpty() throws Exception {
|
||||||
expectReadRecord(createEmptyRequest());
|
expectReadRecord(createEmptyRequest());
|
||||||
|
|
||||||
SyncRecordReader reader =
|
|
||||||
new SyncRecordReaderImpl(messageFactory, recordReader);
|
|
||||||
reader.readRequest();
|
reader.readRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoFormatExceptionIfVersionsIsMaximumSize()
|
||||||
|
throws Exception {
|
||||||
|
expectReadRecord(createVersions(MAX_SUPPORTED_VERSIONS));
|
||||||
|
|
||||||
|
Versions versions = reader.readVersions();
|
||||||
|
List<Byte> supported = versions.getSupportedVersions();
|
||||||
|
assertEquals(MAX_SUPPORTED_VERSIONS, supported.size());
|
||||||
|
for (int i = 0; i < supported.size(); i++) {
|
||||||
|
assertEquals(i, (int) supported.get(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testFormatExceptionIfVersionsIsEmpty() throws Exception {
|
||||||
|
expectReadRecord(createVersions(0));
|
||||||
|
|
||||||
|
reader.readVersions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = FormatException.class)
|
||||||
|
public void testFormatExceptionIfVersionsIsTooLarge() throws Exception {
|
||||||
|
expectReadRecord(createVersions(MAX_SUPPORTED_VERSIONS + 1));
|
||||||
|
|
||||||
|
reader.readVersions();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEofReturnsTrueWhenAtEndOfStream() throws Exception {
|
public void testEofReturnsTrueWhenAtEndOfStream() throws Exception {
|
||||||
expectReadRecord(createAck());
|
expectReadRecord(createAck());
|
||||||
@@ -140,6 +167,12 @@ public class SyncRecordReaderImplTest extends BrambleMockTestCase {
|
|||||||
return new Record(PROTOCOL_VERSION, REQUEST, new byte[0]);
|
return new Record(PROTOCOL_VERSION, REQUEST, new byte[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Record createVersions(int numVersions) {
|
||||||
|
byte[] payload = new byte[numVersions];
|
||||||
|
for (int i = 0; i < payload.length; i++) payload[i] = (byte) i;
|
||||||
|
return new Record(PROTOCOL_VERSION, VERSIONS, payload);
|
||||||
|
}
|
||||||
|
|
||||||
private byte[] createPayload() throws Exception {
|
private byte[] createPayload() throws Exception {
|
||||||
ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
ByteArrayOutputStream payload = new ByteArrayOutputStream();
|
||||||
while (payload.size() + UniqueId.LENGTH <= MAX_RECORD_PAYLOAD_BYTES) {
|
while (payload.size() + UniqueId.LENGTH <= MAX_RECORD_PAYLOAD_BYTES) {
|
||||||
|
|||||||
Reference in New Issue
Block a user