mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 12:49:55 +01:00
Moved the messaging protocol one step closer to BSP.
This breaks backward compatibility for the wire protocol and messages stored in the database. The database schema version has been incremented.
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="org.briarproject"
|
package="org.briarproject"
|
||||||
android:versionCode="9"
|
android:versionCode="10"
|
||||||
android:versionName="0.9" >
|
android:versionName="0.10" >
|
||||||
|
|
||||||
<uses-sdk
|
<uses-sdk
|
||||||
android:minSdkVersion="7"
|
android:minSdkVersion="7"
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
package org.briarproject.api.messaging;
|
package org.briarproject.api.messaging;
|
||||||
|
|
||||||
import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH;
|
|
||||||
|
|
||||||
public interface MessagingConstants {
|
public interface MessagingConstants {
|
||||||
|
|
||||||
/**
|
/** The current version of the messaging protocol. */
|
||||||
* The maximum length of a serialised packet in bytes. To allow for future
|
byte PROTOCOL_VERSION = 0;
|
||||||
* changes in the protocol, this is smaller than the minimum stream length
|
|
||||||
* minus the maximum encryption and authentication overhead.
|
/** The length of the packet header in bytes. */
|
||||||
*/
|
int HEADER_LENGTH = 4;
|
||||||
int MAX_PACKET_LENGTH = MIN_STREAM_LENGTH / 2;
|
|
||||||
|
/** The maximum length of the packet payload in bytes. */
|
||||||
|
int MAX_PAYLOAD_LENGTH = 32 * 1024; // 32 KiB
|
||||||
|
|
||||||
/** The maximum number of public groups a user may subscribe to. */
|
/** The maximum number of public groups a user may subscribe to. */
|
||||||
int MAX_SUBSCRIPTIONS = 3000;
|
int MAX_SUBSCRIPTIONS = 300;
|
||||||
|
|
||||||
/** The maximum length of a group's name in UTF-8 bytes. */
|
/** The maximum length of a group's name in UTF-8 bytes. */
|
||||||
int MAX_GROUP_NAME_LENGTH = 50;
|
int MAX_GROUP_NAME_LENGTH = 50;
|
||||||
@@ -22,10 +23,10 @@ public interface MessagingConstants {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* The maximum length of a message body in bytes. To allow for future
|
* The maximum length of a message body in bytes. To allow for future
|
||||||
* changes in the protocol, this is smaller than the maximum packet length
|
* changes in the protocol, this is smaller than the maximum payload length
|
||||||
* even when all the message's other fields have their maximum lengths.
|
* even when all the message's other fields have their maximum lengths.
|
||||||
*/
|
*/
|
||||||
int MAX_BODY_LENGTH = MAX_PACKET_LENGTH - 1024;
|
int MAX_BODY_LENGTH = MAX_PAYLOAD_LENGTH - 1024;
|
||||||
|
|
||||||
/** The maximum length of a message's content type in UTF-8 bytes. */
|
/** The maximum length of a message's content type in UTF-8 bytes. */
|
||||||
int MAX_CONTENT_TYPE_LENGTH = 50;
|
int MAX_CONTENT_TYPE_LENGTH = 50;
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.briarproject.api.messaging;
|
||||||
|
|
||||||
|
/** Packet types for the messaging protocol. */
|
||||||
|
public interface PacketTypes {
|
||||||
|
|
||||||
|
byte ACK = 0;
|
||||||
|
byte MESSAGE = 1;
|
||||||
|
byte OFFER = 2;
|
||||||
|
byte REQUEST = 3;
|
||||||
|
byte RETENTION_ACK = 4;
|
||||||
|
byte RETENTION_UPDATE = 5;
|
||||||
|
byte SUBSCRIPTION_ACK = 6;
|
||||||
|
byte SUBSCRIPTION_UPDATE = 7;
|
||||||
|
byte TRANSPORT_ACK = 8;
|
||||||
|
byte TRANSPORT_UPDATE = 9;
|
||||||
|
}
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
package org.briarproject.api.messaging;
|
|
||||||
|
|
||||||
/** Struct identifiers for encoding and decoding protocol objects. */
|
|
||||||
public interface Types {
|
|
||||||
|
|
||||||
int AUTHOR = 0;
|
|
||||||
int GROUP = 1;
|
|
||||||
int ACK = 2;
|
|
||||||
int MESSAGE = 3;
|
|
||||||
int OFFER = 4;
|
|
||||||
int REQUEST = 5;
|
|
||||||
int RETENTION_ACK = 6;
|
|
||||||
int RETENTION_UPDATE = 7;
|
|
||||||
int SUBSCRIPTION_ACK = 8;
|
|
||||||
int SUBSCRIPTION_UPDATE = 9;
|
|
||||||
int TRANSPORT_ACK = 10;
|
|
||||||
int TRANSPORT_UPDATE = 11;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
package org.briarproject.api.serial;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
public interface ObjectReader<T> {
|
||||||
|
|
||||||
|
T readObject(Reader r) throws IOException;
|
||||||
|
}
|
||||||
@@ -10,6 +10,10 @@ public interface Reader {
|
|||||||
void addConsumer(Consumer c);
|
void addConsumer(Consumer c);
|
||||||
void removeConsumer(Consumer c);
|
void removeConsumer(Consumer c);
|
||||||
|
|
||||||
|
boolean hasNull() throws IOException;
|
||||||
|
void readNull() throws IOException;
|
||||||
|
void skipNull() throws IOException;
|
||||||
|
|
||||||
boolean hasBoolean() throws IOException;
|
boolean hasBoolean() throws IOException;
|
||||||
boolean readBoolean() throws IOException;
|
boolean readBoolean() throws IOException;
|
||||||
void skipBoolean() throws IOException;
|
void skipBoolean() throws IOException;
|
||||||
@@ -24,11 +28,11 @@ public interface Reader {
|
|||||||
|
|
||||||
boolean hasString() throws IOException;
|
boolean hasString() throws IOException;
|
||||||
String readString(int maxLength) throws IOException;
|
String readString(int maxLength) throws IOException;
|
||||||
void skipString(int maxLength) throws IOException;
|
void skipString() throws IOException;
|
||||||
|
|
||||||
boolean hasBytes() throws IOException;
|
boolean hasBytes() throws IOException;
|
||||||
byte[] readBytes(int maxLength) throws IOException;
|
byte[] readBytes(int maxLength) throws IOException;
|
||||||
void skipBytes(int maxLength) throws IOException;
|
void skipBytes() throws IOException;
|
||||||
|
|
||||||
boolean hasList() throws IOException;
|
boolean hasList() throws IOException;
|
||||||
void readListStart() throws IOException;
|
void readListStart() throws IOException;
|
||||||
@@ -41,15 +45,4 @@ public interface Reader {
|
|||||||
boolean hasMapEnd() throws IOException;
|
boolean hasMapEnd() throws IOException;
|
||||||
void readMapEnd() throws IOException;
|
void readMapEnd() throws IOException;
|
||||||
void skipMap() throws IOException;
|
void skipMap() throws IOException;
|
||||||
|
|
||||||
boolean hasStruct() throws IOException;
|
|
||||||
boolean hasStruct(int id) throws IOException;
|
|
||||||
void readStructStart(int id) throws IOException;
|
|
||||||
boolean hasStructEnd() throws IOException;
|
|
||||||
void readStructEnd() throws IOException;
|
|
||||||
void skipStruct() throws IOException;
|
|
||||||
|
|
||||||
boolean hasNull() throws IOException;
|
|
||||||
void readNull() throws IOException;
|
|
||||||
void skipNull() throws IOException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,9 +6,5 @@ public interface SerialComponent {
|
|||||||
|
|
||||||
int getSerialisedListEndLength();
|
int getSerialisedListEndLength();
|
||||||
|
|
||||||
int getSerialisedStructStartLength(int id);
|
|
||||||
|
|
||||||
int getSerialisedStructEndLength();
|
|
||||||
|
|
||||||
int getSerialisedUniqueIdLength();
|
int getSerialisedUniqueIdLength();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
package org.briarproject.api.serial;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public interface StructReader<T> {
|
|
||||||
|
|
||||||
T readStruct(Reader r) throws IOException;
|
|
||||||
}
|
|
||||||
@@ -12,6 +12,7 @@ public interface Writer {
|
|||||||
void addConsumer(Consumer c);
|
void addConsumer(Consumer c);
|
||||||
void removeConsumer(Consumer c);
|
void removeConsumer(Consumer c);
|
||||||
|
|
||||||
|
void writeNull() throws IOException;
|
||||||
void writeBoolean(boolean b) throws IOException;
|
void writeBoolean(boolean b) throws IOException;
|
||||||
void writeInteger(long l) throws IOException;
|
void writeInteger(long l) throws IOException;
|
||||||
void writeFloat(double d) throws IOException;
|
void writeFloat(double d) throws IOException;
|
||||||
@@ -25,9 +26,4 @@ public interface Writer {
|
|||||||
void writeMap(Map<?, ?> m) throws IOException;
|
void writeMap(Map<?, ?> m) throws IOException;
|
||||||
void writeMapStart() throws IOException;
|
void writeMapStart() throws IOException;
|
||||||
void writeMapEnd() throws IOException;
|
void writeMapEnd() throws IOException;
|
||||||
|
|
||||||
void writeStructStart(int id) throws IOException;
|
|
||||||
void writeStructEnd() throws IOException;
|
|
||||||
|
|
||||||
void writeNull() throws IOException;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ public interface TransportConstants {
|
|||||||
* support. Streams may be shorter than this length, but all transport
|
* support. Streams may be shorter than this length, but all transport
|
||||||
* plugins must support streams of at least this length.
|
* plugins must support streams of at least this length.
|
||||||
*/
|
*/
|
||||||
int MIN_STREAM_LENGTH = 1024 * 1024; // 2^20, 1 MiB
|
int MIN_STREAM_LENGTH = 64 * 1024; // 64 KiB
|
||||||
|
|
||||||
/** The maximum difference between two communicating devices' clocks. */
|
/** The maximum difference between two communicating devices' clocks. */
|
||||||
int MAX_CLOCK_DIFFERENCE = 60 * 60 * 1000; // 1 hour
|
int MAX_CLOCK_DIFFERENCE = 60 * 60 * 1000; // 1 hour
|
||||||
|
|||||||
@@ -64,8 +64,8 @@ import org.briarproject.api.transport.TemporarySecret;
|
|||||||
*/
|
*/
|
||||||
abstract class JdbcDatabase implements Database<Connection> {
|
abstract class JdbcDatabase implements Database<Connection> {
|
||||||
|
|
||||||
private static final int SCHEMA_VERSION = 8;
|
private static final int SCHEMA_VERSION = 9;
|
||||||
private static final int MIN_SCHEMA_VERSION = 8;
|
private static final int MIN_SCHEMA_VERSION = 9;
|
||||||
|
|
||||||
private static final String CREATE_SETTINGS =
|
private static final String CREATE_SETTINGS =
|
||||||
"CREATE TABLE settings"
|
"CREATE TABLE settings"
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package org.briarproject.messaging;
|
package org.briarproject.messaging;
|
||||||
|
|
||||||
import static org.briarproject.api.messaging.Types.AUTHOR;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -45,10 +43,10 @@ class AuthorFactoryImpl implements AuthorFactory {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
try {
|
try {
|
||||||
w.writeStructStart(AUTHOR);
|
w.writeListStart();
|
||||||
w.writeString(name);
|
w.writeString(name);
|
||||||
w.writeBytes(publicKey);
|
w.writeBytes(publicKey);
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
// Shouldn't happen with ByteArrayOutputStream
|
// Shouldn't happen with ByteArrayOutputStream
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.messaging;
|
|||||||
|
|
||||||
import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
import static org.briarproject.api.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||||
import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.AUTHOR;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -13,9 +12,9 @@ import org.briarproject.api.crypto.CryptoComponent;
|
|||||||
import org.briarproject.api.crypto.MessageDigest;
|
import org.briarproject.api.crypto.MessageDigest;
|
||||||
import org.briarproject.api.serial.DigestingConsumer;
|
import org.briarproject.api.serial.DigestingConsumer;
|
||||||
import org.briarproject.api.serial.Reader;
|
import org.briarproject.api.serial.Reader;
|
||||||
import org.briarproject.api.serial.StructReader;
|
import org.briarproject.api.serial.ObjectReader;
|
||||||
|
|
||||||
class AuthorReader implements StructReader<Author> {
|
class AuthorReader implements ObjectReader<Author> {
|
||||||
|
|
||||||
private final MessageDigest messageDigest;
|
private final MessageDigest messageDigest;
|
||||||
|
|
||||||
@@ -23,16 +22,16 @@ class AuthorReader implements StructReader<Author> {
|
|||||||
messageDigest = crypto.getMessageDigest();
|
messageDigest = crypto.getMessageDigest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Author readStruct(Reader r) throws IOException {
|
public Author readObject(Reader r) throws IOException {
|
||||||
// Set up the reader
|
// Set up the reader
|
||||||
DigestingConsumer digesting = new DigestingConsumer(messageDigest);
|
DigestingConsumer digesting = new DigestingConsumer(messageDigest);
|
||||||
r.addConsumer(digesting);
|
r.addConsumer(digesting);
|
||||||
// Read and digest the data
|
// Read and digest the data
|
||||||
r.readStructStart(AUTHOR);
|
r.readListStart();
|
||||||
String name = r.readString(MAX_AUTHOR_NAME_LENGTH);
|
String name = r.readString(MAX_AUTHOR_NAME_LENGTH);
|
||||||
if(name.length() == 0) throw new FormatException();
|
if(name.length() == 0) throw new FormatException();
|
||||||
byte[] publicKey = r.readBytes(MAX_PUBLIC_KEY_LENGTH);
|
byte[] publicKey = r.readBytes(MAX_PUBLIC_KEY_LENGTH);
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
// Reset the reader
|
// Reset the reader
|
||||||
r.removeConsumer(digesting);
|
r.removeConsumer(digesting);
|
||||||
// Build and return the author
|
// Build and return the author
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ package org.briarproject.messaging;
|
|||||||
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
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.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -260,7 +260,7 @@ class DuplexOutgoingSession implements MessagingSession, EventListener {
|
|||||||
if(interrupted) return;
|
if(interrupted) return;
|
||||||
try {
|
try {
|
||||||
Collection<byte[]> b = db.generateRequestedBatch(contactId,
|
Collection<byte[]> b = db.generateRequestedBatch(contactId,
|
||||||
MAX_PACKET_LENGTH, maxLatency);
|
MAX_PAYLOAD_LENGTH, maxLatency);
|
||||||
if(LOG.isLoggable(INFO))
|
if(LOG.isLoggable(INFO))
|
||||||
LOG.info("Generated batch: " + (b != null));
|
LOG.info("Generated batch: " + (b != null));
|
||||||
if(b != null) writerTasks.add(new WriteBatch(b));
|
if(b != null) writerTasks.add(new WriteBatch(b));
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package org.briarproject.messaging;
|
package org.briarproject.messaging;
|
||||||
|
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.GROUP;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -37,10 +36,10 @@ class GroupFactoryImpl implements GroupFactory {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
try {
|
try {
|
||||||
w.writeStructStart(GROUP);
|
w.writeListStart();
|
||||||
w.writeString(name);
|
w.writeString(name);
|
||||||
w.writeBytes(salt);
|
w.writeBytes(salt);
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
// Shouldn't happen with ByteArrayOutputStream
|
// Shouldn't happen with ByteArrayOutputStream
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package org.briarproject.messaging;
|
|||||||
|
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_GROUP_NAME_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_GROUP_NAME_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.GROUP;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -13,9 +12,9 @@ import org.briarproject.api.messaging.Group;
|
|||||||
import org.briarproject.api.messaging.GroupId;
|
import org.briarproject.api.messaging.GroupId;
|
||||||
import org.briarproject.api.serial.DigestingConsumer;
|
import org.briarproject.api.serial.DigestingConsumer;
|
||||||
import org.briarproject.api.serial.Reader;
|
import org.briarproject.api.serial.Reader;
|
||||||
import org.briarproject.api.serial.StructReader;
|
import org.briarproject.api.serial.ObjectReader;
|
||||||
|
|
||||||
class GroupReader implements StructReader<Group> {
|
class GroupReader implements ObjectReader<Group> {
|
||||||
|
|
||||||
private final MessageDigest messageDigest;
|
private final MessageDigest messageDigest;
|
||||||
|
|
||||||
@@ -23,16 +22,16 @@ class GroupReader implements StructReader<Group> {
|
|||||||
messageDigest = crypto.getMessageDigest();
|
messageDigest = crypto.getMessageDigest();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Group readStruct(Reader r) throws IOException {
|
public Group readObject(Reader r) throws IOException {
|
||||||
DigestingConsumer digesting = new DigestingConsumer(messageDigest);
|
DigestingConsumer digesting = new DigestingConsumer(messageDigest);
|
||||||
// Read and digest the data
|
// Read and digest the data
|
||||||
r.addConsumer(digesting);
|
r.addConsumer(digesting);
|
||||||
r.readStructStart(GROUP);
|
r.readListStart();
|
||||||
String name = r.readString(MAX_GROUP_NAME_LENGTH);
|
String name = r.readString(MAX_GROUP_NAME_LENGTH);
|
||||||
if(name.length() == 0) throw new FormatException();
|
if(name.length() == 0) throw new FormatException();
|
||||||
byte[] salt = r.readBytes(GROUP_SALT_LENGTH);
|
byte[] salt = r.readBytes(GROUP_SALT_LENGTH);
|
||||||
if(salt.length != GROUP_SALT_LENGTH) throw new FormatException();
|
if(salt.length != GROUP_SALT_LENGTH) throw new FormatException();
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
r.removeConsumer(digesting);
|
r.removeConsumer(digesting);
|
||||||
// Build and return the group
|
// Build and return the group
|
||||||
GroupId id = new GroupId(messageDigest.digest());
|
GroupId id = new GroupId(messageDigest.digest());
|
||||||
|
|||||||
@@ -3,11 +3,8 @@ package org.briarproject.messaging;
|
|||||||
import static org.briarproject.api.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
import static org.briarproject.api.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MESSAGE_SALT_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MESSAGE_SALT_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.AUTHOR;
|
|
||||||
import static org.briarproject.api.messaging.Types.GROUP;
|
|
||||||
import static org.briarproject.api.messaging.Types.MESSAGE;
|
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -77,7 +74,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
// Initialise the consumers
|
// Initialise the consumers
|
||||||
CountingConsumer counting = new CountingConsumer(MAX_PACKET_LENGTH);
|
CountingConsumer counting = new CountingConsumer(MAX_PAYLOAD_LENGTH);
|
||||||
w.addConsumer(counting);
|
w.addConsumer(counting);
|
||||||
Consumer digestingConsumer = new DigestingConsumer(messageDigest);
|
Consumer digestingConsumer = new DigestingConsumer(messageDigest);
|
||||||
w.addConsumer(digestingConsumer);
|
w.addConsumer(digestingConsumer);
|
||||||
@@ -88,7 +85,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
w.addConsumer(signingConsumer);
|
w.addConsumer(signingConsumer);
|
||||||
}
|
}
|
||||||
// Write the message
|
// Write the message
|
||||||
w.writeStructStart(MESSAGE);
|
w.writeListStart();
|
||||||
if(parent == null) w.writeNull();
|
if(parent == null) w.writeNull();
|
||||||
else w.writeBytes(parent.getBytes());
|
else w.writeBytes(parent.getBytes());
|
||||||
writeGroup(w, group);
|
writeGroup(w, group);
|
||||||
@@ -111,7 +108,7 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
throw new IllegalArgumentException();
|
throw new IllegalArgumentException();
|
||||||
w.writeBytes(sig);
|
w.writeBytes(sig);
|
||||||
}
|
}
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
// Hash the message, including the signature, to get the message ID
|
// Hash the message, including the signature, to get the message ID
|
||||||
w.removeConsumer(digestingConsumer);
|
w.removeConsumer(digestingConsumer);
|
||||||
MessageId id = new MessageId(messageDigest.digest());
|
MessageId id = new MessageId(messageDigest.digest());
|
||||||
@@ -120,16 +117,16 @@ class MessageFactoryImpl implements MessageFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void writeGroup(Writer w, Group g) throws IOException {
|
private void writeGroup(Writer w, Group g) throws IOException {
|
||||||
w.writeStructStart(GROUP);
|
w.writeListStart();
|
||||||
w.writeString(g.getName());
|
w.writeString(g.getName());
|
||||||
w.writeBytes(g.getSalt());
|
w.writeBytes(g.getSalt());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeAuthor(Writer w, Author a) throws IOException {
|
private void writeAuthor(Writer w, Author a) throws IOException {
|
||||||
w.writeStructStart(AUTHOR);
|
w.writeListStart();
|
||||||
w.writeString(a.getName());
|
w.writeString(a.getName());
|
||||||
w.writeBytes(a.getPublicKey());
|
w.writeBytes(a.getPublicKey());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,8 @@ package org.briarproject.messaging;
|
|||||||
import static org.briarproject.api.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
import static org.briarproject.api.AuthorConstants.MAX_SIGNATURE_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MESSAGE_SALT_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MESSAGE_SALT_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.MESSAGE;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
@@ -17,27 +16,27 @@ import org.briarproject.api.messaging.MessageId;
|
|||||||
import org.briarproject.api.messaging.UnverifiedMessage;
|
import org.briarproject.api.messaging.UnverifiedMessage;
|
||||||
import org.briarproject.api.serial.CopyingConsumer;
|
import org.briarproject.api.serial.CopyingConsumer;
|
||||||
import org.briarproject.api.serial.CountingConsumer;
|
import org.briarproject.api.serial.CountingConsumer;
|
||||||
|
import org.briarproject.api.serial.ObjectReader;
|
||||||
import org.briarproject.api.serial.Reader;
|
import org.briarproject.api.serial.Reader;
|
||||||
import org.briarproject.api.serial.StructReader;
|
|
||||||
|
|
||||||
class MessageReader implements StructReader<UnverifiedMessage> {
|
class MessageReader implements ObjectReader<UnverifiedMessage> {
|
||||||
|
|
||||||
private final StructReader<Group> groupReader;
|
private final ObjectReader<Group> groupReader;
|
||||||
private final StructReader<Author> authorReader;
|
private final ObjectReader<Author> authorReader;
|
||||||
|
|
||||||
MessageReader(StructReader<Group> groupReader,
|
MessageReader(ObjectReader<Group> groupReader,
|
||||||
StructReader<Author> authorReader) {
|
ObjectReader<Author> authorReader) {
|
||||||
this.groupReader = groupReader;
|
this.groupReader = groupReader;
|
||||||
this.authorReader = authorReader;
|
this.authorReader = authorReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnverifiedMessage readStruct(Reader r) throws IOException {
|
public UnverifiedMessage readObject(Reader r) throws IOException {
|
||||||
CopyingConsumer copying = new CopyingConsumer();
|
CopyingConsumer copying = new CopyingConsumer();
|
||||||
CountingConsumer counting = new CountingConsumer(MAX_PACKET_LENGTH);
|
CountingConsumer counting = new CountingConsumer(MAX_PAYLOAD_LENGTH);
|
||||||
r.addConsumer(copying);
|
r.addConsumer(copying);
|
||||||
r.addConsumer(counting);
|
r.addConsumer(counting);
|
||||||
// Read the start of the struct
|
// Read the start of the message
|
||||||
r.readStructStart(MESSAGE);
|
r.readListStart();
|
||||||
// Read the parent's message ID, if there is one
|
// Read the parent's message ID, if there is one
|
||||||
MessageId parent = null;
|
MessageId parent = null;
|
||||||
if(r.hasNull()) {
|
if(r.hasNull()) {
|
||||||
@@ -48,11 +47,11 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
|||||||
parent = new MessageId(b);
|
parent = new MessageId(b);
|
||||||
}
|
}
|
||||||
// Read the group
|
// Read the group
|
||||||
Group group = groupReader.readStruct(r);
|
Group group = groupReader.readObject(r);
|
||||||
// Read the author, if there is one
|
// Read the author, if there is one
|
||||||
Author author = null;
|
Author author = null;
|
||||||
if(r.hasNull()) r.readNull();
|
if(r.hasNull()) r.readNull();
|
||||||
else author = authorReader.readStruct(r);
|
else author = authorReader.readObject(r);
|
||||||
// Read the content type
|
// Read the content type
|
||||||
String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH);
|
String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH);
|
||||||
// Read the timestamp
|
// Read the timestamp
|
||||||
@@ -71,11 +70,12 @@ class MessageReader implements StructReader<UnverifiedMessage> {
|
|||||||
byte[] signature = null;
|
byte[] signature = null;
|
||||||
if(author == null) r.readNull();
|
if(author == null) r.readNull();
|
||||||
else signature = r.readBytes(MAX_SIGNATURE_LENGTH);
|
else signature = r.readBytes(MAX_SIGNATURE_LENGTH);
|
||||||
// Read the end of the struct
|
// Read the end of the message
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
// The signature will be verified later
|
// Reset the reader
|
||||||
r.removeConsumer(counting);
|
r.removeConsumer(counting);
|
||||||
r.removeConsumer(copying);
|
r.removeConsumer(copying);
|
||||||
|
// Build and return the unverified message
|
||||||
byte[] raw = copying.getCopy();
|
byte[] raw = copying.getCopy();
|
||||||
return new UnverifiedMessage(parent, group, author, contentType,
|
return new UnverifiedMessage(parent, group, author, contentType,
|
||||||
timestamp, raw, signature, bodyStart, body.length,
|
timestamp, raw, signature, bodyStart, body.length,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import org.briarproject.api.messaging.PacketReaderFactory;
|
|||||||
import org.briarproject.api.messaging.PacketWriterFactory;
|
import org.briarproject.api.messaging.PacketWriterFactory;
|
||||||
import org.briarproject.api.messaging.SubscriptionUpdate;
|
import org.briarproject.api.messaging.SubscriptionUpdate;
|
||||||
import org.briarproject.api.messaging.UnverifiedMessage;
|
import org.briarproject.api.messaging.UnverifiedMessage;
|
||||||
import org.briarproject.api.serial.StructReader;
|
import org.briarproject.api.serial.ObjectReader;
|
||||||
|
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import com.google.inject.Provides;
|
import com.google.inject.Provides;
|
||||||
@@ -34,25 +34,25 @@ public class MessagingModule extends AbstractModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
StructReader<Author> getAuthorReader(CryptoComponent crypto) {
|
ObjectReader<Author> getAuthorReader(CryptoComponent crypto) {
|
||||||
return new AuthorReader(crypto);
|
return new AuthorReader(crypto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
StructReader<Group> getGroupReader(CryptoComponent crypto) {
|
ObjectReader<Group> getGroupReader(CryptoComponent crypto) {
|
||||||
return new GroupReader(crypto);
|
return new GroupReader(crypto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
StructReader<UnverifiedMessage> getMessageReader(
|
ObjectReader<UnverifiedMessage> getMessageReader(
|
||||||
StructReader<Group> groupReader,
|
ObjectReader<Group> groupReader,
|
||||||
StructReader<Author> authorReader) {
|
ObjectReader<Author> authorReader) {
|
||||||
return new MessageReader(groupReader, authorReader);
|
return new MessageReader(groupReader, authorReader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
StructReader<SubscriptionUpdate> getSubscriptionUpdateReader(
|
ObjectReader<SubscriptionUpdate> getSubscriptionUpdateReader(
|
||||||
StructReader<Group> groupReader) {
|
ObjectReader<Group> groupReader) {
|
||||||
return new SubscriptionUpdateReader(groupReader);
|
return new SubscriptionUpdateReader(groupReader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,18 +9,18 @@ import org.briarproject.api.messaging.PacketReaderFactory;
|
|||||||
import org.briarproject.api.messaging.SubscriptionUpdate;
|
import org.briarproject.api.messaging.SubscriptionUpdate;
|
||||||
import org.briarproject.api.messaging.UnverifiedMessage;
|
import org.briarproject.api.messaging.UnverifiedMessage;
|
||||||
import org.briarproject.api.serial.ReaderFactory;
|
import org.briarproject.api.serial.ReaderFactory;
|
||||||
import org.briarproject.api.serial.StructReader;
|
import org.briarproject.api.serial.ObjectReader;
|
||||||
|
|
||||||
class PacketReaderFactoryImpl implements PacketReaderFactory {
|
class PacketReaderFactoryImpl implements PacketReaderFactory {
|
||||||
|
|
||||||
private final ReaderFactory readerFactory;
|
private final ReaderFactory readerFactory;
|
||||||
private final StructReader<UnverifiedMessage> messageReader;
|
private final ObjectReader<UnverifiedMessage> messageReader;
|
||||||
private final StructReader<SubscriptionUpdate> subscriptionUpdateReader;
|
private final ObjectReader<SubscriptionUpdate> subscriptionUpdateReader;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PacketReaderFactoryImpl(ReaderFactory readerFactory,
|
PacketReaderFactoryImpl(ReaderFactory readerFactory,
|
||||||
StructReader<UnverifiedMessage> messageReader,
|
ObjectReader<UnverifiedMessage> messageReader,
|
||||||
StructReader<SubscriptionUpdate> subscriptionUpdateReader) {
|
ObjectReader<SubscriptionUpdate> subscriptionUpdateReader) {
|
||||||
this.readerFactory = readerFactory;
|
this.readerFactory = readerFactory;
|
||||||
this.messageReader = messageReader;
|
this.messageReader = messageReader;
|
||||||
this.subscriptionUpdateReader = subscriptionUpdateReader;
|
this.subscriptionUpdateReader = subscriptionUpdateReader;
|
||||||
|
|||||||
@@ -3,18 +3,21 @@ package org.briarproject.messaging;
|
|||||||
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTIES_PER_TRANSPORT;
|
||||||
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
import static org.briarproject.api.TransportPropertyConstants.MAX_PROPERTY_LENGTH;
|
||||||
import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH;
|
import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.HEADER_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.ACK;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.MESSAGE;
|
import static org.briarproject.api.messaging.MessagingConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.api.messaging.Types.OFFER;
|
import static org.briarproject.api.messaging.PacketTypes.ACK;
|
||||||
import static org.briarproject.api.messaging.Types.REQUEST;
|
import static org.briarproject.api.messaging.PacketTypes.MESSAGE;
|
||||||
import static org.briarproject.api.messaging.Types.RETENTION_ACK;
|
import static org.briarproject.api.messaging.PacketTypes.OFFER;
|
||||||
import static org.briarproject.api.messaging.Types.RETENTION_UPDATE;
|
import static org.briarproject.api.messaging.PacketTypes.REQUEST;
|
||||||
import static org.briarproject.api.messaging.Types.SUBSCRIPTION_ACK;
|
import static org.briarproject.api.messaging.PacketTypes.RETENTION_ACK;
|
||||||
import static org.briarproject.api.messaging.Types.SUBSCRIPTION_UPDATE;
|
import static org.briarproject.api.messaging.PacketTypes.RETENTION_UPDATE;
|
||||||
import static org.briarproject.api.messaging.Types.TRANSPORT_ACK;
|
import static org.briarproject.api.messaging.PacketTypes.SUBSCRIPTION_ACK;
|
||||||
import static org.briarproject.api.messaging.Types.TRANSPORT_UPDATE;
|
import static org.briarproject.api.messaging.PacketTypes.SUBSCRIPTION_UPDATE;
|
||||||
|
import static org.briarproject.api.messaging.PacketTypes.TRANSPORT_ACK;
|
||||||
|
import static org.briarproject.api.messaging.PacketTypes.TRANSPORT_UPDATE;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -39,42 +42,82 @@ import org.briarproject.api.messaging.SubscriptionUpdate;
|
|||||||
import org.briarproject.api.messaging.TransportAck;
|
import org.briarproject.api.messaging.TransportAck;
|
||||||
import org.briarproject.api.messaging.TransportUpdate;
|
import org.briarproject.api.messaging.TransportUpdate;
|
||||||
import org.briarproject.api.messaging.UnverifiedMessage;
|
import org.briarproject.api.messaging.UnverifiedMessage;
|
||||||
import org.briarproject.api.serial.Consumer;
|
|
||||||
import org.briarproject.api.serial.CountingConsumer;
|
|
||||||
import org.briarproject.api.serial.Reader;
|
import org.briarproject.api.serial.Reader;
|
||||||
import org.briarproject.api.serial.ReaderFactory;
|
import org.briarproject.api.serial.ReaderFactory;
|
||||||
import org.briarproject.api.serial.StructReader;
|
import org.briarproject.api.serial.ObjectReader;
|
||||||
|
import org.briarproject.util.ByteUtils;
|
||||||
|
|
||||||
// This class is not thread-safe
|
// This class is not thread-safe
|
||||||
class PacketReaderImpl implements PacketReader {
|
class PacketReaderImpl implements PacketReader {
|
||||||
|
|
||||||
private final StructReader<UnverifiedMessage> messageReader;
|
private enum State { BUFFER_EMPTY, BUFFER_FULL, EOF };
|
||||||
private final StructReader<SubscriptionUpdate> subscriptionUpdateReader;
|
|
||||||
private final Reader r;
|
private final ReaderFactory readerFactory;
|
||||||
|
private final ObjectReader<UnverifiedMessage> messageReader;
|
||||||
|
private final ObjectReader<SubscriptionUpdate> subscriptionUpdateReader;
|
||||||
|
private final InputStream in;
|
||||||
|
private final byte[] header, payload;
|
||||||
|
|
||||||
|
private State state = State.BUFFER_EMPTY;
|
||||||
|
private int payloadLength = 0;
|
||||||
|
|
||||||
PacketReaderImpl(ReaderFactory readerFactory,
|
PacketReaderImpl(ReaderFactory readerFactory,
|
||||||
StructReader<UnverifiedMessage> messageReader,
|
ObjectReader<UnverifiedMessage> messageReader,
|
||||||
StructReader<SubscriptionUpdate> subscriptionUpdateReader,
|
ObjectReader<SubscriptionUpdate> subscriptionUpdateReader,
|
||||||
InputStream in) {
|
InputStream in) {
|
||||||
|
this.readerFactory = readerFactory;
|
||||||
this.messageReader = messageReader;
|
this.messageReader = messageReader;
|
||||||
this.subscriptionUpdateReader = subscriptionUpdateReader;
|
this.subscriptionUpdateReader = subscriptionUpdateReader;
|
||||||
r = readerFactory.createReader(in);
|
this.in = in;
|
||||||
|
header = new byte[HEADER_LENGTH];
|
||||||
|
payload = new byte[MAX_PAYLOAD_LENGTH];
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readPacket() throws IOException {
|
||||||
|
assert state == State.BUFFER_EMPTY;
|
||||||
|
// Read the header
|
||||||
|
int offset = 0;
|
||||||
|
while(offset < HEADER_LENGTH) {
|
||||||
|
int read = in.read(header, offset, HEADER_LENGTH - offset);
|
||||||
|
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_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;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean eof() throws IOException {
|
public boolean eof() throws IOException {
|
||||||
return r.eof();
|
if(state == State.BUFFER_EMPTY) readPacket();
|
||||||
|
assert state != State.BUFFER_EMPTY;
|
||||||
|
return state == State.EOF;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasAck() throws IOException {
|
public boolean hasAck() throws IOException {
|
||||||
return r.hasStruct(ACK);
|
return !eof() && header[1] == ACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Ack readAck() throws IOException {
|
public Ack readAck() throws IOException {
|
||||||
|
if(!hasAck()) throw new FormatException();
|
||||||
// Set up the reader
|
// Set up the reader
|
||||||
Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH);
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
r.addConsumer(counting);
|
Reader r = readerFactory.createReader(bais);
|
||||||
// Read the start of the struct
|
// Read the start of the payload
|
||||||
r.readStructStart(ACK);
|
r.readListStart();
|
||||||
// Read the message IDs
|
// Read the message IDs
|
||||||
List<MessageId> acked = new ArrayList<MessageId>();
|
List<MessageId> acked = new ArrayList<MessageId>();
|
||||||
r.readListStart();
|
r.readListStart();
|
||||||
@@ -86,32 +129,41 @@ class PacketReaderImpl implements PacketReader {
|
|||||||
}
|
}
|
||||||
if(acked.isEmpty()) throw new FormatException();
|
if(acked.isEmpty()) throw new FormatException();
|
||||||
r.readListEnd();
|
r.readListEnd();
|
||||||
// Read the end of the struct
|
// Read the end of the payload
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
// Reset the reader
|
if(!r.eof()) throw new FormatException();
|
||||||
r.removeConsumer(counting);
|
state = State.BUFFER_EMPTY;
|
||||||
// Build and return the ack
|
// Build and return the ack
|
||||||
return new Ack(Collections.unmodifiableList(acked));
|
return new Ack(Collections.unmodifiableList(acked));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasMessage() throws IOException {
|
public boolean hasMessage() throws IOException {
|
||||||
return r.hasStruct(MESSAGE);
|
return !eof() && header[1] == MESSAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public UnverifiedMessage readMessage() throws IOException {
|
public UnverifiedMessage readMessage() throws IOException {
|
||||||
return messageReader.readStruct(r);
|
if(!hasMessage()) throw new FormatException();
|
||||||
|
// Set up the reader
|
||||||
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
|
Reader r = readerFactory.createReader(bais);
|
||||||
|
// Read and build the message
|
||||||
|
UnverifiedMessage m = messageReader.readObject(r);
|
||||||
|
if(!r.eof()) throw new FormatException();
|
||||||
|
state = State.BUFFER_EMPTY;
|
||||||
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasOffer() throws IOException {
|
public boolean hasOffer() throws IOException {
|
||||||
return r.hasStruct(OFFER);
|
return !eof() && header[1] == OFFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Offer readOffer() throws IOException {
|
public Offer readOffer() throws IOException {
|
||||||
|
if(!hasOffer()) throw new FormatException();
|
||||||
// Set up the reader
|
// Set up the reader
|
||||||
Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH);
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
r.addConsumer(counting);
|
Reader r = readerFactory.createReader(bais);
|
||||||
// Read the start of the struct
|
// Read the start of the payload
|
||||||
r.readStructStart(OFFER);
|
r.readListStart();
|
||||||
// Read the message IDs
|
// Read the message IDs
|
||||||
List<MessageId> offered = new ArrayList<MessageId>();
|
List<MessageId> offered = new ArrayList<MessageId>();
|
||||||
r.readListStart();
|
r.readListStart();
|
||||||
@@ -123,27 +175,28 @@ class PacketReaderImpl implements PacketReader {
|
|||||||
}
|
}
|
||||||
if(offered.isEmpty()) throw new FormatException();
|
if(offered.isEmpty()) throw new FormatException();
|
||||||
r.readListEnd();
|
r.readListEnd();
|
||||||
// Read the end of the struct
|
// Read the end of the payload
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
// Reset the reader
|
if(!r.eof()) throw new FormatException();
|
||||||
r.removeConsumer(counting);
|
state = State.BUFFER_EMPTY;
|
||||||
// Build and return the offer
|
// Build and return the offer
|
||||||
return new Offer(Collections.unmodifiableList(offered));
|
return new Offer(Collections.unmodifiableList(offered));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRequest() throws IOException {
|
public boolean hasRequest() throws IOException {
|
||||||
return r.hasStruct(REQUEST);
|
return !eof() && header[1] == REQUEST;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Request readRequest() throws IOException {
|
public Request readRequest() throws IOException {
|
||||||
|
if(!hasRequest()) throw new FormatException();
|
||||||
// Set up the reader
|
// Set up the reader
|
||||||
Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH);
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
r.addConsumer(counting);
|
Reader r = readerFactory.createReader(bais);
|
||||||
// Read the start of the struct
|
// Read the start of the payload
|
||||||
r.readStructStart(REQUEST);
|
|
||||||
// Read the message IDs
|
|
||||||
List<MessageId> requested = new ArrayList<MessageId>();
|
|
||||||
r.readListStart();
|
r.readListStart();
|
||||||
|
// Read the message IDs
|
||||||
|
r.readListStart();
|
||||||
|
List<MessageId> requested = new ArrayList<MessageId>();
|
||||||
while(!r.hasListEnd()) {
|
while(!r.hasListEnd()) {
|
||||||
byte[] b = r.readBytes(UniqueId.LENGTH);
|
byte[] b = r.readBytes(UniqueId.LENGTH);
|
||||||
if(b.length != UniqueId.LENGTH)
|
if(b.length != UniqueId.LENGTH)
|
||||||
@@ -152,85 +205,134 @@ class PacketReaderImpl implements PacketReader {
|
|||||||
}
|
}
|
||||||
if(requested.isEmpty()) throw new FormatException();
|
if(requested.isEmpty()) throw new FormatException();
|
||||||
r.readListEnd();
|
r.readListEnd();
|
||||||
// Read the end of the struct
|
// Read the end of the payload
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
// Reset the reader
|
if(!r.eof()) throw new FormatException();
|
||||||
r.removeConsumer(counting);
|
state = State.BUFFER_EMPTY;
|
||||||
// Build and return the request
|
// Build and return the request
|
||||||
return new Request(Collections.unmodifiableList(requested));
|
return new Request(Collections.unmodifiableList(requested));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRetentionAck() throws IOException {
|
public boolean hasRetentionAck() throws IOException {
|
||||||
return r.hasStruct(RETENTION_ACK);
|
return !eof() && header[1] == RETENTION_ACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RetentionAck readRetentionAck() throws IOException {
|
public RetentionAck readRetentionAck() throws IOException {
|
||||||
r.readStructStart(RETENTION_ACK);
|
if(!hasRetentionAck()) throw new FormatException();
|
||||||
|
// Set up the reader
|
||||||
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
|
Reader r = readerFactory.createReader(bais);
|
||||||
|
// Read the start of the payload
|
||||||
|
r.readListStart();
|
||||||
|
// Read the version
|
||||||
long version = r.readInteger();
|
long version = r.readInteger();
|
||||||
if(version < 0) throw new FormatException();
|
if(version < 0) throw new FormatException();
|
||||||
r.readStructEnd();
|
// Read the end of the payload
|
||||||
|
r.readListEnd();
|
||||||
|
if(!r.eof()) throw new FormatException();
|
||||||
|
state = State.BUFFER_EMPTY;
|
||||||
|
// Build and return the retention ack
|
||||||
return new RetentionAck(version);
|
return new RetentionAck(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasRetentionUpdate() throws IOException {
|
public boolean hasRetentionUpdate() throws IOException {
|
||||||
return r.hasStruct(RETENTION_UPDATE);
|
return !eof() && header[1] == RETENTION_UPDATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RetentionUpdate readRetentionUpdate() throws IOException {
|
public RetentionUpdate readRetentionUpdate() throws IOException {
|
||||||
r.readStructStart(RETENTION_UPDATE);
|
if(!hasRetentionUpdate()) throw new FormatException();
|
||||||
|
// Set up the reader
|
||||||
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
|
Reader r = readerFactory.createReader(bais);
|
||||||
|
// Read the start of the payload
|
||||||
|
r.readListStart();
|
||||||
|
// Read the retention time and version
|
||||||
long retention = r.readInteger();
|
long retention = r.readInteger();
|
||||||
if(retention < 0) throw new FormatException();
|
if(retention < 0) throw new FormatException();
|
||||||
long version = r.readInteger();
|
long version = r.readInteger();
|
||||||
if(version < 0) throw new FormatException();
|
if(version < 0) throw new FormatException();
|
||||||
r.readStructEnd();
|
// Read the end of the payload
|
||||||
|
r.readListEnd();
|
||||||
|
if(!r.eof()) throw new FormatException();
|
||||||
|
state = State.BUFFER_EMPTY;
|
||||||
|
// Build and return the retention update
|
||||||
return new RetentionUpdate(retention, version);
|
return new RetentionUpdate(retention, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSubscriptionAck() throws IOException {
|
public boolean hasSubscriptionAck() throws IOException {
|
||||||
return r.hasStruct(SUBSCRIPTION_ACK);
|
return !eof() && header[1] == SUBSCRIPTION_ACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionAck readSubscriptionAck() throws IOException {
|
public SubscriptionAck readSubscriptionAck() throws IOException {
|
||||||
r.readStructStart(SUBSCRIPTION_ACK);
|
if(!hasSubscriptionAck()) throw new FormatException();
|
||||||
|
// Set up the reader
|
||||||
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
|
Reader r = readerFactory.createReader(bais);
|
||||||
|
// Read the start of the payload
|
||||||
|
r.readListStart();
|
||||||
|
// Read the version
|
||||||
long version = r.readInteger();
|
long version = r.readInteger();
|
||||||
if(version < 0) throw new FormatException();
|
if(version < 0) throw new FormatException();
|
||||||
r.readStructEnd();
|
// Read the end of the payload
|
||||||
|
r.readListEnd();
|
||||||
|
if(!r.eof()) throw new FormatException();
|
||||||
|
state = State.BUFFER_EMPTY;
|
||||||
|
// Build and return the subscription ack
|
||||||
return new SubscriptionAck(version);
|
return new SubscriptionAck(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasSubscriptionUpdate() throws IOException {
|
public boolean hasSubscriptionUpdate() throws IOException {
|
||||||
return r.hasStruct(SUBSCRIPTION_UPDATE);
|
return !eof() && header[1] == SUBSCRIPTION_UPDATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionUpdate readSubscriptionUpdate() throws IOException {
|
public SubscriptionUpdate readSubscriptionUpdate() throws IOException {
|
||||||
return subscriptionUpdateReader.readStruct(r);
|
if(!hasSubscriptionUpdate()) throw new FormatException();
|
||||||
|
// Set up the reader
|
||||||
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
|
Reader r = readerFactory.createReader(bais);
|
||||||
|
// Read and build the subscription update
|
||||||
|
SubscriptionUpdate u = subscriptionUpdateReader.readObject(r);
|
||||||
|
if(!r.eof()) throw new FormatException();
|
||||||
|
state = State.BUFFER_EMPTY;
|
||||||
|
return u;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTransportAck() throws IOException {
|
public boolean hasTransportAck() throws IOException {
|
||||||
return r.hasStruct(TRANSPORT_ACK);
|
return !eof() && header[1] == TRANSPORT_ACK;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportAck readTransportAck() throws IOException {
|
public TransportAck readTransportAck() throws IOException {
|
||||||
r.readStructStart(TRANSPORT_ACK);
|
if(!hasTransportAck()) throw new FormatException();
|
||||||
|
// Set up the reader
|
||||||
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
|
Reader r = readerFactory.createReader(bais);
|
||||||
|
// Read the start of the payload
|
||||||
|
r.readListStart();
|
||||||
|
// Read the transport ID and version
|
||||||
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
|
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
|
||||||
if(idString.length() == 0) throw new FormatException();
|
if(idString.length() == 0) throw new FormatException();
|
||||||
TransportId id = new TransportId(idString);
|
TransportId id = new TransportId(idString);
|
||||||
long version = r.readInteger();
|
long version = r.readInteger();
|
||||||
if(version < 0) throw new FormatException();
|
if(version < 0) throw new FormatException();
|
||||||
r.readStructEnd();
|
// Read the end of the payload
|
||||||
|
r.readListEnd();
|
||||||
|
if(!r.eof()) throw new FormatException();
|
||||||
|
state = State.BUFFER_EMPTY;
|
||||||
|
// Build and return the transport ack
|
||||||
return new TransportAck(id, version);
|
return new TransportAck(id, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasTransportUpdate() throws IOException {
|
public boolean hasTransportUpdate() throws IOException {
|
||||||
return r.hasStruct(TRANSPORT_UPDATE);
|
return !eof() && header[1] == TRANSPORT_UPDATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportUpdate readTransportUpdate() throws IOException {
|
public TransportUpdate readTransportUpdate() throws IOException {
|
||||||
|
if(!hasTransportUpdate()) throw new FormatException();
|
||||||
// Set up the reader
|
// Set up the reader
|
||||||
Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH);
|
InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength);
|
||||||
r.addConsumer(counting);
|
Reader r = readerFactory.createReader(bais);
|
||||||
// Read the start of the struct
|
// Read the start of the payload
|
||||||
r.readStructStart(TRANSPORT_UPDATE);
|
r.readListStart();
|
||||||
// Read the transport ID
|
// Read the transport ID
|
||||||
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
|
String idString = r.readString(MAX_TRANSPORT_ID_LENGTH);
|
||||||
if(idString.length() == 0) throw new FormatException();
|
if(idString.length() == 0) throw new FormatException();
|
||||||
@@ -249,10 +351,10 @@ class PacketReaderImpl implements PacketReader {
|
|||||||
// Read the version number
|
// Read the version number
|
||||||
long version = r.readInteger();
|
long version = r.readInteger();
|
||||||
if(version < 0) throw new FormatException();
|
if(version < 0) throw new FormatException();
|
||||||
// Read the end of the struct
|
// Read the end of the payload
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
// Reset the reader
|
if(!r.eof()) throw new FormatException();
|
||||||
r.removeConsumer(counting);
|
state = State.BUFFER_EMPTY;
|
||||||
// Build and return the transport update
|
// Build and return the transport update
|
||||||
return new TransportUpdate(id, new TransportProperties(p), version);
|
return new TransportUpdate(id, new TransportProperties(p), version);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
package org.briarproject.messaging;
|
package org.briarproject.messaging;
|
||||||
|
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.HEADER_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.ACK;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.GROUP;
|
import static org.briarproject.api.messaging.MessagingConstants.PROTOCOL_VERSION;
|
||||||
import static org.briarproject.api.messaging.Types.OFFER;
|
import static org.briarproject.api.messaging.PacketTypes.ACK;
|
||||||
import static org.briarproject.api.messaging.Types.REQUEST;
|
import static org.briarproject.api.messaging.PacketTypes.OFFER;
|
||||||
import static org.briarproject.api.messaging.Types.RETENTION_ACK;
|
import static org.briarproject.api.messaging.PacketTypes.REQUEST;
|
||||||
import static org.briarproject.api.messaging.Types.RETENTION_UPDATE;
|
import static org.briarproject.api.messaging.PacketTypes.RETENTION_ACK;
|
||||||
import static org.briarproject.api.messaging.Types.SUBSCRIPTION_ACK;
|
import static org.briarproject.api.messaging.PacketTypes.RETENTION_UPDATE;
|
||||||
import static org.briarproject.api.messaging.Types.SUBSCRIPTION_UPDATE;
|
import static org.briarproject.api.messaging.PacketTypes.SUBSCRIPTION_ACK;
|
||||||
import static org.briarproject.api.messaging.Types.TRANSPORT_ACK;
|
import static org.briarproject.api.messaging.PacketTypes.SUBSCRIPTION_UPDATE;
|
||||||
import static org.briarproject.api.messaging.Types.TRANSPORT_UPDATE;
|
import static org.briarproject.api.messaging.PacketTypes.TRANSPORT_ACK;
|
||||||
|
import static org.briarproject.api.messaging.PacketTypes.TRANSPORT_UPDATE;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
@@ -19,6 +21,7 @@ import org.briarproject.api.messaging.Ack;
|
|||||||
import org.briarproject.api.messaging.Group;
|
import org.briarproject.api.messaging.Group;
|
||||||
import org.briarproject.api.messaging.MessageId;
|
import org.briarproject.api.messaging.MessageId;
|
||||||
import org.briarproject.api.messaging.Offer;
|
import org.briarproject.api.messaging.Offer;
|
||||||
|
import org.briarproject.api.messaging.PacketTypes;
|
||||||
import org.briarproject.api.messaging.PacketWriter;
|
import org.briarproject.api.messaging.PacketWriter;
|
||||||
import org.briarproject.api.messaging.Request;
|
import org.briarproject.api.messaging.Request;
|
||||||
import org.briarproject.api.messaging.RetentionAck;
|
import org.briarproject.api.messaging.RetentionAck;
|
||||||
@@ -30,118 +33,161 @@ import org.briarproject.api.messaging.TransportUpdate;
|
|||||||
import org.briarproject.api.serial.SerialComponent;
|
import org.briarproject.api.serial.SerialComponent;
|
||||||
import org.briarproject.api.serial.Writer;
|
import org.briarproject.api.serial.Writer;
|
||||||
import org.briarproject.api.serial.WriterFactory;
|
import org.briarproject.api.serial.WriterFactory;
|
||||||
|
import org.briarproject.util.ByteUtils;
|
||||||
|
|
||||||
// This class is not thread-safe
|
// This class is not thread-safe
|
||||||
class PacketWriterImpl implements PacketWriter {
|
class PacketWriterImpl implements PacketWriter {
|
||||||
|
|
||||||
private final SerialComponent serial;
|
private final SerialComponent serial;
|
||||||
|
private final WriterFactory writerFactory;
|
||||||
private final OutputStream out;
|
private final OutputStream out;
|
||||||
private final Writer w;
|
private final byte[] header;
|
||||||
|
private final ByteArrayOutputStream payload;
|
||||||
|
|
||||||
PacketWriterImpl(SerialComponent serial, WriterFactory writerFactory,
|
PacketWriterImpl(SerialComponent serial, WriterFactory writerFactory,
|
||||||
OutputStream out) {
|
OutputStream out) {
|
||||||
this.serial = serial;
|
this.serial = serial;
|
||||||
|
this.writerFactory = writerFactory;
|
||||||
this.out = out;
|
this.out = out;
|
||||||
w = writerFactory.createWriter(out);
|
header = new byte[HEADER_LENGTH];
|
||||||
|
header[0] = PROTOCOL_VERSION;
|
||||||
|
payload = new ByteArrayOutputStream(MAX_PAYLOAD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxMessagesForAck(long capacity) {
|
public int getMaxMessagesForAck(long capacity) {
|
||||||
return getMaxMessagesForPacket(capacity, ACK);
|
return getMaxMessagesForPacket(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxMessagesForRequest(long capacity) {
|
public int getMaxMessagesForRequest(long capacity) {
|
||||||
return getMaxMessagesForPacket(capacity, REQUEST);
|
return getMaxMessagesForPacket(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMaxMessagesForOffer(long capacity) {
|
public int getMaxMessagesForOffer(long capacity) {
|
||||||
return getMaxMessagesForPacket(capacity, OFFER);
|
return getMaxMessagesForPacket(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
private int getMaxMessagesForPacket(long capacity, int structId) {
|
private int getMaxMessagesForPacket(long capacity) {
|
||||||
int packet = (int) Math.min(capacity, MAX_PACKET_LENGTH);
|
int payload = (int) Math.min(capacity - HEADER_LENGTH,
|
||||||
int overhead = serial.getSerialisedStructStartLength(structId)
|
MAX_PAYLOAD_LENGTH);
|
||||||
+ serial.getSerialisedListStartLength()
|
int overhead = serial.getSerialisedListStartLength() * 2
|
||||||
+ serial.getSerialisedListEndLength()
|
+ serial.getSerialisedListEndLength() * 2;
|
||||||
+ serial.getSerialisedStructEndLength();
|
|
||||||
int idLength = serial.getSerialisedUniqueIdLength();
|
int idLength = serial.getSerialisedUniqueIdLength();
|
||||||
return (packet - overhead) / idLength;
|
return (payload - overhead) / idLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void writePacket(byte packetType) throws IOException {
|
||||||
|
header[1] = packetType;
|
||||||
|
ByteUtils.writeUint16(payload.size(), header, 2);
|
||||||
|
out.write(header);
|
||||||
|
payload.writeTo(out);
|
||||||
|
payload.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeAck(Ack a) throws IOException {
|
public void writeAck(Ack a) throws IOException {
|
||||||
w.writeStructStart(ACK);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(MessageId m : a.getMessageIds()) w.writeBytes(m.getBytes());
|
for(MessageId m : a.getMessageIds()) w.writeBytes(m.getBytes());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(ACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeMessage(byte[] raw) throws IOException {
|
public void writeMessage(byte[] raw) throws IOException {
|
||||||
|
header[1] = PacketTypes.MESSAGE;
|
||||||
|
ByteUtils.writeUint16(raw.length, header, 2);
|
||||||
|
out.write(header);
|
||||||
out.write(raw);
|
out.write(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeOffer(Offer o) throws IOException {
|
public void writeOffer(Offer o) throws IOException {
|
||||||
w.writeStructStart(OFFER);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes());
|
for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(OFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeRequest(Request r) throws IOException {
|
public void writeRequest(Request r) throws IOException {
|
||||||
w.writeStructStart(REQUEST);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(MessageId m : r.getMessageIds()) w.writeBytes(m.getBytes());
|
for(MessageId m : r.getMessageIds()) w.writeBytes(m.getBytes());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeRetentionAck(RetentionAck a) throws IOException {
|
public void writeRetentionAck(RetentionAck a) throws IOException {
|
||||||
w.writeStructStart(RETENTION_ACK);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeInteger(a.getVersion());
|
w.writeInteger(a.getVersion());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(RETENTION_ACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeRetentionUpdate(RetentionUpdate u) throws IOException {
|
public void writeRetentionUpdate(RetentionUpdate u) throws IOException {
|
||||||
w.writeStructStart(RETENTION_UPDATE);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeInteger(u.getRetentionTime());
|
w.writeInteger(u.getRetentionTime());
|
||||||
w.writeInteger(u.getVersion());
|
w.writeInteger(u.getVersion());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(RETENTION_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeSubscriptionAck(SubscriptionAck a) throws IOException {
|
public void writeSubscriptionAck(SubscriptionAck a) throws IOException {
|
||||||
w.writeStructStart(SUBSCRIPTION_ACK);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeInteger(a.getVersion());
|
w.writeInteger(a.getVersion());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(SUBSCRIPTION_ACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeSubscriptionUpdate(SubscriptionUpdate u)
|
public void writeSubscriptionUpdate(SubscriptionUpdate u)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
w.writeStructStart(SUBSCRIPTION_UPDATE);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
for(Group g : u.getGroups()) {
|
for(Group g : u.getGroups()) {
|
||||||
w.writeStructStart(GROUP);
|
w.writeListStart();
|
||||||
w.writeString(g.getName());
|
w.writeString(g.getName());
|
||||||
w.writeBytes(g.getSalt());
|
w.writeBytes(g.getSalt());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
}
|
}
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeInteger(u.getVersion());
|
w.writeInteger(u.getVersion());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(SUBSCRIPTION_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTransportAck(TransportAck a) throws IOException {
|
public void writeTransportAck(TransportAck a) throws IOException {
|
||||||
w.writeStructStart(TRANSPORT_ACK);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeString(a.getId().getString());
|
w.writeString(a.getId().getString());
|
||||||
w.writeInteger(a.getVersion());
|
w.writeInteger(a.getVersion());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(TRANSPORT_ACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeTransportUpdate(TransportUpdate u) throws IOException {
|
public void writeTransportUpdate(TransportUpdate u) throws IOException {
|
||||||
w.writeStructStart(TRANSPORT_UPDATE);
|
assert payload.size() == 0;
|
||||||
|
Writer w = writerFactory.createWriter(payload);
|
||||||
|
w.writeListStart();
|
||||||
w.writeString(u.getId().getString());
|
w.writeString(u.getId().getString());
|
||||||
w.writeMap(u.getProperties());
|
w.writeMap(u.getProperties());
|
||||||
w.writeInteger(u.getVersion());
|
w.writeInteger(u.getVersion());
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
|
writePacket(TRANSPORT_UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() throws IOException {
|
public void flush() throws IOException {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ package org.briarproject.messaging;
|
|||||||
|
|
||||||
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.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -167,7 +167,7 @@ class SimplexOutgoingSession implements MessagingSession, EventListener {
|
|||||||
if(interrupted) return;
|
if(interrupted) return;
|
||||||
try {
|
try {
|
||||||
Collection<byte[]> b = db.generateBatch(contactId,
|
Collection<byte[]> b = db.generateBatch(contactId,
|
||||||
MAX_PACKET_LENGTH, maxLatency);
|
MAX_PAYLOAD_LENGTH, maxLatency);
|
||||||
if(LOG.isLoggable(INFO))
|
if(LOG.isLoggable(INFO))
|
||||||
LOG.info("Generated batch: " + (b != null));
|
LOG.info("Generated batch: " + (b != null));
|
||||||
if(b == null) decrementOutstandingQueries();
|
if(b == null) decrementOutstandingQueries();
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package org.briarproject.messaging;
|
package org.briarproject.messaging;
|
||||||
|
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
|
||||||
import static org.briarproject.api.messaging.Types.SUBSCRIPTION_UPDATE;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -17,29 +16,29 @@ import org.briarproject.api.messaging.GroupId;
|
|||||||
import org.briarproject.api.messaging.SubscriptionUpdate;
|
import org.briarproject.api.messaging.SubscriptionUpdate;
|
||||||
import org.briarproject.api.serial.Consumer;
|
import org.briarproject.api.serial.Consumer;
|
||||||
import org.briarproject.api.serial.CountingConsumer;
|
import org.briarproject.api.serial.CountingConsumer;
|
||||||
|
import org.briarproject.api.serial.ObjectReader;
|
||||||
import org.briarproject.api.serial.Reader;
|
import org.briarproject.api.serial.Reader;
|
||||||
import org.briarproject.api.serial.StructReader;
|
|
||||||
|
|
||||||
class SubscriptionUpdateReader implements StructReader<SubscriptionUpdate> {
|
class SubscriptionUpdateReader implements ObjectReader<SubscriptionUpdate> {
|
||||||
|
|
||||||
private final StructReader<Group> groupReader;
|
private final ObjectReader<Group> groupReader;
|
||||||
|
|
||||||
SubscriptionUpdateReader(StructReader<Group> groupReader) {
|
SubscriptionUpdateReader(ObjectReader<Group> groupReader) {
|
||||||
this.groupReader = groupReader;
|
this.groupReader = groupReader;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscriptionUpdate readStruct(Reader r) throws IOException {
|
public SubscriptionUpdate readObject(Reader r) throws IOException {
|
||||||
// Set up the reader
|
// Set up the reader
|
||||||
Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH);
|
Consumer counting = new CountingConsumer(MAX_PAYLOAD_LENGTH);
|
||||||
r.addConsumer(counting);
|
r.addConsumer(counting);
|
||||||
// Read the start of the struct
|
// Read the start of the update
|
||||||
r.readStructStart(SUBSCRIPTION_UPDATE);
|
r.readListStart();
|
||||||
// Read the subscriptions, rejecting duplicates
|
// Read the subscriptions, rejecting duplicates
|
||||||
List<Group> groups = new ArrayList<Group>();
|
List<Group> groups = new ArrayList<Group>();
|
||||||
Set<GroupId> ids = new HashSet<GroupId>();
|
Set<GroupId> ids = new HashSet<GroupId>();
|
||||||
r.readListStart();
|
r.readListStart();
|
||||||
for(int i = 0; i < MAX_SUBSCRIPTIONS && !r.hasListEnd(); i++) {
|
for(int i = 0; i < MAX_SUBSCRIPTIONS && !r.hasListEnd(); i++) {
|
||||||
Group g = groupReader.readStruct(r);
|
Group g = groupReader.readObject(r);
|
||||||
if(!ids.add(g.getId())) throw new FormatException(); // Duplicate
|
if(!ids.add(g.getId())) throw new FormatException(); // Duplicate
|
||||||
groups.add(g);
|
groups.add(g);
|
||||||
}
|
}
|
||||||
@@ -47,8 +46,8 @@ class SubscriptionUpdateReader implements StructReader<SubscriptionUpdate> {
|
|||||||
// Read the version number
|
// Read the version number
|
||||||
long version = r.readInteger();
|
long version = r.readInteger();
|
||||||
if(version < 0) throw new FormatException();
|
if(version < 0) throw new FormatException();
|
||||||
// Read the end of the struct
|
// Read the end of the update
|
||||||
r.readStructEnd();
|
r.readListEnd();
|
||||||
// Reset the reader
|
// Reset the reader
|
||||||
r.removeConsumer(counting);
|
r.removeConsumer(counting);
|
||||||
// Build and return the subscription update
|
// Build and return the subscription update
|
||||||
|
|||||||
21
briar-core/src/org/briarproject/serial/ObjectTypes.java
Normal file
21
briar-core/src/org/briarproject/serial/ObjectTypes.java
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package org.briarproject.serial;
|
||||||
|
|
||||||
|
interface ObjectTypes {
|
||||||
|
|
||||||
|
byte NULL = 0x00;
|
||||||
|
byte BOOLEAN = 0x11;
|
||||||
|
byte INT_8 = 0x21;
|
||||||
|
byte INT_16 = 0x22;
|
||||||
|
byte INT_32 = 0x24;
|
||||||
|
byte INT_64 = 0x28;
|
||||||
|
byte FLOAT_64 = 0x38;
|
||||||
|
byte STRING_8 = 0x41;
|
||||||
|
byte STRING_16 = 0x42;
|
||||||
|
byte STRING_32 = 0x44;
|
||||||
|
byte RAW_8 = 0x51;
|
||||||
|
byte RAW_16 = 0x52;
|
||||||
|
byte RAW_32 = 0x54;
|
||||||
|
byte LIST = 0x60;
|
||||||
|
byte MAP = 0x70;
|
||||||
|
byte END = (byte) 0x80;
|
||||||
|
}
|
||||||
@@ -1,23 +1,20 @@
|
|||||||
package org.briarproject.serial;
|
package org.briarproject.serial;
|
||||||
|
|
||||||
import static org.briarproject.serial.Tag.BYTES_16;
|
import static org.briarproject.serial.ObjectTypes.END;
|
||||||
import static org.briarproject.serial.Tag.BYTES_32;
|
import static org.briarproject.serial.ObjectTypes.FLOAT_64;
|
||||||
import static org.briarproject.serial.Tag.BYTES_8;
|
import static org.briarproject.serial.ObjectTypes.INT_16;
|
||||||
import static org.briarproject.serial.Tag.END;
|
import static org.briarproject.serial.ObjectTypes.INT_32;
|
||||||
import static org.briarproject.serial.Tag.FALSE;
|
import static org.briarproject.serial.ObjectTypes.INT_64;
|
||||||
import static org.briarproject.serial.Tag.FLOAT;
|
import static org.briarproject.serial.ObjectTypes.INT_8;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_16;
|
import static org.briarproject.serial.ObjectTypes.LIST;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_32;
|
import static org.briarproject.serial.ObjectTypes.MAP;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_64;
|
import static org.briarproject.serial.ObjectTypes.NULL;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_8;
|
import static org.briarproject.serial.ObjectTypes.RAW_16;
|
||||||
import static org.briarproject.serial.Tag.LIST;
|
import static org.briarproject.serial.ObjectTypes.RAW_32;
|
||||||
import static org.briarproject.serial.Tag.MAP;
|
import static org.briarproject.serial.ObjectTypes.RAW_8;
|
||||||
import static org.briarproject.serial.Tag.NULL;
|
import static org.briarproject.serial.ObjectTypes.STRING_16;
|
||||||
import static org.briarproject.serial.Tag.STRING_16;
|
import static org.briarproject.serial.ObjectTypes.STRING_32;
|
||||||
import static org.briarproject.serial.Tag.STRING_32;
|
import static org.briarproject.serial.ObjectTypes.STRING_8;
|
||||||
import static org.briarproject.serial.Tag.STRING_8;
|
|
||||||
import static org.briarproject.serial.Tag.STRUCT;
|
|
||||||
import static org.briarproject.serial.Tag.TRUE;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@@ -37,7 +34,7 @@ class ReaderImpl implements Reader {
|
|||||||
private final Collection<Consumer> consumers = new ArrayList<Consumer>(0);
|
private final Collection<Consumer> consumers = new ArrayList<Consumer>(0);
|
||||||
|
|
||||||
private boolean hasLookahead = false, eof = false;
|
private boolean hasLookahead = false, eof = false;
|
||||||
private byte next, nextStructId;
|
private byte next;
|
||||||
private byte[] buf = new byte[8];
|
private byte[] buf = new byte[8];
|
||||||
|
|
||||||
ReaderImpl(InputStream in) {
|
ReaderImpl(InputStream in) {
|
||||||
@@ -54,21 +51,12 @@ class ReaderImpl implements Reader {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
next = (byte) i;
|
next = (byte) i;
|
||||||
// If necessary, read another lookahead byte
|
|
||||||
if(next == STRUCT) {
|
|
||||||
i = in.read();
|
|
||||||
if(i == -1) throw new FormatException();
|
|
||||||
nextStructId = (byte) i;
|
|
||||||
}
|
|
||||||
hasLookahead = true;
|
hasLookahead = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void consumeLookahead() throws IOException {
|
private void consumeLookahead() throws IOException {
|
||||||
assert hasLookahead;
|
assert hasLookahead;
|
||||||
for(Consumer c : consumers) {
|
for(Consumer c : consumers) c.write(next);
|
||||||
c.write(next);
|
|
||||||
if(next == STRUCT) c.write(nextStructId);
|
|
||||||
}
|
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,11 +89,10 @@ class ReaderImpl implements Reader {
|
|||||||
if(hasBoolean()) skipBoolean();
|
if(hasBoolean()) skipBoolean();
|
||||||
else if(hasInteger()) skipInteger();
|
else if(hasInteger()) skipInteger();
|
||||||
else if(hasFloat()) skipFloat();
|
else if(hasFloat()) skipFloat();
|
||||||
else if(hasString()) skipString(Integer.MAX_VALUE);
|
else if(hasString()) skipString();
|
||||||
else if(hasBytes()) skipBytes(Integer.MAX_VALUE);
|
else if(hasBytes()) skipBytes();
|
||||||
else if(hasList()) skipList();
|
else if(hasList()) skipList();
|
||||||
else if(hasMap()) skipMap();
|
else if(hasMap()) skipMap();
|
||||||
else if(hasStruct()) skipStruct();
|
|
||||||
else if(hasNull()) skipNull();
|
else if(hasNull()) skipNull();
|
||||||
else throw new FormatException();
|
else throw new FormatException();
|
||||||
}
|
}
|
||||||
@@ -127,36 +114,59 @@ class ReaderImpl implements Reader {
|
|||||||
if(!consumers.remove(c)) throw new IllegalArgumentException();
|
if(!consumers.remove(c)) throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasNull() throws IOException {
|
||||||
|
if(!hasLookahead) readLookahead();
|
||||||
|
if(eof) return false;
|
||||||
|
return next == NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void readNull() throws IOException {
|
||||||
|
if(!hasNull()) throw new FormatException();
|
||||||
|
consumeLookahead();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void skipNull() throws IOException {
|
||||||
|
if(!hasNull()) throw new FormatException();
|
||||||
|
hasLookahead = false;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasBoolean() throws IOException {
|
public boolean hasBoolean() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if(!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if(eof) return false;
|
||||||
return next == FALSE || next == TRUE;
|
return next == ObjectTypes.BOOLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean readBoolean() throws IOException {
|
public boolean readBoolean() throws IOException {
|
||||||
if(!hasBoolean()) throw new FormatException();
|
if(!hasBoolean()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
return next == TRUE;
|
return readBoolean(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean readBoolean(boolean consume) throws IOException {
|
||||||
|
readIntoBuffer(1, consume);
|
||||||
|
if(buf[0] != 0 && buf[0] != 1) throw new FormatException();
|
||||||
|
return buf[0] == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipBoolean() throws IOException {
|
public void skipBoolean() throws IOException {
|
||||||
if(!hasBoolean()) throw new FormatException();
|
if(!hasBoolean()) throw new FormatException();
|
||||||
|
skip(1);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasInteger() throws IOException {
|
public boolean hasInteger() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if(!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if(eof) return false;
|
||||||
return next == INTEGER_8 || next == INTEGER_16 || next == INTEGER_32 ||
|
return next == INT_8 || next == INT_16 || next == INT_32 ||
|
||||||
next == INTEGER_64;
|
next == INT_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
public long readInteger() throws IOException {
|
public long readInteger() throws IOException {
|
||||||
if(!hasInteger()) throw new FormatException();
|
if(!hasInteger()) throw new FormatException();
|
||||||
consumeLookahead();
|
consumeLookahead();
|
||||||
if(next == INTEGER_8) return readInt8(true);
|
if(next == INT_8) return readInt8(true);
|
||||||
if(next == INTEGER_16) return readInt16(true);
|
if(next == INT_16) return readInt16(true);
|
||||||
if(next == INTEGER_32) return readInt32(true);
|
if(next == INT_32) return readInt32(true);
|
||||||
return readInt64(true);
|
return readInt64(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,9 +203,9 @@ class ReaderImpl implements Reader {
|
|||||||
|
|
||||||
public void skipInteger() throws IOException {
|
public void skipInteger() throws IOException {
|
||||||
if(!hasInteger()) throw new FormatException();
|
if(!hasInteger()) throw new FormatException();
|
||||||
if(next == INTEGER_8) skip(1);
|
if(next == INT_8) skip(1);
|
||||||
else if(next == INTEGER_16) skip(2);
|
else if(next == INT_16) skip(2);
|
||||||
else if(next == INTEGER_32) skip(4);
|
else if(next == INT_32) skip(4);
|
||||||
else skip(8);
|
else skip(8);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
@@ -203,7 +213,7 @@ class ReaderImpl implements Reader {
|
|||||||
public boolean hasFloat() throws IOException {
|
public boolean hasFloat() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if(!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if(eof) return false;
|
||||||
return next == FLOAT;
|
return next == FLOAT_64;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double readFloat() throws IOException {
|
public double readFloat() throws IOException {
|
||||||
@@ -244,10 +254,10 @@ class ReaderImpl implements Reader {
|
|||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipString(int maxLength) throws IOException {
|
public void skipString() throws IOException {
|
||||||
if(!hasString()) throw new FormatException();
|
if(!hasString()) throw new FormatException();
|
||||||
int length = readStringLength(false);
|
int length = readStringLength(false);
|
||||||
if(length < 0 || length > maxLength) throw new FormatException();
|
if(length < 0) throw new FormatException();
|
||||||
skip(length);
|
skip(length);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
@@ -255,7 +265,7 @@ class ReaderImpl implements Reader {
|
|||||||
public boolean hasBytes() throws IOException {
|
public boolean hasBytes() throws IOException {
|
||||||
if(!hasLookahead) readLookahead();
|
if(!hasLookahead) readLookahead();
|
||||||
if(eof) return false;
|
if(eof) return false;
|
||||||
return next == BYTES_8 || next == BYTES_16 || next == BYTES_32;
|
return next == RAW_8 || next == RAW_16 || next == RAW_32;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] readBytes(int maxLength) throws IOException {
|
public byte[] readBytes(int maxLength) throws IOException {
|
||||||
@@ -270,16 +280,16 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int readBytesLength(boolean consume) throws IOException {
|
private int readBytesLength(boolean consume) throws IOException {
|
||||||
if(next == BYTES_8) return readInt8(consume);
|
if(next == RAW_8) return readInt8(consume);
|
||||||
if(next == BYTES_16) return readInt16(consume);
|
if(next == RAW_16) return readInt16(consume);
|
||||||
if(next == BYTES_32) return readInt32(consume);
|
if(next == RAW_32) return readInt32(consume);
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void skipBytes(int maxLength) throws IOException {
|
public void skipBytes() throws IOException {
|
||||||
if(!hasBytes()) throw new FormatException();
|
if(!hasBytes()) throw new FormatException();
|
||||||
int length = readBytesLength(false);
|
int length = readBytesLength(false);
|
||||||
if(length < 0 || length > maxLength) throw new FormatException();
|
if(length < 0) throw new FormatException();
|
||||||
skip(length);
|
skip(length);
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
@@ -349,53 +359,4 @@ class ReaderImpl implements Reader {
|
|||||||
}
|
}
|
||||||
hasLookahead = false;
|
hasLookahead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean hasStruct() throws IOException {
|
|
||||||
if(!hasLookahead) readLookahead();
|
|
||||||
if(eof) return false;
|
|
||||||
return next == STRUCT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasStruct(int id) throws IOException {
|
|
||||||
if(id < 0 || id > 255) throw new IllegalArgumentException();
|
|
||||||
if(!hasLookahead) readLookahead();
|
|
||||||
if(eof) return false;
|
|
||||||
return next == STRUCT && (nextStructId & 0xFF) == id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readStructStart(int id) throws IOException {
|
|
||||||
if(!hasStruct(id)) throw new FormatException();
|
|
||||||
consumeLookahead();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasStructEnd() throws IOException {
|
|
||||||
return hasEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readStructEnd() throws IOException {
|
|
||||||
readEnd();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void skipStruct() throws IOException {
|
|
||||||
if(!hasStruct()) throw new FormatException();
|
|
||||||
hasLookahead = false;
|
|
||||||
while(!hasStructEnd()) skipObject();
|
|
||||||
hasLookahead = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasNull() throws IOException {
|
|
||||||
if(!hasLookahead) readLookahead();
|
|
||||||
if(eof) return false;
|
|
||||||
return next == NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void readNull() throws IOException {
|
|
||||||
if(!hasNull()) throw new FormatException();
|
|
||||||
consumeLookahead();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void skipNull() throws IOException {
|
|
||||||
if(!hasNull()) throw new FormatException();
|
|
||||||
hasLookahead = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,16 +15,6 @@ class SerialComponentImpl implements SerialComponent {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSerialisedStructStartLength(int id) {
|
|
||||||
// STRUCT tag, 8-bit ID
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSerialisedStructEndLength() {
|
|
||||||
// END tag
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getSerialisedUniqueIdLength() {
|
public int getSerialisedUniqueIdLength() {
|
||||||
// BYTES_8, BYTES_16 or BYTES_32 tag, length, bytes
|
// BYTES_8, BYTES_16 or BYTES_32 tag, length, bytes
|
||||||
return 1 + getLengthBytes(UniqueId.LENGTH) + UniqueId.LENGTH;
|
return 1 + getLengthBytes(UniqueId.LENGTH) + UniqueId.LENGTH;
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
package org.briarproject.serial;
|
|
||||||
|
|
||||||
interface Tag {
|
|
||||||
|
|
||||||
byte FALSE = 0x00;
|
|
||||||
byte TRUE = 0x01;
|
|
||||||
byte INTEGER_8 = 0x02;
|
|
||||||
byte INTEGER_16 = 0x03;
|
|
||||||
byte INTEGER_32 = 0x04;
|
|
||||||
byte INTEGER_64 = 0x05;
|
|
||||||
byte FLOAT = 0x06;
|
|
||||||
byte STRING_8 = 0x07;
|
|
||||||
byte STRING_16 = 0x08;
|
|
||||||
byte STRING_32 = 0x09;
|
|
||||||
byte BYTES_8 = 0x0A;
|
|
||||||
byte BYTES_16 = 0x0B;
|
|
||||||
byte BYTES_32 = 0x0C;
|
|
||||||
byte LIST = 0x0D;
|
|
||||||
byte MAP = 0x0E;
|
|
||||||
byte STRUCT = 0x0F;
|
|
||||||
byte END = 0x10;
|
|
||||||
byte NULL = 0x11;
|
|
||||||
}
|
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
package org.briarproject.serial;
|
package org.briarproject.serial;
|
||||||
|
|
||||||
import static org.briarproject.serial.Tag.BYTES_16;
|
import static org.briarproject.serial.ObjectTypes.BOOLEAN;
|
||||||
import static org.briarproject.serial.Tag.BYTES_32;
|
import static org.briarproject.serial.ObjectTypes.END;
|
||||||
import static org.briarproject.serial.Tag.BYTES_8;
|
import static org.briarproject.serial.ObjectTypes.FLOAT_64;
|
||||||
import static org.briarproject.serial.Tag.FALSE;
|
import static org.briarproject.serial.ObjectTypes.INT_16;
|
||||||
import static org.briarproject.serial.Tag.FLOAT;
|
import static org.briarproject.serial.ObjectTypes.INT_32;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_16;
|
import static org.briarproject.serial.ObjectTypes.INT_64;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_32;
|
import static org.briarproject.serial.ObjectTypes.INT_8;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_64;
|
import static org.briarproject.serial.ObjectTypes.LIST;
|
||||||
import static org.briarproject.serial.Tag.INTEGER_8;
|
import static org.briarproject.serial.ObjectTypes.MAP;
|
||||||
import static org.briarproject.serial.Tag.STRING_16;
|
import static org.briarproject.serial.ObjectTypes.NULL;
|
||||||
import static org.briarproject.serial.Tag.STRING_32;
|
import static org.briarproject.serial.ObjectTypes.RAW_16;
|
||||||
import static org.briarproject.serial.Tag.STRING_8;
|
import static org.briarproject.serial.ObjectTypes.RAW_32;
|
||||||
import static org.briarproject.serial.Tag.TRUE;
|
import static org.briarproject.serial.ObjectTypes.RAW_8;
|
||||||
|
import static org.briarproject.serial.ObjectTypes.STRING_16;
|
||||||
|
import static org.briarproject.serial.ObjectTypes.STRING_32;
|
||||||
|
import static org.briarproject.serial.ObjectTypes.STRING_8;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@@ -52,23 +55,28 @@ class WriterImpl implements Writer {
|
|||||||
if(!consumers.remove(c)) throw new IllegalArgumentException();
|
if(!consumers.remove(c)) throw new IllegalArgumentException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeNull() throws IOException {
|
||||||
|
write(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
public void writeBoolean(boolean b) throws IOException {
|
public void writeBoolean(boolean b) throws IOException {
|
||||||
if(b) write(TRUE);
|
write(BOOLEAN);
|
||||||
else write(FALSE);
|
if(b) write((byte) 1);
|
||||||
|
else write((byte) 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeInteger(long i) throws IOException {
|
public void writeInteger(long i) throws IOException {
|
||||||
if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
|
if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) {
|
||||||
write(INTEGER_8);
|
write(INT_8);
|
||||||
write((byte) i);
|
write((byte) i);
|
||||||
} else if(i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
|
} else if(i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) {
|
||||||
write(INTEGER_16);
|
write(INT_16);
|
||||||
writeInt16((short) i);
|
writeInt16((short) i);
|
||||||
} else if(i >= Integer.MIN_VALUE && i <= Integer.MAX_VALUE) {
|
} else if(i >= Integer.MIN_VALUE && i <= Integer.MAX_VALUE) {
|
||||||
write(INTEGER_32);
|
write(INT_32);
|
||||||
writeInt32((int) i);
|
writeInt32((int) i);
|
||||||
} else {
|
} else {
|
||||||
write(INTEGER_64);
|
write(INT_64);
|
||||||
writeInt64(i);
|
writeInt64(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,7 +105,7 @@ class WriterImpl implements Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeFloat(double d) throws IOException {
|
public void writeFloat(double d) throws IOException {
|
||||||
write(FLOAT);
|
write(FLOAT_64);
|
||||||
writeInt64(Double.doubleToRawLongBits(d));
|
writeInt64(Double.doubleToRawLongBits(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,22 +126,22 @@ class WriterImpl implements Writer {
|
|||||||
|
|
||||||
public void writeBytes(byte[] b) throws IOException {
|
public void writeBytes(byte[] b) throws IOException {
|
||||||
if(b.length <= Byte.MAX_VALUE) {
|
if(b.length <= Byte.MAX_VALUE) {
|
||||||
write(BYTES_8);
|
write(RAW_8);
|
||||||
write((byte) b.length);
|
write((byte) b.length);
|
||||||
} else if(b.length <= Short.MAX_VALUE) {
|
} else if(b.length <= Short.MAX_VALUE) {
|
||||||
write(BYTES_16);
|
write(RAW_16);
|
||||||
writeInt16((short) b.length);
|
writeInt16((short) b.length);
|
||||||
} else {
|
} else {
|
||||||
write(BYTES_32);
|
write(RAW_32);
|
||||||
writeInt32(b.length);
|
writeInt32(b.length);
|
||||||
}
|
}
|
||||||
write(b);
|
write(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeList(Collection<?> c) throws IOException {
|
public void writeList(Collection<?> c) throws IOException {
|
||||||
write(Tag.LIST);
|
write(ObjectTypes.LIST);
|
||||||
for(Object o : c) writeObject(o);
|
for(Object o : c) writeObject(o);
|
||||||
write(Tag.END);
|
write(ObjectTypes.END);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeObject(Object o) throws IOException {
|
private void writeObject(Object o) throws IOException {
|
||||||
@@ -154,42 +162,28 @@ class WriterImpl implements Writer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void writeListStart() throws IOException {
|
public void writeListStart() throws IOException {
|
||||||
write(Tag.LIST);
|
write(LIST);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeListEnd() throws IOException {
|
public void writeListEnd() throws IOException {
|
||||||
write(Tag.END);
|
write(END);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeMap(Map<?, ?> m) throws IOException {
|
public void writeMap(Map<?, ?> m) throws IOException {
|
||||||
write(Tag.MAP);
|
write(MAP);
|
||||||
for(Entry<?, ?> e : m.entrySet()) {
|
for(Entry<?, ?> e : m.entrySet()) {
|
||||||
writeObject(e.getKey());
|
writeObject(e.getKey());
|
||||||
writeObject(e.getValue());
|
writeObject(e.getValue());
|
||||||
}
|
}
|
||||||
write(Tag.END);
|
write(END);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeMapStart() throws IOException {
|
public void writeMapStart() throws IOException {
|
||||||
write(Tag.MAP);
|
write(MAP);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void writeMapEnd() throws IOException {
|
public void writeMapEnd() throws IOException {
|
||||||
write(Tag.END);
|
write(END);
|
||||||
}
|
|
||||||
|
|
||||||
public void writeStructStart(int id) throws IOException {
|
|
||||||
if(id < 0 || id > 255) throw new IllegalArgumentException();
|
|
||||||
write(Tag.STRUCT);
|
|
||||||
write((byte) id);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeStructEnd() throws IOException {
|
|
||||||
write(Tag.END);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void writeNull() throws IOException {
|
|
||||||
write(Tag.NULL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void write(byte b) throws IOException {
|
private void write(byte b) throws IOException {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import static org.briarproject.api.TransportPropertyConstants.MAX_TRANSPORT_ID_L
|
|||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_BODY_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_CONTENT_TYPE_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_GROUP_NAME_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_GROUP_NAME_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_SUBSCRIPTIONS;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -106,7 +106,7 @@ public class ConstantsTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMessageIdsFitIntoLargeAck() throws Exception {
|
public void testMessageIdsFitIntoLargeAck() throws Exception {
|
||||||
testMessageIdsFitIntoAck(MAX_PACKET_LENGTH);
|
testMessageIdsFitIntoAck(MAX_PAYLOAD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -139,12 +139,12 @@ public class ConstantsTest extends BriarTestCase {
|
|||||||
+ MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH
|
+ MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH
|
||||||
+ MAX_PUBLIC_KEY_LENGTH + MAX_CONTENT_TYPE_LENGTH
|
+ MAX_PUBLIC_KEY_LENGTH + MAX_CONTENT_TYPE_LENGTH
|
||||||
+ MAX_BODY_LENGTH);
|
+ MAX_BODY_LENGTH);
|
||||||
assertTrue(length <= MAX_PACKET_LENGTH);
|
assertTrue(length <= MAX_PAYLOAD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMessageIdsFitIntoLargeOffer() throws Exception {
|
public void testMessageIdsFitIntoLargeOffer() throws Exception {
|
||||||
testMessageIdsFitIntoOffer(MAX_PACKET_LENGTH);
|
testMessageIdsFitIntoOffer(MAX_PAYLOAD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -154,7 +154,7 @@ public class ConstantsTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMessageIdsFitIntoLargeRequest() throws Exception {
|
public void testMessageIdsFitIntoLargeRequest() throws Exception {
|
||||||
testMessageIdsFitIntoRequest(MAX_PACKET_LENGTH);
|
testMessageIdsFitIntoRequest(MAX_PAYLOAD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -180,7 +180,7 @@ public class ConstantsTest extends BriarTestCase {
|
|||||||
PacketWriter writer = packetWriterFactory.createPacketWriter(out);
|
PacketWriter writer = packetWriterFactory.createPacketWriter(out);
|
||||||
writer.writeTransportUpdate(u);
|
writer.writeTransportUpdate(u);
|
||||||
// Check the size of the serialised transport update
|
// Check the size of the serialised transport update
|
||||||
assertTrue(out.size() <= MAX_PACKET_LENGTH);
|
assertTrue(out.size() <= MAX_PAYLOAD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -198,7 +198,7 @@ public class ConstantsTest extends BriarTestCase {
|
|||||||
PacketWriter writer = packetWriterFactory.createPacketWriter(out);
|
PacketWriter writer = packetWriterFactory.createPacketWriter(out);
|
||||||
writer.writeSubscriptionUpdate(u);
|
writer.writeSubscriptionUpdate(u);
|
||||||
// Check the size of the serialised subscription update
|
// Check the size of the serialised subscription update
|
||||||
assertTrue(out.size() <= MAX_PACKET_LENGTH);
|
assertTrue(out.size() <= MAX_PAYLOAD_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testMessageIdsFitIntoAck(int length) throws Exception {
|
private void testMessageIdsFitIntoAck(int length) throws Exception {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package org.briarproject.messaging;
|
package org.briarproject.messaging;
|
||||||
|
|
||||||
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
|
import static org.briarproject.api.messaging.MessagingConstants.HEADER_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.ACK;
|
import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH;
|
||||||
import static org.briarproject.api.messaging.Types.OFFER;
|
import static org.briarproject.api.messaging.PacketTypes.ACK;
|
||||||
import static org.briarproject.api.messaging.Types.REQUEST;
|
import static org.briarproject.api.messaging.PacketTypes.OFFER;
|
||||||
|
import static org.briarproject.api.messaging.PacketTypes.REQUEST;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
@@ -16,6 +17,7 @@ import org.briarproject.api.serial.SerialComponent;
|
|||||||
import org.briarproject.api.serial.Writer;
|
import org.briarproject.api.serial.Writer;
|
||||||
import org.briarproject.api.serial.WriterFactory;
|
import org.briarproject.api.serial.WriterFactory;
|
||||||
import org.briarproject.serial.SerialModule;
|
import org.briarproject.serial.SerialModule;
|
||||||
|
import org.briarproject.util.ByteUtils;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import com.google.inject.Guice;
|
import com.google.inject.Guice;
|
||||||
@@ -137,85 +139,106 @@ public class PacketReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
private byte[] createAck(boolean tooBig) throws Exception {
|
private byte[] createAck(boolean tooBig) throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(new byte[HEADER_LENGTH]);
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
w.writeStructStart(ACK);
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
while(out.size() + serial.getSerialisedUniqueIdLength()
|
while(out.size() + serial.getSerialisedUniqueIdLength()
|
||||||
+ serial.getSerialisedListEndLength()
|
+ serial.getSerialisedListEndLength() * 2
|
||||||
+ serial.getSerialisedStructEndLength()
|
< HEADER_LENGTH + MAX_PAYLOAD_LENGTH) {
|
||||||
< MAX_PACKET_LENGTH) {
|
|
||||||
w.writeBytes(TestUtils.getRandomId());
|
w.writeBytes(TestUtils.getRandomId());
|
||||||
}
|
}
|
||||||
if(tooBig) w.writeBytes(TestUtils.getRandomId());
|
if(tooBig) w.writeBytes(TestUtils.getRandomId());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
|
assertEquals(tooBig, out.size() > HEADER_LENGTH + MAX_PAYLOAD_LENGTH);
|
||||||
return out.toByteArray();
|
byte[] packet = out.toByteArray();
|
||||||
|
packet[1] = ACK;
|
||||||
|
ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2);
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createEmptyAck() throws Exception {
|
private byte[] createEmptyAck() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(new byte[HEADER_LENGTH]);
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
w.writeStructStart(ACK);
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
return out.toByteArray();
|
byte[] packet = out.toByteArray();
|
||||||
|
packet[1] = ACK;
|
||||||
|
ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2);
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createOffer(boolean tooBig) throws Exception {
|
private byte[] createOffer(boolean tooBig) throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(new byte[HEADER_LENGTH]);
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
w.writeStructStart(OFFER);
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
while(out.size() + serial.getSerialisedUniqueIdLength()
|
while(out.size() + serial.getSerialisedUniqueIdLength()
|
||||||
+ serial.getSerialisedListEndLength()
|
+ serial.getSerialisedListEndLength() * 2
|
||||||
+ serial.getSerialisedStructEndLength()
|
< HEADER_LENGTH + MAX_PAYLOAD_LENGTH) {
|
||||||
< MAX_PACKET_LENGTH) {
|
|
||||||
w.writeBytes(TestUtils.getRandomId());
|
w.writeBytes(TestUtils.getRandomId());
|
||||||
}
|
}
|
||||||
if(tooBig) w.writeBytes(TestUtils.getRandomId());
|
if(tooBig) w.writeBytes(TestUtils.getRandomId());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
|
assertEquals(tooBig, out.size() > HEADER_LENGTH + MAX_PAYLOAD_LENGTH);
|
||||||
return out.toByteArray();
|
byte[] packet = out.toByteArray();
|
||||||
|
packet[1] = OFFER;
|
||||||
|
ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2);
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createEmptyOffer() throws Exception {
|
private byte[] createEmptyOffer() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(new byte[HEADER_LENGTH]);
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
w.writeStructStart(OFFER);
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
return out.toByteArray();
|
byte[] packet = out.toByteArray();
|
||||||
|
packet[1] = OFFER;
|
||||||
|
ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2);
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createRequest(boolean tooBig) throws Exception {
|
private byte[] createRequest(boolean tooBig) throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(new byte[HEADER_LENGTH]);
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
w.writeStructStart(REQUEST);
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
while(out.size() + serial.getSerialisedUniqueIdLength()
|
while(out.size() + serial.getSerialisedUniqueIdLength()
|
||||||
+ serial.getSerialisedListEndLength()
|
+ serial.getSerialisedListEndLength() * 2
|
||||||
+ serial.getSerialisedStructEndLength()
|
< HEADER_LENGTH + MAX_PAYLOAD_LENGTH) {
|
||||||
< MAX_PACKET_LENGTH) {
|
|
||||||
w.writeBytes(TestUtils.getRandomId());
|
w.writeBytes(TestUtils.getRandomId());
|
||||||
}
|
}
|
||||||
if(tooBig) w.writeBytes(TestUtils.getRandomId());
|
if(tooBig) w.writeBytes(TestUtils.getRandomId());
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH);
|
assertEquals(tooBig, out.size() > HEADER_LENGTH + MAX_PAYLOAD_LENGTH);
|
||||||
return out.toByteArray();
|
byte[] packet = out.toByteArray();
|
||||||
|
packet[1] = REQUEST;
|
||||||
|
ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2);
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte[] createEmptyRequest() throws Exception {
|
private byte[] createEmptyRequest() throws Exception {
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
out.write(new byte[HEADER_LENGTH]);
|
||||||
Writer w = writerFactory.createWriter(out);
|
Writer w = writerFactory.createWriter(out);
|
||||||
w.writeStructStart(REQUEST);
|
w.writeListStart();
|
||||||
w.writeListStart();
|
w.writeListStart();
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
w.writeStructEnd();
|
w.writeListEnd();
|
||||||
return out.toByteArray();
|
byte[] packet = out.toByteArray();
|
||||||
|
packet[1] = REQUEST;
|
||||||
|
ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2);
|
||||||
|
return packet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,29 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
private ByteArrayInputStream in = null;
|
private ByteArrayInputStream in = null;
|
||||||
private ReaderImpl r = null;
|
private ReaderImpl r = null;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadEmptyInput() throws Exception {
|
||||||
|
setContents("");
|
||||||
|
assertTrue(r.eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReadNull() throws Exception {
|
||||||
|
setContents("00");
|
||||||
|
r.readNull();
|
||||||
|
assertTrue(r.eof());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSkipNull() throws Exception {
|
||||||
|
setContents("00");
|
||||||
|
r.skipNull();
|
||||||
|
assertTrue(r.eof());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadBoolean() throws Exception {
|
public void testReadBoolean() throws Exception {
|
||||||
setContents("00" + "01");
|
setContents("11" + "00" + "11" + "01");
|
||||||
assertFalse(r.readBoolean());
|
assertFalse(r.readBoolean());
|
||||||
assertTrue(r.readBoolean());
|
assertTrue(r.readBoolean());
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
@@ -25,7 +45,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipBoolean() throws Exception {
|
public void testSkipBoolean() throws Exception {
|
||||||
setContents("00" + "01");
|
setContents("11" + "00" + "11" + "01");
|
||||||
r.skipBoolean();
|
r.skipBoolean();
|
||||||
r.skipBoolean();
|
r.skipBoolean();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
@@ -33,8 +53,8 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadInt8() throws Exception {
|
public void testReadInt8() throws Exception {
|
||||||
setContents("02" + "00" + "02" + "FF"
|
setContents("21" + "00" + "21" + "FF"
|
||||||
+ "02" + "7F" + "02" + "80");
|
+ "21" + "7F" + "21" + "80");
|
||||||
assertEquals(0, r.readInteger());
|
assertEquals(0, r.readInteger());
|
||||||
assertEquals(-1, r.readInteger());
|
assertEquals(-1, r.readInteger());
|
||||||
assertEquals(Byte.MAX_VALUE, r.readInteger());
|
assertEquals(Byte.MAX_VALUE, r.readInteger());
|
||||||
@@ -44,15 +64,15 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipInt8() throws Exception {
|
public void testSkipInt8() throws Exception {
|
||||||
setContents("02" + "00");
|
setContents("21" + "00");
|
||||||
r.skipInteger();
|
r.skipInteger();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadInt16() throws Exception {
|
public void testReadInt16() throws Exception {
|
||||||
setContents("03" + "0080" + "03" + "FF7F"
|
setContents("22" + "0080" + "22" + "FF7F"
|
||||||
+ "03" + "7FFF" + "03" + "8000");
|
+ "22" + "7FFF" + "22" + "8000");
|
||||||
assertEquals(Byte.MAX_VALUE + 1, r.readInteger());
|
assertEquals(Byte.MAX_VALUE + 1, r.readInteger());
|
||||||
assertEquals(Byte.MIN_VALUE - 1, r.readInteger());
|
assertEquals(Byte.MIN_VALUE - 1, r.readInteger());
|
||||||
assertEquals(Short.MAX_VALUE, r.readInteger());
|
assertEquals(Short.MAX_VALUE, r.readInteger());
|
||||||
@@ -62,15 +82,15 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipInt16() throws Exception {
|
public void testSkipInt16() throws Exception {
|
||||||
setContents("03" + "0080");
|
setContents("22" + "0080");
|
||||||
r.skipInteger();
|
r.skipInteger();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadInt32() throws Exception {
|
public void testReadInt32() throws Exception {
|
||||||
setContents("04" + "00008000" + "04" + "FFFF7FFF"
|
setContents("24" + "00008000" + "24" + "FFFF7FFF"
|
||||||
+ "04" + "7FFFFFFF" + "04" + "80000000");
|
+ "24" + "7FFFFFFF" + "24" + "80000000");
|
||||||
assertEquals(Short.MAX_VALUE + 1, r.readInteger());
|
assertEquals(Short.MAX_VALUE + 1, r.readInteger());
|
||||||
assertEquals(Short.MIN_VALUE - 1, r.readInteger());
|
assertEquals(Short.MIN_VALUE - 1, r.readInteger());
|
||||||
assertEquals(Integer.MAX_VALUE, r.readInteger());
|
assertEquals(Integer.MAX_VALUE, r.readInteger());
|
||||||
@@ -80,15 +100,15 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipInt32() throws Exception {
|
public void testSkipInt32() throws Exception {
|
||||||
setContents("04" + "00008000");
|
setContents("24" + "00008000");
|
||||||
r.skipInteger();
|
r.skipInteger();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadInt64() throws Exception {
|
public void testReadInt64() throws Exception {
|
||||||
setContents("05" + "0000000080000000" + "05" + "FFFFFFFF7FFFFFFF"
|
setContents("28" + "0000000080000000" + "28" + "FFFFFFFF7FFFFFFF"
|
||||||
+ "05" + "7FFFFFFFFFFFFFFF" + "05" + "8000000000000000");
|
+ "28" + "7FFFFFFFFFFFFFFF" + "28" + "8000000000000000");
|
||||||
assertEquals(Integer.MAX_VALUE + 1L, r.readInteger());
|
assertEquals(Integer.MAX_VALUE + 1L, r.readInteger());
|
||||||
assertEquals(Integer.MIN_VALUE - 1L, r.readInteger());
|
assertEquals(Integer.MIN_VALUE - 1L, r.readInteger());
|
||||||
assertEquals(Long.MAX_VALUE, r.readInteger());
|
assertEquals(Long.MAX_VALUE, r.readInteger());
|
||||||
@@ -98,7 +118,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipInt64() throws Exception {
|
public void testSkipInt64() throws Exception {
|
||||||
setContents("05" + "0000000080000000");
|
setContents("28" + "0000000080000000");
|
||||||
r.skipInteger();
|
r.skipInteger();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
@@ -106,39 +126,39 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testIntegersMustHaveMinimalLength() throws Exception {
|
public void testIntegersMustHaveMinimalLength() throws Exception {
|
||||||
// INTEGER_16 could be encoded as INTEGER_8
|
// INTEGER_16 could be encoded as INTEGER_8
|
||||||
setContents("02" + "7F" + "03" + "007F");
|
setContents("21" + "7F" + "22" + "007F");
|
||||||
assertEquals(Byte.MAX_VALUE, r.readInteger());
|
assertEquals(Byte.MAX_VALUE, r.readInteger());
|
||||||
try {
|
try {
|
||||||
r.readInteger();
|
r.readInteger();
|
||||||
fail();
|
fail();
|
||||||
} catch(FormatException expected) {}
|
} catch(FormatException expected) {}
|
||||||
setContents("02" + "80" + "03" + "FF80");
|
setContents("21" + "80" + "22" + "FF80");
|
||||||
assertEquals(Byte.MIN_VALUE, r.readInteger());
|
assertEquals(Byte.MIN_VALUE, r.readInteger());
|
||||||
try {
|
try {
|
||||||
r.readInteger();
|
r.readInteger();
|
||||||
fail();
|
fail();
|
||||||
} catch(FormatException expected) {}
|
} catch(FormatException expected) {}
|
||||||
// INTEGER_32 could be encoded as INTEGER_16
|
// INTEGER_32 could be encoded as INTEGER_16
|
||||||
setContents("03" + "7FFF" + "04" + "00007FFF");
|
setContents("22" + "7FFF" + "24" + "00007FFF");
|
||||||
assertEquals(Short.MAX_VALUE, r.readInteger());
|
assertEquals(Short.MAX_VALUE, r.readInteger());
|
||||||
try {
|
try {
|
||||||
r.readInteger();
|
r.readInteger();
|
||||||
fail();
|
fail();
|
||||||
} catch(FormatException expected) {}
|
} catch(FormatException expected) {}
|
||||||
setContents("03" + "8000" + "04" + "FFFF8000");
|
setContents("22" + "8000" + "24" + "FFFF8000");
|
||||||
assertEquals(Short.MIN_VALUE, r.readInteger());
|
assertEquals(Short.MIN_VALUE, r.readInteger());
|
||||||
try {
|
try {
|
||||||
r.readInteger();
|
r.readInteger();
|
||||||
fail();
|
fail();
|
||||||
} catch(FormatException expected) {}
|
} catch(FormatException expected) {}
|
||||||
// INTEGER_64 could be encoded as INTEGER_32
|
// INTEGER_64 could be encoded as INTEGER_32
|
||||||
setContents("04" + "7FFFFFFF" + "05" + "000000007FFFFFFF");
|
setContents("24" + "7FFFFFFF" + "28" + "000000007FFFFFFF");
|
||||||
assertEquals(Integer.MAX_VALUE, r.readInteger());
|
assertEquals(Integer.MAX_VALUE, r.readInteger());
|
||||||
try {
|
try {
|
||||||
r.readInteger();
|
r.readInteger();
|
||||||
fail();
|
fail();
|
||||||
} catch(FormatException expected) {}
|
} catch(FormatException expected) {}
|
||||||
setContents("04" + "80000000" + "05" + "FFFFFFFF80000000");
|
setContents("24" + "80000000" + "28" + "FFFFFFFF80000000");
|
||||||
assertEquals(Integer.MIN_VALUE, r.readInteger());
|
assertEquals(Integer.MIN_VALUE, r.readInteger());
|
||||||
try {
|
try {
|
||||||
r.readInteger();
|
r.readInteger();
|
||||||
@@ -150,10 +170,10 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
public void testReadFloat() throws Exception {
|
public void testReadFloat() throws Exception {
|
||||||
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
|
// http://babbage.cs.qc.edu/IEEE-754/Decimal.html
|
||||||
// http://steve.hollasch.net/cgindex/coding/ieeefloat.html
|
// http://steve.hollasch.net/cgindex/coding/ieeefloat.html
|
||||||
setContents("06" + "0000000000000000" + "06" + "3FF0000000000000"
|
setContents("38" + "0000000000000000" + "38" + "3FF0000000000000"
|
||||||
+ "06" + "4000000000000000" + "06" + "BFF0000000000000"
|
+ "38" + "4000000000000000" + "38" + "BFF0000000000000"
|
||||||
+ "06" + "8000000000000000" + "06" + "FFF0000000000000"
|
+ "38" + "8000000000000000" + "38" + "FFF0000000000000"
|
||||||
+ "06" + "7FF0000000000000" + "06" + "7FF8000000000000");
|
+ "38" + "7FF0000000000000" + "38" + "7FF8000000000000");
|
||||||
assertEquals(0.0, r.readFloat());
|
assertEquals(0.0, r.readFloat());
|
||||||
assertEquals(1.0, r.readFloat());
|
assertEquals(1.0, r.readFloat());
|
||||||
assertEquals(2.0, r.readFloat());
|
assertEquals(2.0, r.readFloat());
|
||||||
@@ -167,7 +187,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipFloat() throws Exception {
|
public void testSkipFloat() throws Exception {
|
||||||
setContents("06" + "0000000000000000");
|
setContents("38" + "0000000000000000");
|
||||||
r.skipFloat();
|
r.skipFloat();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
@@ -177,8 +197,8 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
String longest = TestUtils.createRandomString(Byte.MAX_VALUE);
|
String longest = TestUtils.createRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("07" + "03" + "666F6F" + "07" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"07" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
assertEquals("foo", r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals("", r.readString(Integer.MAX_VALUE));
|
assertEquals("", r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
||||||
@@ -188,7 +208,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadString8ChecksMaxLength() throws Exception {
|
public void testReadString8ChecksMaxLength() throws Exception {
|
||||||
// "foo" twice
|
// "foo" twice
|
||||||
setContents("07" + "03" + "666F6F" + "07" + "03" + "666F6F");
|
setContents("41" + "03" + "666F6F" + "41" + "03" + "666F6F");
|
||||||
assertEquals("foo", r.readString(3));
|
assertEquals("foo", r.readString(3));
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
try {
|
try {
|
||||||
@@ -202,26 +222,14 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
String longest = TestUtils.createRandomString(Byte.MAX_VALUE);
|
String longest = TestUtils.createRandomString(Byte.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// "foo", the empty string, and 127 random letters
|
// "foo", the empty string, and 127 random letters
|
||||||
setContents("07" + "03" + "666F6F" + "07" + "00" +
|
setContents("41" + "03" + "666F6F" + "41" + "00" +
|
||||||
"07" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
r.skipString(Integer.MAX_VALUE);
|
r.skipString();
|
||||||
r.skipString(Integer.MAX_VALUE);
|
r.skipString();
|
||||||
r.skipString(Integer.MAX_VALUE);
|
r.skipString();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipString8ChecksMaxLength() throws Exception {
|
|
||||||
// "foo" twice
|
|
||||||
setContents("07" + "03" + "666F6F" + "07" + "03" + "666F6F");
|
|
||||||
r.skipString(3);
|
|
||||||
assertTrue(r.hasString());
|
|
||||||
try {
|
|
||||||
r.skipString(2);
|
|
||||||
fail();
|
|
||||||
} catch(FormatException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString16() throws Exception {
|
public void testReadString16() throws Exception {
|
||||||
String shortest = TestUtils.createRandomString(Byte.MAX_VALUE + 1);
|
String shortest = TestUtils.createRandomString(Byte.MAX_VALUE + 1);
|
||||||
@@ -229,7 +237,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
String longest = TestUtils.createRandomString(Short.MAX_VALUE);
|
String longest = TestUtils.createRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 -1 random letters
|
// 128 random letters and 2^15 -1 random letters
|
||||||
setContents("08" + "0080" + shortHex + "08" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
||||||
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest, r.readString(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
@@ -240,7 +248,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
String shortest = TestUtils.createRandomString(Byte.MAX_VALUE + 1);
|
String shortest = TestUtils.createRandomString(Byte.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 128 random letters, twice
|
// 128 random letters, twice
|
||||||
setContents("08" + "0080" + shortHex + "08" + "0080" + shortHex);
|
setContents("42" + "0080" + shortHex + "42" + "0080" + shortHex);
|
||||||
assertEquals(shortest, r.readString(Byte.MAX_VALUE + 1));
|
assertEquals(shortest, r.readString(Byte.MAX_VALUE + 1));
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
try {
|
try {
|
||||||
@@ -256,32 +264,18 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
String longest = TestUtils.createRandomString(Short.MAX_VALUE);
|
String longest = TestUtils.createRandomString(Short.MAX_VALUE);
|
||||||
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
String longHex = StringUtils.toHexString(longest.getBytes("UTF-8"));
|
||||||
// 128 random letters and 2^15 - 1 random letters
|
// 128 random letters and 2^15 - 1 random letters
|
||||||
setContents("08" + "0080" + shortHex + "08" + "7FFF" + longHex);
|
setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
r.skipString(Integer.MAX_VALUE);
|
r.skipString();
|
||||||
r.skipString(Integer.MAX_VALUE);
|
r.skipString();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipString16ChecksMaxLength() throws Exception {
|
|
||||||
String shortest = TestUtils.createRandomString(Byte.MAX_VALUE + 1);
|
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
|
||||||
// 128 random letters, twice
|
|
||||||
setContents("08" + "0080" + shortHex + "08" + "0080" + shortHex);
|
|
||||||
r.skipString(Byte.MAX_VALUE + 1);
|
|
||||||
assertTrue(r.hasString());
|
|
||||||
try {
|
|
||||||
r.skipString(Byte.MAX_VALUE);
|
|
||||||
fail();
|
|
||||||
} catch(FormatException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadString32() throws Exception {
|
public void testReadString32() throws Exception {
|
||||||
String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1);
|
String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters
|
// 2^15 random letters
|
||||||
setContents("09" + "00008000" + shortHex);
|
setContents("44" + "00008000" + shortHex);
|
||||||
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
assertEquals(shortest, r.readString(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
@@ -291,8 +285,8 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1);
|
String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters, twice
|
// 2^15 random letters, twice
|
||||||
setContents("09" + "00008000" + shortHex +
|
setContents("44" + "00008000" + shortHex +
|
||||||
"09" + "00008000" + shortHex);
|
"44" + "00008000" + shortHex);
|
||||||
assertEquals(shortest, r.readString(Short.MAX_VALUE + 1));
|
assertEquals(shortest, r.readString(Short.MAX_VALUE + 1));
|
||||||
assertTrue(r.hasString());
|
assertTrue(r.hasString());
|
||||||
try {
|
try {
|
||||||
@@ -306,34 +300,19 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1);
|
String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1);
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
// 2^15 random letters, twice
|
// 2^15 random letters, twice
|
||||||
setContents("09" + "00008000" + shortHex +
|
setContents("44" + "00008000" + shortHex +
|
||||||
"09" + "00008000" + shortHex);
|
"44" + "00008000" + shortHex);
|
||||||
r.skipString(Integer.MAX_VALUE);
|
r.skipString();
|
||||||
r.skipString(Integer.MAX_VALUE);
|
r.skipString();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipString32ChecksMaxLength() throws Exception {
|
|
||||||
String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1);
|
|
||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
|
||||||
// 2^15 random letters, twice
|
|
||||||
setContents("09" + "00008000" + shortHex +
|
|
||||||
"09" + "00008000" + shortHex);
|
|
||||||
r.skipString(Short.MAX_VALUE + 1);
|
|
||||||
assertTrue(r.hasString());
|
|
||||||
try {
|
|
||||||
r.skipString(Short.MAX_VALUE);
|
|
||||||
fail();
|
|
||||||
} catch(FormatException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStringsMustHaveMinimalLength() throws Exception {
|
public void testStringsMustHaveMinimalLength() throws Exception {
|
||||||
// STRING_16 could be encoded as STRING_8
|
// STRING_16 could be encoded as STRING_8
|
||||||
String longest8 = TestUtils.createRandomString(Byte.MAX_VALUE);
|
String longest8 = TestUtils.createRandomString(Byte.MAX_VALUE);
|
||||||
String long8Hex = StringUtils.toHexString(longest8.getBytes("UTF-8"));
|
String long8Hex = StringUtils.toHexString(longest8.getBytes("UTF-8"));
|
||||||
setContents("07" + "7F" + long8Hex + "08" + "007F" + long8Hex);
|
setContents("41" + "7F" + long8Hex + "42" + "007F" + long8Hex);
|
||||||
assertEquals(longest8, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest8, r.readString(Integer.MAX_VALUE));
|
||||||
try {
|
try {
|
||||||
r.readString(Integer.MAX_VALUE);
|
r.readString(Integer.MAX_VALUE);
|
||||||
@@ -342,7 +321,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
// STRING_32 could be encoded as STRING_16
|
// STRING_32 could be encoded as STRING_16
|
||||||
String longest16 = TestUtils.createRandomString(Short.MAX_VALUE);
|
String longest16 = TestUtils.createRandomString(Short.MAX_VALUE);
|
||||||
String long16Hex = StringUtils.toHexString(longest16.getBytes("UTF-8"));
|
String long16Hex = StringUtils.toHexString(longest16.getBytes("UTF-8"));
|
||||||
setContents("08" + "7FFF" + long16Hex + "09" + "00007FFF" + long16Hex);
|
setContents("42" + "7FFF" + long16Hex + "44" + "00007FFF" + long16Hex);
|
||||||
assertEquals(longest16, r.readString(Integer.MAX_VALUE));
|
assertEquals(longest16, r.readString(Integer.MAX_VALUE));
|
||||||
try {
|
try {
|
||||||
r.readString(Integer.MAX_VALUE);
|
r.readString(Integer.MAX_VALUE);
|
||||||
@@ -355,8 +334,8 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("0A" + "03" + "010203" + "0A" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"0A" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(Integer.MAX_VALUE));
|
||||||
assertArrayEquals(new byte[0], r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(new byte[0], r.readBytes(Integer.MAX_VALUE));
|
||||||
assertArrayEquals(longest, r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(longest, r.readBytes(Integer.MAX_VALUE));
|
||||||
@@ -366,7 +345,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadBytes8ChecksMaxLength() throws Exception {
|
public void testReadBytes8ChecksMaxLength() throws Exception {
|
||||||
// {1, 2, 3} twice
|
// {1, 2, 3} twice
|
||||||
setContents("0A" + "03" + "010203" + "0A" + "03" + "010203");
|
setContents("51" + "03" + "010203" + "51" + "03" + "010203");
|
||||||
assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(3));
|
assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(3));
|
||||||
assertTrue(r.hasBytes());
|
assertTrue(r.hasBytes());
|
||||||
try {
|
try {
|
||||||
@@ -380,26 +359,14 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
byte[] longest = new byte[Byte.MAX_VALUE];
|
byte[] longest = new byte[Byte.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// {1, 2, 3}, {}, and 127 zero bytes
|
// {1, 2, 3}, {}, and 127 zero bytes
|
||||||
setContents("0A" + "03" + "010203" + "0A" + "00" +
|
setContents("51" + "03" + "010203" + "51" + "00" +
|
||||||
"0A" + "7F" + longHex);
|
"51" + "7F" + longHex);
|
||||||
r.skipBytes(Integer.MAX_VALUE);
|
r.skipBytes();
|
||||||
r.skipBytes(Integer.MAX_VALUE);
|
r.skipBytes();
|
||||||
r.skipBytes(Integer.MAX_VALUE);
|
r.skipBytes();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipBytes8ChecksMaxLength() throws Exception {
|
|
||||||
// {1, 2, 3} twice
|
|
||||||
setContents("0A" + "03" + "010203" + "0A" + "03" + "010203");
|
|
||||||
r.skipBytes(3);
|
|
||||||
assertTrue(r.hasBytes());
|
|
||||||
try {
|
|
||||||
r.skipBytes(2);
|
|
||||||
fail();
|
|
||||||
} catch(FormatException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadBytes16() throws Exception {
|
public void testReadBytes16() throws Exception {
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
@@ -407,7 +374,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("0B" + "0080" + shortHex + "0B" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
assertArrayEquals(shortest, r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(shortest, r.readBytes(Integer.MAX_VALUE));
|
||||||
assertArrayEquals(longest, r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(longest, r.readBytes(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
@@ -418,7 +385,7 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
// 128 zero bytes, twice
|
// 128 zero bytes, twice
|
||||||
setContents("0B" + "0080" + shortHex + "0B" + "0080" + shortHex);
|
setContents("52" + "0080" + shortHex + "52" + "0080" + shortHex);
|
||||||
assertArrayEquals(shortest, r.readBytes(Byte.MAX_VALUE + 1));
|
assertArrayEquals(shortest, r.readBytes(Byte.MAX_VALUE + 1));
|
||||||
assertTrue(r.hasBytes());
|
assertTrue(r.hasBytes());
|
||||||
try {
|
try {
|
||||||
@@ -434,32 +401,18 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
byte[] longest = new byte[Short.MAX_VALUE];
|
byte[] longest = new byte[Short.MAX_VALUE];
|
||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
// 128 zero bytes and 2^15 - 1 zero bytes
|
// 128 zero bytes and 2^15 - 1 zero bytes
|
||||||
setContents("0B" + "0080" + shortHex + "0B" + "7FFF" + longHex);
|
setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
r.skipBytes(Integer.MAX_VALUE);
|
r.skipBytes();
|
||||||
r.skipBytes(Integer.MAX_VALUE);
|
r.skipBytes();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipBytes16ChecksMaxLength() throws Exception {
|
|
||||||
byte[] shortest = new byte[Byte.MAX_VALUE + 1];
|
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
|
||||||
// 128 zero bytes, twice
|
|
||||||
setContents("0B" + "0080" + shortHex + "0B" + "0080" + shortHex);
|
|
||||||
r.skipBytes(Byte.MAX_VALUE + 1);
|
|
||||||
assertTrue(r.hasBytes());
|
|
||||||
try {
|
|
||||||
r.skipBytes(Byte.MAX_VALUE);
|
|
||||||
fail();
|
|
||||||
} catch(FormatException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadBytes32() throws Exception {
|
public void testReadBytes32() throws Exception {
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
// 2^15 zero bytes
|
// 2^15 zero bytes
|
||||||
setContents("0C" + "00008000" + shortHex);
|
setContents("54" + "00008000" + shortHex);
|
||||||
assertArrayEquals(shortest, r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(shortest, r.readBytes(Integer.MAX_VALUE));
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
@@ -469,8 +422,8 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
// 2^15 zero bytes, twice
|
// 2^15 zero bytes, twice
|
||||||
setContents("0C" + "00008000" + shortHex +
|
setContents("54" + "00008000" + shortHex +
|
||||||
"0C" + "00008000" + shortHex);
|
"54" + "00008000" + shortHex);
|
||||||
assertArrayEquals(shortest, r.readBytes(Short.MAX_VALUE + 1));
|
assertArrayEquals(shortest, r.readBytes(Short.MAX_VALUE + 1));
|
||||||
assertTrue(r.hasBytes());
|
assertTrue(r.hasBytes());
|
||||||
try {
|
try {
|
||||||
@@ -484,43 +437,28 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
// 2^15 zero bytes, twice
|
// 2^15 zero bytes, twice
|
||||||
setContents("0C" + "00008000" + shortHex +
|
setContents("54" + "00008000" + shortHex +
|
||||||
"0C" + "00008000" + shortHex);
|
"54" + "00008000" + shortHex);
|
||||||
r.skipBytes(Integer.MAX_VALUE);
|
r.skipBytes();
|
||||||
r.skipBytes(Integer.MAX_VALUE);
|
r.skipBytes();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipBytes32ChecksMaxLength() throws Exception {
|
|
||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
|
||||||
// 2^15 zero bytes, twice
|
|
||||||
setContents("0C" + "00008000" + shortHex +
|
|
||||||
"0C" + "00008000" + shortHex);
|
|
||||||
r.skipBytes(Short.MAX_VALUE + 1);
|
|
||||||
assertTrue(r.hasBytes());
|
|
||||||
try {
|
|
||||||
r.skipBytes(Short.MAX_VALUE);
|
|
||||||
fail();
|
|
||||||
} catch(FormatException expected) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBytesMustHaveMinimalLength() throws Exception {
|
public void testBytesMustHaveMinimalLength() throws Exception {
|
||||||
// BYTES_16 could be encoded as BYTES_8
|
// RAW_16 could be encoded as RAW_8
|
||||||
byte[] longest8 = new byte[Byte.MAX_VALUE];
|
byte[] longest8 = new byte[Byte.MAX_VALUE];
|
||||||
String long8Hex = StringUtils.toHexString(longest8);
|
String long8Hex = StringUtils.toHexString(longest8);
|
||||||
setContents("0A" + "7F" + long8Hex + "0B" + "007F" + long8Hex);
|
setContents("51" + "7F" + long8Hex + "52" + "007F" + long8Hex);
|
||||||
assertArrayEquals(longest8, r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(longest8, r.readBytes(Integer.MAX_VALUE));
|
||||||
try {
|
try {
|
||||||
r.readBytes(Integer.MAX_VALUE);
|
r.readBytes(Integer.MAX_VALUE);
|
||||||
fail();
|
fail();
|
||||||
} catch(FormatException expected) {}
|
} catch(FormatException expected) {}
|
||||||
// BYTES_32 could be encoded as BYTES_16
|
// RAW_32 could be encoded as RAW_16
|
||||||
byte[] longest16 = new byte[Short.MAX_VALUE];
|
byte[] longest16 = new byte[Short.MAX_VALUE];
|
||||||
String long16Hex = StringUtils.toHexString(longest16);
|
String long16Hex = StringUtils.toHexString(longest16);
|
||||||
setContents("0B" + "7FFF" + long16Hex + "0C" + "00007FFF" + long16Hex);
|
setContents("52" + "7FFF" + long16Hex + "54" + "00007FFF" + long16Hex);
|
||||||
assertArrayEquals(longest16, r.readBytes(Integer.MAX_VALUE));
|
assertArrayEquals(longest16, r.readBytes(Integer.MAX_VALUE));
|
||||||
try {
|
try {
|
||||||
r.readBytes(Integer.MAX_VALUE);
|
r.readBytes(Integer.MAX_VALUE);
|
||||||
@@ -531,9 +469,9 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testReadList() throws Exception {
|
public void testReadList() throws Exception {
|
||||||
// A list containing 1, "foo", and 128
|
// A list containing 1, "foo", and 128
|
||||||
setContents("0D" + "02" + "01" +
|
setContents("60" + "21" + "01" +
|
||||||
"07" + "03" + "666F6F" +
|
"41" + "03" + "666F6F" +
|
||||||
"03" + "0080" + "10");
|
"22" + "0080" + "80");
|
||||||
r.readListStart();
|
r.readListStart();
|
||||||
assertFalse(r.hasListEnd());
|
assertFalse(r.hasListEnd());
|
||||||
assertEquals(1, r.readInteger());
|
assertEquals(1, r.readInteger());
|
||||||
@@ -549,25 +487,25 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testSkipList() throws Exception {
|
public void testSkipList() throws Exception {
|
||||||
// A list containing 1, "foo", and 128
|
// A list containing 1, "foo", and 128
|
||||||
setContents("0D" + "02" + "01" +
|
setContents("60" + "21" + "01" +
|
||||||
"07" + "03" + "666F6F" +
|
"41" + "03" + "666F6F" +
|
||||||
"03" + "0080" + "10");
|
"22" + "0080" + "80");
|
||||||
r.skipList();
|
r.skipList();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadMap() throws Exception {
|
public void testReadMap() throws Exception {
|
||||||
// A map containing "foo" -> 123 and byte[0] -> null
|
// A map containing "foo" -> 123 and "bar" -> null
|
||||||
setContents("0E" + "07" + "03" + "666F6F" + "02" + "7B" +
|
setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
|
||||||
"0A" + "00" + "11" + "10");
|
"41" + "03" + "626172" + "00" + "80");
|
||||||
r.readMapStart();
|
r.readMapStart();
|
||||||
assertFalse(r.hasMapEnd());
|
assertFalse(r.hasMapEnd());
|
||||||
assertEquals("foo", r.readString(1000));
|
assertEquals("foo", r.readString(1000));
|
||||||
assertFalse(r.hasMapEnd());
|
assertFalse(r.hasMapEnd());
|
||||||
assertEquals(123, r.readInteger());
|
assertEquals(123, r.readInteger());
|
||||||
assertFalse(r.hasMapEnd());
|
assertFalse(r.hasMapEnd());
|
||||||
assertArrayEquals(new byte[0], r.readBytes(1000));
|
assertEquals("bar", r.readString(1000));
|
||||||
assertFalse(r.hasMapEnd());
|
assertFalse(r.hasMapEnd());
|
||||||
assertTrue(r.hasNull());
|
assertTrue(r.hasNull());
|
||||||
r.readNull();
|
r.readNull();
|
||||||
@@ -578,58 +516,18 @@ public class ReaderImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSkipMap() throws Exception {
|
public void testSkipMap() throws Exception {
|
||||||
// A map containing "foo" -> 123 and byte[0] -> null
|
// A map containing "foo" -> 123 and "bar" -> null
|
||||||
setContents("0E" + "07" + "03" + "666F6F" + "02" + "7B" +
|
setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" +
|
||||||
"0A" + "00" + "11" + "10");
|
"41" + "03" + "626172" + "00" + "80");
|
||||||
r.skipMap();
|
r.skipMap();
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadStruct() throws Exception {
|
public void testSkipNestedListsAndMaps() throws Exception {
|
||||||
// Two empty structs with IDs 0 and 255
|
// A list containing a map containing two empty lists
|
||||||
setContents("0F00" + "10" + "0FFF" + "10");
|
setContents("60" + "70" + "60" + "80" + "60" + "80" + "80" + "80");
|
||||||
r.readStructStart(0);
|
r.skipList();
|
||||||
r.readStructEnd();
|
|
||||||
r.readStructStart(255);
|
|
||||||
r.readStructEnd();
|
|
||||||
assertTrue(r.eof());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipStruct() throws Exception {
|
|
||||||
// Two empty structs with IDs 0 and 255
|
|
||||||
setContents("0F00" + "10" + "0FFF" + "10");
|
|
||||||
r.skipStruct();
|
|
||||||
r.skipStruct();
|
|
||||||
assertTrue(r.eof());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipNestedStructMapAndList() throws Exception {
|
|
||||||
// A struct containing a map containing two empty lists
|
|
||||||
setContents("0F00" + "0E" + "0D" + "10" + "0D" + "10" + "10" + "10");
|
|
||||||
r.skipStruct();
|
|
||||||
assertTrue(r.eof());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadNull() throws Exception {
|
|
||||||
setContents("11");
|
|
||||||
r.readNull();
|
|
||||||
assertTrue(r.eof());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSkipNull() throws Exception {
|
|
||||||
setContents("11");
|
|
||||||
r.skipNull();
|
|
||||||
assertTrue(r.eof());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadEmptyInput() throws Exception {
|
|
||||||
setContents("");
|
|
||||||
assertTrue(r.eof());
|
assertTrue(r.eof());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,18 +19,25 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
private ByteArrayOutputStream out = null;
|
private ByteArrayOutputStream out = null;
|
||||||
private WriterImpl w = null;
|
private WriterImpl w = null;
|
||||||
|
|
||||||
|
@Override
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
out = new ByteArrayOutputStream();
|
out = new ByteArrayOutputStream();
|
||||||
w = new WriterImpl(out);
|
w = new WriterImpl(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testWriteNull() throws IOException {
|
||||||
|
w.writeNull();
|
||||||
|
checkContents("00");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteBoolean() throws IOException {
|
public void testWriteBoolean() throws IOException {
|
||||||
w.writeBoolean(true);
|
w.writeBoolean(true);
|
||||||
w.writeBoolean(false);
|
w.writeBoolean(false);
|
||||||
// TRUE tag, FALSE tag
|
// BOOLEAN tag, 1, BOOLEAN tag, 0
|
||||||
checkContents("01" + "00");
|
checkContents("11" + "01" + "11" + "00");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -46,11 +53,11 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
w.writeInteger(Long.MAX_VALUE);
|
w.writeInteger(Long.MAX_VALUE);
|
||||||
w.writeInteger(Long.MIN_VALUE);
|
w.writeInteger(Long.MIN_VALUE);
|
||||||
// INTEGER_8 tag, 0, INTEGER_8 tag, -1, etc
|
// INTEGER_8 tag, 0, INTEGER_8 tag, -1, etc
|
||||||
checkContents("02" + "00" + "02" + "FF" +
|
checkContents("21" + "00" + "21" + "FF" +
|
||||||
"02" + "7F" + "02" + "80" +
|
"21" + "7F" + "21" + "80" +
|
||||||
"03" + "7FFF" + "03" + "8000" +
|
"22" + "7FFF" + "22" + "8000" +
|
||||||
"04" + "7FFFFFFF" + "04" + "80000000" +
|
"24" + "7FFFFFFF" + "24" + "80000000" +
|
||||||
"05" + "7FFFFFFFFFFFFFFF" + "05" + "8000000000000000");
|
"28" + "7FFFFFFFFFFFFFFF" + "28" + "8000000000000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -65,10 +72,10 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
w.writeFloat(Double.NEGATIVE_INFINITY); // 1 2047 0 -> 0xFFF00000...
|
w.writeFloat(Double.NEGATIVE_INFINITY); // 1 2047 0 -> 0xFFF00000...
|
||||||
w.writeFloat(Double.POSITIVE_INFINITY); // 0 2047 0 -> 0x7FF00000...
|
w.writeFloat(Double.POSITIVE_INFINITY); // 0 2047 0 -> 0x7FF00000...
|
||||||
w.writeFloat(Double.NaN); // 0 2047 1 -> 0x7FF8000000000000
|
w.writeFloat(Double.NaN); // 0 2047 1 -> 0x7FF8000000000000
|
||||||
checkContents("06" + "0000000000000000" + "06" + "3FF0000000000000"
|
checkContents("38" + "0000000000000000" + "38" + "3FF0000000000000"
|
||||||
+ "06" + "4000000000000000" + "06" + "BFF0000000000000"
|
+ "38" + "4000000000000000" + "38" + "BFF0000000000000"
|
||||||
+ "06" + "8000000000000000" + "06" + "FFF0000000000000"
|
+ "38" + "8000000000000000" + "38" + "FFF0000000000000"
|
||||||
+ "06" + "7FF0000000000000" + "06" + "7FF8000000000000");
|
+ "38" + "7FF0000000000000" + "38" + "7FF8000000000000");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -79,8 +86,8 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
w.writeString(longest);
|
w.writeString(longest);
|
||||||
// STRING_8 tag, length 16, UTF-8 bytes, STRING_8 tag, length 127,
|
// STRING_8 tag, length 16, UTF-8 bytes, STRING_8 tag, length 127,
|
||||||
// UTF-8 bytes
|
// UTF-8 bytes
|
||||||
checkContents("07" + "10" + "666F6F206261722062617A2062616D20" +
|
checkContents("41" + "10" + "666F6F206261722062617A2062616D20" +
|
||||||
"07" + "7F" + longHex);
|
"41" + "7F" + longHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -93,7 +100,7 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
w.writeString(longest);
|
w.writeString(longest);
|
||||||
// STRING_16 tag, length 128, UTF-8 bytes, STRING_16 tag,
|
// STRING_16 tag, length 128, UTF-8 bytes, STRING_16 tag,
|
||||||
// length 2^15 - 1, UTF-8 bytes
|
// length 2^15 - 1, UTF-8 bytes
|
||||||
checkContents("08" + "0080" + shortHex + "08" + "7FFF" + longHex);
|
checkContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -102,7 +109,7 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8"));
|
||||||
w.writeString(shortest);
|
w.writeString(shortest);
|
||||||
// STRING_32 tag, length 2^15, UTF-8 bytes
|
// STRING_32 tag, length 2^15, UTF-8 bytes
|
||||||
checkContents("09" + "00008000" + shortHex);
|
checkContents("44" + "00008000" + shortHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -111,8 +118,8 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
w.writeBytes(new byte[] {1, 2, 3});
|
w.writeBytes(new byte[] {1, 2, 3});
|
||||||
w.writeBytes(longest);
|
w.writeBytes(longest);
|
||||||
// BYTES_8 tag, length 3, bytes, BYTES_8 tag, length 127, bytes
|
// RAW_8 tag, length 3, bytes, RAW_8 tag, length 127, bytes
|
||||||
checkContents("0A" + "03" + "010203" + "0A" + "7F" + longHex);
|
checkContents("51" + "03" + "010203" + "51" + "7F" + longHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -123,8 +130,8 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
String longHex = StringUtils.toHexString(longest);
|
String longHex = StringUtils.toHexString(longest);
|
||||||
w.writeBytes(shortest);
|
w.writeBytes(shortest);
|
||||||
w.writeBytes(longest);
|
w.writeBytes(longest);
|
||||||
// BYTES_16 tag, length 128, bytes, BYTES_16 tag, length 2^15 - 1, bytes
|
// RAW_16 tag, length 128, bytes, RAW_16 tag, length 2^15 - 1, bytes
|
||||||
checkContents("0B" + "0080" + shortHex + "0B" + "7FFF" + longHex);
|
checkContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -132,8 +139,8 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
byte[] shortest = new byte[Short.MAX_VALUE + 1];
|
||||||
String shortHex = StringUtils.toHexString(shortest);
|
String shortHex = StringUtils.toHexString(shortest);
|
||||||
w.writeBytes(shortest);
|
w.writeBytes(shortest);
|
||||||
// BYTES_32 tag, length 2^15, bytes
|
// RAW_32 tag, length 2^15, bytes
|
||||||
checkContents("0C" + "00008000" + shortHex);
|
checkContents("54" + "00008000" + shortHex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -142,7 +149,7 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
for(int i = 0; i < 3; i++) l.add(i);
|
for(int i = 0; i < 3; i++) l.add(i);
|
||||||
w.writeList(l);
|
w.writeList(l);
|
||||||
// LIST tag, elements as integers, END tag
|
// LIST tag, elements as integers, END tag
|
||||||
checkContents("0D" + "02" + "00" + "02" + "01" + "02" + "02" + "10");
|
checkContents("60" + "21" + "00" + "21" + "01" + "21" + "02" + "80");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -153,20 +160,20 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
l.add(2);
|
l.add(2);
|
||||||
w.writeList(l);
|
w.writeList(l);
|
||||||
// LIST tag, 1 as integer, NULL tag, 2 as integer, END tag
|
// LIST tag, 1 as integer, NULL tag, 2 as integer, END tag
|
||||||
checkContents("0D" + "02" + "01" + "11" + "02" + "02" + "10");
|
checkContents("60" + "21" + "01" + "00" + "21" + "02" + "80");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteMap() throws IOException {
|
public void testWriteMap() throws IOException {
|
||||||
// Use LinkedHashMap to get predictable iteration order
|
// Use LinkedHashMap to get predictable iteration order
|
||||||
Map<Object, Object> m = new LinkedHashMap<Object, Object>();
|
Map<String, Object> m = new LinkedHashMap<String, Object>();
|
||||||
for(int i = 0; i < 4; i++) m.put(i, i + 1);
|
for(int i = 0; i < 4; i++) m.put(String.valueOf(i), i);
|
||||||
w.writeMap(m);
|
w.writeMap(m);
|
||||||
// MAP tag, entries as integers, END tag
|
// MAP tag, keys as strings and values as integers, END tag
|
||||||
checkContents("0E" + "02" + "00" + "02" + "01" +
|
checkContents("70" + "41" + "01" + "30" + "21" + "00" +
|
||||||
"02" + "01" + "02" + "02" +
|
"41" + "01" + "31" + "21" + "01" +
|
||||||
"02" + "02" + "02" + "03" +
|
"41" + "01" + "32" + "21" + "02" +
|
||||||
"02" + "03" + "02" + "04" + "10");
|
"41" + "01" + "33" + "21" + "03" + "80");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -177,9 +184,9 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
w.writeInteger(128);
|
w.writeInteger(128);
|
||||||
w.writeListEnd();
|
w.writeListEnd();
|
||||||
// LIST tag, 1 as integer, "foo" as string, 128 as integer, END tag
|
// LIST tag, 1 as integer, "foo" as string, 128 as integer, END tag
|
||||||
checkContents("0D" + "02" + "01" +
|
checkContents("60" + "21" + "01" +
|
||||||
"07" + "03" + "666F6F" +
|
"41" + "03" + "666F6F" +
|
||||||
"03" + "0080" + "10");
|
"22" + "0080" + "80");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -187,42 +194,30 @@ public class WriterImplTest extends BriarTestCase {
|
|||||||
w.writeMapStart();
|
w.writeMapStart();
|
||||||
w.writeString("foo");
|
w.writeString("foo");
|
||||||
w.writeInteger(123);
|
w.writeInteger(123);
|
||||||
w.writeBytes(new byte[0]);
|
w.writeString("bar");
|
||||||
w.writeNull();
|
w.writeNull();
|
||||||
w.writeMapEnd();
|
w.writeMapEnd();
|
||||||
// MAP tag, "foo" as string, 123 as integer, {} as bytes, NULL tag,
|
// MAP tag, "foo" as string, 123 as integer, "bar" as string,
|
||||||
// END tag
|
// NULL tag, END tag
|
||||||
checkContents("0E" + "07" + "03" + "666F6F" +
|
checkContents("70" + "41" + "03" + "666F6F" +
|
||||||
"02" + "7B" + "0A" + "00" + "11" + "10");
|
"21" + "7B" + "41" + "03" + "626172" + "00" + "80");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testWriteNestedMapsAndLists() throws IOException {
|
public void testWriteNestedMapsAndLists() throws IOException {
|
||||||
Map<Object, Object> m = new LinkedHashMap<Object, Object>();
|
Map<String, Object> inner = new LinkedHashMap<String, Object>();
|
||||||
m.put("foo", 123);
|
inner.put("bar", new byte[0]);
|
||||||
List<Object> l = new ArrayList<Object>();
|
List<Object> list = new ArrayList<Object>();
|
||||||
l.add((byte) 1);
|
list.add(1);
|
||||||
Map<Object, Object> m1 = new LinkedHashMap<Object, Object>();
|
list.add(inner);
|
||||||
m1.put(m, l);
|
Map<String, Object> outer = new LinkedHashMap<String, Object>();
|
||||||
w.writeMap(m1);
|
outer.put("foo", list);
|
||||||
// MAP tag, MAP tag, "foo" as string, 123 as integer, END tag,
|
w.writeMap(outer);
|
||||||
// LIST tag, 1 as integer, END tag, END tag
|
// MAP tag, "foo" as string, LIST tag, 1 as integer, MAP tag,
|
||||||
checkContents("0E" + "0E" + "07" + "03" + "666F6F" +
|
// "bar" as string, {} as raw, END tag, END tag, END tag
|
||||||
"02" + "7B" + "10" + "0D" + "02" + "01" + "10" + "10");
|
checkContents("70" + "41" + "03" + "666F6F" + "60" +
|
||||||
}
|
"21" + "01" + "70" + "41" + "03" + "626172" + "51" + "00" +
|
||||||
|
"80" + "80" + "80");
|
||||||
@Test
|
|
||||||
public void testWriteStruct() throws IOException {
|
|
||||||
w.writeStructStart(123);
|
|
||||||
w.writeStructEnd();
|
|
||||||
// STRUCT tag, 123 as struct ID, END tag
|
|
||||||
checkContents("0F" + "7B" + "10");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWriteNull() throws IOException {
|
|
||||||
w.writeNull();
|
|
||||||
checkContents("11");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkContents(String hex) throws IOException {
|
private void checkContents(String hex) throws IOException {
|
||||||
|
|||||||
Reference in New Issue
Block a user