mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-19 06:09:55 +01:00
Address review comments
This commit is contained in:
@@ -24,4 +24,5 @@ public interface RecordReader {
|
|||||||
boolean hasRequest() throws IOException;
|
boolean hasRequest() throws IOException;
|
||||||
|
|
||||||
Request readRequest() throws IOException;
|
Request readRequest() throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,15 +17,10 @@ public interface SyncConstants {
|
|||||||
/**
|
/**
|
||||||
* The maximum length of the record payload in bytes.
|
* The maximum length of the record payload in bytes.
|
||||||
*/
|
*/
|
||||||
int MAX_RECORD_PAYLOAD_LENGTH = 32 * 1024; // 32 KiB
|
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. */
|
||||||
int MAX_GROUP_DESCRIPTOR_LENGTH = 32 * 1024; // 32 KiB
|
int MAX_GROUP_DESCRIPTOR_LENGTH = 16 * 1024; // 16 KiB
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum length of a message in bytes.
|
|
||||||
*/
|
|
||||||
int MAX_MESSAGE_LENGTH = MAX_RECORD_PAYLOAD_LENGTH - RECORD_HEADER_LENGTH;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The length of the message header in bytes.
|
* The length of the message header in bytes.
|
||||||
@@ -37,6 +32,11 @@ public interface SyncConstants {
|
|||||||
*/
|
*/
|
||||||
int MAX_MESSAGE_BODY_LENGTH = 32 * 1024; // 32 KiB
|
int MAX_MESSAGE_BODY_LENGTH = 32 * 1024; // 32 KiB
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum length of a message in bytes.
|
||||||
|
*/
|
||||||
|
int MAX_MESSAGE_LENGTH = MESSAGE_HEADER_LENGTH + MAX_MESSAGE_BODY_LENGTH;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -96,37 +96,33 @@ class KeyAgreementTransport {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private byte[] readRecord(byte expectedType) throws AbortException {
|
private byte[] readRecord(byte expectedType) throws AbortException {
|
||||||
byte[] header = readHeader();
|
while (true) {
|
||||||
int len = ByteUtils.readUint16(header,
|
byte[] header = readHeader();
|
||||||
RECORD_HEADER_PAYLOAD_LENGTH_OFFSET);
|
int len = ByteUtils.readUint16(header,
|
||||||
if (header[0] != PROTOCOL_VERSION) {
|
RECORD_HEADER_PAYLOAD_LENGTH_OFFSET);
|
||||||
// ignore record with unknown protocol version and try next
|
if (header[0] != PROTOCOL_VERSION) {
|
||||||
|
throw new AbortException(false);
|
||||||
|
}
|
||||||
|
byte type = header[1];
|
||||||
|
if (type == ABORT) throw new AbortException(true);
|
||||||
|
if (type != expectedType) {
|
||||||
|
if (type != KEY && type != CONFIRM) {
|
||||||
|
// ignore unrecognised record and try next
|
||||||
|
try {
|
||||||
|
readData(len);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new AbortException(e);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
throw new AbortException(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
readData(len);
|
return readData(len);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new AbortException(e);
|
throw new AbortException(e);
|
||||||
}
|
}
|
||||||
return readRecord(expectedType);
|
|
||||||
}
|
|
||||||
byte type = header[1];
|
|
||||||
if (type == ABORT) throw new AbortException(true);
|
|
||||||
if (type != expectedType) {
|
|
||||||
if (type != KEY && type != CONFIRM) {
|
|
||||||
// ignore unrecognised record and try next
|
|
||||||
try {
|
|
||||||
readData(len);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AbortException(e);
|
|
||||||
}
|
|
||||||
return readRecord(expectedType);
|
|
||||||
} else {
|
|
||||||
throw new AbortException(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return readData(len);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new AbortException(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,14 +42,14 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD
|
|||||||
/**
|
/**
|
||||||
* An outgoing {@link SyncSession} suitable for duplex transports. The session
|
* An outgoing {@link SyncSession} suitable for duplex transports. The session
|
||||||
* offers messages before sending them, keeps its output stream open when there
|
* offers messages before sending them, keeps its output stream open when there
|
||||||
* are no packets to send, and reacts to events that make packets available to
|
* are no records to send, and reacts to events that make records available to
|
||||||
* send.
|
* send.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class DuplexOutgoingSession implements SyncSession, EventListener {
|
class DuplexOutgoingSession implements SyncSession, EventListener {
|
||||||
|
|
||||||
// Check for retransmittable packets once every 60 seconds
|
// Check for retransmittable records once every 60 seconds
|
||||||
private static final int RETX_QUERY_INTERVAL = 60 * 1000;
|
private static final int RETX_QUERY_INTERVAL = 60 * 1000;
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(DuplexOutgoingSession.class.getName());
|
Logger.getLogger(DuplexOutgoingSession.class.getName());
|
||||||
@@ -91,7 +91,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
public void run() throws IOException {
|
public void run() throws IOException {
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
try {
|
try {
|
||||||
// Start a query for each type of packet
|
// Start a query for each type of record
|
||||||
dbExecutor.execute(new GenerateAck());
|
dbExecutor.execute(new GenerateAck());
|
||||||
dbExecutor.execute(new GenerateBatch());
|
dbExecutor.execute(new GenerateBatch());
|
||||||
dbExecutor.execute(new GenerateOffer());
|
dbExecutor.execute(new GenerateOffer());
|
||||||
@@ -100,10 +100,10 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
long nextKeepalive = now + maxIdleTime;
|
long nextKeepalive = now + maxIdleTime;
|
||||||
long nextRetxQuery = now + RETX_QUERY_INTERVAL;
|
long nextRetxQuery = now + RETX_QUERY_INTERVAL;
|
||||||
boolean dataToFlush = true;
|
boolean dataToFlush = true;
|
||||||
// Write packets until interrupted
|
// Write records until interrupted
|
||||||
try {
|
try {
|
||||||
while (!interrupted) {
|
while (!interrupted) {
|
||||||
// Work out how long we should wait for a packet
|
// Work out how long we should wait for a record
|
||||||
now = clock.currentTimeMillis();
|
now = clock.currentTimeMillis();
|
||||||
long wait = Math.min(nextKeepalive, nextRetxQuery) - now;
|
long wait = Math.min(nextKeepalive, nextRetxQuery) - now;
|
||||||
if (wait < 0) wait = 0;
|
if (wait < 0) wait = 0;
|
||||||
@@ -113,13 +113,13 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
dataToFlush = false;
|
dataToFlush = false;
|
||||||
nextKeepalive = now + maxIdleTime;
|
nextKeepalive = now + maxIdleTime;
|
||||||
}
|
}
|
||||||
// Wait for a packet
|
// Wait for a record
|
||||||
ThrowingRunnable<IOException> task = writerTasks.poll(wait,
|
ThrowingRunnable<IOException> task = writerTasks.poll(wait,
|
||||||
MILLISECONDS);
|
MILLISECONDS);
|
||||||
if (task == null) {
|
if (task == null) {
|
||||||
now = clock.currentTimeMillis();
|
now = clock.currentTimeMillis();
|
||||||
if (now >= nextRetxQuery) {
|
if (now >= nextRetxQuery) {
|
||||||
// Check for retransmittable packets
|
// Check for retransmittable records
|
||||||
dbExecutor.execute(new GenerateBatch());
|
dbExecutor.execute(new GenerateBatch());
|
||||||
dbExecutor.execute(new GenerateOffer());
|
dbExecutor.execute(new GenerateOffer());
|
||||||
nextRetxQuery = now + RETX_QUERY_INTERVAL;
|
nextRetxQuery = now + RETX_QUERY_INTERVAL;
|
||||||
@@ -139,7 +139,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
}
|
}
|
||||||
if (dataToFlush) recordWriter.flush();
|
if (dataToFlush) recordWriter.flush();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while waiting for a packet to write");
|
LOG.info("Interrupted while waiting for a record to write");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.FormatException;
|
||||||
import org.briarproject.bramble.api.contact.ContactId;
|
import org.briarproject.bramble.api.contact.ContactId;
|
||||||
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
|
||||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||||
@@ -60,7 +61,7 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
public void run() throws IOException {
|
public void run() throws IOException {
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
try {
|
try {
|
||||||
// Read packets until interrupted or EOF
|
// Read records until interrupted or EOF
|
||||||
while (!interrupted && !recordReader.eof()) {
|
while (!interrupted && !recordReader.eof()) {
|
||||||
if (recordReader.hasAck()) {
|
if (recordReader.hasAck()) {
|
||||||
Ack a = recordReader.readAck();
|
Ack a = recordReader.readAck();
|
||||||
@@ -74,8 +75,10 @@ class IncomingSession implements SyncSession, EventListener {
|
|||||||
} else if (recordReader.hasRequest()) {
|
} else if (recordReader.hasRequest()) {
|
||||||
Request r = recordReader.readRequest();
|
Request r = recordReader.readRequest();
|
||||||
dbExecutor.execute(new ReceiveRequest(r));
|
dbExecutor.execute(new ReceiveRequest(r));
|
||||||
|
} else {
|
||||||
|
// unknown records are ignored in RecordReader#eof()
|
||||||
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
// unknown records are ignored
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
eventBus.removeListener(this);
|
eventBus.removeListener(this);
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
package org.briarproject.bramble.sync;
|
package org.briarproject.bramble.sync;
|
||||||
|
|
||||||
import org.briarproject.bramble.api.crypto.CryptoComponent;
|
|
||||||
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
|
||||||
import org.briarproject.bramble.api.sync.MessageFactory;
|
import org.briarproject.bramble.api.sync.MessageFactory;
|
||||||
import org.briarproject.bramble.api.sync.RecordReader;
|
import org.briarproject.bramble.api.sync.RecordReader;
|
||||||
@@ -15,13 +14,10 @@ import javax.inject.Inject;
|
|||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class RecordReaderFactoryImpl implements RecordReaderFactory {
|
class RecordReaderFactoryImpl implements RecordReaderFactory {
|
||||||
|
|
||||||
private final CryptoComponent crypto;
|
|
||||||
private final MessageFactory messageFactory;
|
private final MessageFactory messageFactory;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
RecordReaderFactoryImpl(CryptoComponent crypto,
|
RecordReaderFactoryImpl(MessageFactory messageFactory) {
|
||||||
MessageFactory messageFactory) {
|
|
||||||
this.crypto = crypto;
|
|
||||||
this.messageFactory = messageFactory;
|
this.messageFactory = messageFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -51,32 +51,49 @@ class RecordReaderImpl implements RecordReader {
|
|||||||
|
|
||||||
private void readRecord() throws IOException {
|
private void readRecord() throws IOException {
|
||||||
if (state != State.BUFFER_EMPTY) throw new IllegalStateException();
|
if (state != State.BUFFER_EMPTY) throw new IllegalStateException();
|
||||||
// Read the header
|
while (true) {
|
||||||
int offset = 0;
|
// Read the header
|
||||||
while (offset < RECORD_HEADER_LENGTH) {
|
int offset = 0;
|
||||||
int read = in.read(header, offset, RECORD_HEADER_LENGTH - offset);
|
while (offset < RECORD_HEADER_LENGTH) {
|
||||||
if (read == -1) {
|
int read =
|
||||||
if (offset > 0) throw new FormatException();
|
in.read(header, offset, RECORD_HEADER_LENGTH - offset);
|
||||||
state = State.EOF;
|
if (read == -1) {
|
||||||
|
if (offset > 0) throw new FormatException();
|
||||||
|
state = State.EOF;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
offset += read;
|
||||||
|
}
|
||||||
|
// Check the protocol version
|
||||||
|
if (header[0] != PROTOCOL_VERSION) throw new FormatException();
|
||||||
|
// Read the payload length
|
||||||
|
payloadLength = ByteUtils.readUint16(header, 2);
|
||||||
|
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
|
||||||
|
if (header[1] == ACK || header[1] == MESSAGE ||
|
||||||
|
header[1] == OFFER || header[1] == REQUEST) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
offset += read;
|
|
||||||
}
|
}
|
||||||
// Check the protocol version
|
|
||||||
if (header[0] != PROTOCOL_VERSION) throw new FormatException();
|
|
||||||
// Read the payload length
|
|
||||||
payloadLength = ByteUtils.readUint16(header, 2);
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The return value indicates whether there's another record available
|
||||||
|
* or whether we've reached the end of the input stream.
|
||||||
|
* If a record is available,
|
||||||
|
* it's been read into the buffer by the time eof() returns,
|
||||||
|
* so the method that called eof() can access the record from the buffer,
|
||||||
|
* for example to check its type or extract its payload.
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean eof() throws IOException {
|
public boolean eof() throws IOException {
|
||||||
if (state == State.BUFFER_EMPTY) readRecord();
|
if (state == State.BUFFER_EMPTY) readRecord();
|
||||||
@@ -153,4 +170,5 @@ class RecordReaderImpl implements RecordReader {
|
|||||||
if (!hasRequest()) throw new FormatException();
|
if (!hasRequest()) throw new FormatException();
|
||||||
return new Request(readMessageIds());
|
return new Request(readMessageIds());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ import static org.briarproject.bramble.api.sync.SyncConstants.MAX_RECORD_PAYLOAD
|
|||||||
/**
|
/**
|
||||||
* An outgoing {@link SyncSession} suitable for simplex transports. The session
|
* An outgoing {@link SyncSession} suitable for simplex transports. The session
|
||||||
* sends messages without offering them first, and closes its output stream
|
* sends messages without offering them first, and closes its output stream
|
||||||
* when there are no more packets to send.
|
* when there are no more records to send.
|
||||||
*/
|
*/
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
@@ -70,7 +70,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
this.contactId = contactId;
|
this.contactId = contactId;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.recordWriter = recordWriter;
|
this.recordWriter = recordWriter;
|
||||||
outstandingQueries = new AtomicInteger(2); // One per type of packet
|
outstandingQueries = new AtomicInteger(2); // One per type of record
|
||||||
writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>();
|
writerTasks = new LinkedBlockingQueue<ThrowingRunnable<IOException>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,10 +79,10 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
public void run() throws IOException {
|
public void run() throws IOException {
|
||||||
eventBus.addListener(this);
|
eventBus.addListener(this);
|
||||||
try {
|
try {
|
||||||
// Start a query for each type of packet
|
// Start a query for each type of record
|
||||||
dbExecutor.execute(new GenerateAck());
|
dbExecutor.execute(new GenerateAck());
|
||||||
dbExecutor.execute(new GenerateBatch());
|
dbExecutor.execute(new GenerateBatch());
|
||||||
// Write packets until interrupted or no more packets to write
|
// Write records until interrupted or no more records to write
|
||||||
try {
|
try {
|
||||||
while (!interrupted) {
|
while (!interrupted) {
|
||||||
ThrowingRunnable<IOException> task = writerTasks.take();
|
ThrowingRunnable<IOException> task = writerTasks.take();
|
||||||
@@ -91,7 +91,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener {
|
|||||||
}
|
}
|
||||||
recordWriter.flush();
|
recordWriter.flush();
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
LOG.info("Interrupted while waiting for a packet to write");
|
LOG.info("Interrupted while waiting for a record to write");
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -40,9 +40,9 @@ public class SyncModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
RecordReaderFactory provideRecordReaderFactory(CryptoComponent crypto,
|
RecordReaderFactory provideRecordReaderFactory(
|
||||||
MessageFactory messageFactory) {
|
RecordReaderFactoryImpl recordReaderFactory) {
|
||||||
return new RecordReaderFactoryImpl(crypto, messageFactory);
|
return recordReaderFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
|||||||
Reference in New Issue
Block a user