diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/record/Record.java b/bramble-api/src/main/java/org/briarproject/bramble/api/record/Record.java new file mode 100644 index 0000000000000000000000000000000000000000..fedb7212c2ad75dd35fea5b7e1799a2b81022f67 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/record/Record.java @@ -0,0 +1,36 @@ +package org.briarproject.bramble.api.record; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class Record { + + public static final int RECORD_HEADER_BYTES = 4; + public static final int MAX_RECORD_PAYLOAD_BYTES = 48 * 1024; // 48 KiB + + private final byte protocolVersion, recordType; + private final byte[] payload; + + public Record(byte protocolVersion, byte recordType, byte[] payload) { + if (payload.length > MAX_RECORD_PAYLOAD_BYTES) + throw new IllegalArgumentException(); + this.protocolVersion = protocolVersion; + this.recordType = recordType; + this.payload = payload; + } + + public byte getProtocolVersion() { + return protocolVersion; + } + + public byte getRecordType() { + return recordType; + } + + public byte[] getPayload() { + return payload; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordReader.java b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordReader.java new file mode 100644 index 0000000000000000000000000000000000000000..371dead2025f40a1dc5e4fc8f7f6b15d5f76cc45 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordReader.java @@ -0,0 +1,20 @@ +package org.briarproject.bramble.api.record; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.io.EOFException; +import java.io.IOException; + +@NotNullByDefault +public interface RecordReader { + + /** + * Reads and returns the next record. + * + * @throws EOFException if the end of the stream is reached without reading + * a complete record + */ + Record readRecord() throws IOException; + + void close() throws IOException; +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordReaderFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordReaderFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..17588eaed2d17871b86b8f15de8b7847a97b01d7 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordReaderFactory.java @@ -0,0 +1,8 @@ +package org.briarproject.bramble.api.record; + +import java.io.InputStream; + +public interface RecordReaderFactory { + + RecordReader createRecordReader(InputStream in); +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordWriter.java b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..eb83d4d410ae358e2978f8557980cc82600b0a57 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordWriter.java @@ -0,0 +1,15 @@ +package org.briarproject.bramble.api.record; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.io.IOException; + +@NotNullByDefault +public interface RecordWriter { + + void writeRecord(Record r) throws IOException; + + void flush() throws IOException; + + void close() throws IOException; +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordWriterFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordWriterFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..2713bb4febad77a8363ca2286782b2b44d457547 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/record/RecordWriterFactory.java @@ -0,0 +1,8 @@ +package org.briarproject.bramble.api.record; + +import java.io.OutputStream; + +public interface RecordWriterFactory { + + RecordWriter createRecordWriter(OutputStream out); +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/record/RecordModule.java b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordModule.java new file mode 100644 index 0000000000000000000000000000000000000000..54dd4587c3285be5f575051faf89fc6af5aa1212 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordModule.java @@ -0,0 +1,21 @@ +package org.briarproject.bramble.record; + +import org.briarproject.bramble.api.record.RecordReaderFactory; +import org.briarproject.bramble.api.record.RecordWriterFactory; + +import dagger.Module; +import dagger.Provides; + +@Module +public class RecordModule { + + @Provides + RecordReaderFactory provideRecordReaderFactory() { + return new RecordReaderFactoryImpl(); + } + + @Provides + RecordWriterFactory provideRecordWriterFactory() { + return new RecordWriterFactoryImpl(); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/record/RecordReaderFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordReaderFactoryImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..f8b89d8883a5cb601627dc4df4c790791a9803ce --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordReaderFactoryImpl.java @@ -0,0 +1,14 @@ +package org.briarproject.bramble.record; + +import org.briarproject.bramble.api.record.RecordReader; +import org.briarproject.bramble.api.record.RecordReaderFactory; + +import java.io.InputStream; + +class RecordReaderFactoryImpl implements RecordReaderFactory { + + @Override + public RecordReader createRecordReader(InputStream in) { + return new RecordReaderImpl(in); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/record/RecordReaderImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordReaderImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..92fb696ae54eae284083b10a2dcf37864ed206dd --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordReaderImpl.java @@ -0,0 +1,43 @@ +package org.briarproject.bramble.record; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.record.Record; +import org.briarproject.bramble.api.record.RecordReader; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.InputStream; + +import javax.annotation.concurrent.NotThreadSafe; + +import static org.briarproject.bramble.api.record.Record.MAX_RECORD_PAYLOAD_BYTES; + +@NotThreadSafe +@NotNullByDefault +class RecordReaderImpl implements RecordReader { + + private final DataInputStream in; + + RecordReaderImpl(InputStream in) { + this.in = new DataInputStream(new BufferedInputStream(in, 1024)); + } + + @Override + public Record readRecord() throws IOException { + byte protocolVersion = in.readByte(); + byte recordType = in.readByte(); + int payloadLength = in.readShort() & 0xFFFF; // Convert to unsigned + if (payloadLength < 0 || payloadLength > MAX_RECORD_PAYLOAD_BYTES) + throw new FormatException(); + byte[] payload = new byte[payloadLength]; + in.readFully(payload); + return new Record(protocolVersion, recordType, payload); + } + + @Override + public void close() throws IOException { + in.close(); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/record/RecordWriterFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordWriterFactoryImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..a20742423478c335e1708acdccdf54ad4bf16cc2 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordWriterFactoryImpl.java @@ -0,0 +1,14 @@ +package org.briarproject.bramble.record; + +import org.briarproject.bramble.api.record.RecordWriter; +import org.briarproject.bramble.api.record.RecordWriterFactory; + +import java.io.OutputStream; + +class RecordWriterFactoryImpl implements RecordWriterFactory { + + @Override + public RecordWriter createRecordWriter(OutputStream out) { + return new RecordWriterImpl(out); + } +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/record/RecordWriterImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordWriterImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..281b3c6382c1257e48140dbdaa83c3afe168a461 --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/record/RecordWriterImpl.java @@ -0,0 +1,42 @@ +package org.briarproject.bramble.record; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.record.Record; +import org.briarproject.bramble.api.record.RecordWriter; + +import java.io.BufferedOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.annotation.concurrent.NotThreadSafe; + +@NotThreadSafe +@NotNullByDefault +class RecordWriterImpl implements RecordWriter { + + private final DataOutputStream out; + + RecordWriterImpl(OutputStream out) { + this.out = new DataOutputStream(new BufferedOutputStream(out, 1024)); + } + + @Override + public void writeRecord(Record r) throws IOException { + out.write(r.getProtocolVersion()); + out.write(r.getRecordType()); + byte[] payload = r.getPayload(); + out.writeShort(payload.length); + out.write(payload); + } + + @Override + public void flush() throws IOException { + out.flush(); + } + + @Override + public void close() throws IOException { + out.close(); + } +}