diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index d46693223a4a7e7a2c27fac869d0769494c633e8..e3c64dfbd81a544360b5879ffa8539dd96c9e5d1 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -1,8 +1,8 @@ <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="org.briarproject" - android:versionCode="9" - android:versionName="0.9" > + android:versionCode="10" + android:versionName="0.10" > <uses-sdk android:minSdkVersion="7" diff --git a/briar-api/src/org/briarproject/api/messaging/MessagingConstants.java b/briar-api/src/org/briarproject/api/messaging/MessagingConstants.java index 0f52b490100a54f6a7352d7a09db211a1d426342..fefe79a3ba996414a5a85340bfca18447a16b612 100644 --- a/briar-api/src/org/briarproject/api/messaging/MessagingConstants.java +++ b/briar-api/src/org/briarproject/api/messaging/MessagingConstants.java @@ -1,18 +1,19 @@ package org.briarproject.api.messaging; -import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH; public interface MessagingConstants { - /** - * The maximum length of a serialised packet in bytes. To allow for future - * changes in the protocol, this is smaller than the minimum stream length - * minus the maximum encryption and authentication overhead. - */ - int MAX_PACKET_LENGTH = MIN_STREAM_LENGTH / 2; + /** The current version of the messaging protocol. */ + byte PROTOCOL_VERSION = 0; + + /** The length of the packet header in bytes. */ + int HEADER_LENGTH = 4; + + /** 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. */ - int MAX_SUBSCRIPTIONS = 3000; + int MAX_SUBSCRIPTIONS = 300; /** The maximum length of a group's name in UTF-8 bytes. */ 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 - * 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. */ - 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. */ int MAX_CONTENT_TYPE_LENGTH = 50; diff --git a/briar-api/src/org/briarproject/api/messaging/PacketTypes.java b/briar-api/src/org/briarproject/api/messaging/PacketTypes.java new file mode 100644 index 0000000000000000000000000000000000000000..41c2eee6f7c7cc5d5c7b5b6102995208eb81c007 --- /dev/null +++ b/briar-api/src/org/briarproject/api/messaging/PacketTypes.java @@ -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; +} diff --git a/briar-api/src/org/briarproject/api/messaging/Types.java b/briar-api/src/org/briarproject/api/messaging/Types.java deleted file mode 100644 index 83db6e6c9bff9690b9152360ff77a6e02a3a1501..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/messaging/Types.java +++ /dev/null @@ -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; -} diff --git a/briar-api/src/org/briarproject/api/serial/ObjectReader.java b/briar-api/src/org/briarproject/api/serial/ObjectReader.java new file mode 100644 index 0000000000000000000000000000000000000000..4606c33004c6c35495e5e730ee143987ac337a38 --- /dev/null +++ b/briar-api/src/org/briarproject/api/serial/ObjectReader.java @@ -0,0 +1,8 @@ +package org.briarproject.api.serial; + +import java.io.IOException; + +public interface ObjectReader<T> { + + T readObject(Reader r) throws IOException; +} diff --git a/briar-api/src/org/briarproject/api/serial/Reader.java b/briar-api/src/org/briarproject/api/serial/Reader.java index 59113c414c9bea2659a7257216191f611f9188cf..401ec7930f053da660af55aeb5c94a9d83a010c4 100644 --- a/briar-api/src/org/briarproject/api/serial/Reader.java +++ b/briar-api/src/org/briarproject/api/serial/Reader.java @@ -10,6 +10,10 @@ public interface Reader { void addConsumer(Consumer c); void removeConsumer(Consumer c); + boolean hasNull() throws IOException; + void readNull() throws IOException; + void skipNull() throws IOException; + boolean hasBoolean() throws IOException; boolean readBoolean() throws IOException; void skipBoolean() throws IOException; @@ -24,11 +28,11 @@ public interface Reader { boolean hasString() throws IOException; String readString(int maxLength) throws IOException; - void skipString(int maxLength) throws IOException; + void skipString() throws IOException; boolean hasBytes() throws IOException; byte[] readBytes(int maxLength) throws IOException; - void skipBytes(int maxLength) throws IOException; + void skipBytes() throws IOException; boolean hasList() throws IOException; void readListStart() throws IOException; @@ -41,15 +45,4 @@ public interface Reader { boolean hasMapEnd() throws IOException; void readMapEnd() 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; } diff --git a/briar-api/src/org/briarproject/api/serial/SerialComponent.java b/briar-api/src/org/briarproject/api/serial/SerialComponent.java index be3d6196849d3cc4702b68cbe57f85b59d639d7d..ecaf2c365779802d55faf4594f99386183ffed11 100644 --- a/briar-api/src/org/briarproject/api/serial/SerialComponent.java +++ b/briar-api/src/org/briarproject/api/serial/SerialComponent.java @@ -6,9 +6,5 @@ public interface SerialComponent { int getSerialisedListEndLength(); - int getSerialisedStructStartLength(int id); - - int getSerialisedStructEndLength(); - int getSerialisedUniqueIdLength(); } diff --git a/briar-api/src/org/briarproject/api/serial/StructReader.java b/briar-api/src/org/briarproject/api/serial/StructReader.java deleted file mode 100644 index 14e14746645b898a5c10c1b8978b8e3eeafb86db..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/serial/StructReader.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.briarproject.api.serial; - -import java.io.IOException; - -public interface StructReader<T> { - - T readStruct(Reader r) throws IOException; -} diff --git a/briar-api/src/org/briarproject/api/serial/Writer.java b/briar-api/src/org/briarproject/api/serial/Writer.java index 2ad638bbc83382b7a50f2792a4c57822d31ee3b1..3d70451172ca94a5bf3f96cff4692e869e63ad73 100644 --- a/briar-api/src/org/briarproject/api/serial/Writer.java +++ b/briar-api/src/org/briarproject/api/serial/Writer.java @@ -12,6 +12,7 @@ public interface Writer { void addConsumer(Consumer c); void removeConsumer(Consumer c); + void writeNull() throws IOException; void writeBoolean(boolean b) throws IOException; void writeInteger(long l) throws IOException; void writeFloat(double d) throws IOException; @@ -25,9 +26,4 @@ public interface Writer { void writeMap(Map<?, ?> m) throws IOException; void writeMapStart() throws IOException; void writeMapEnd() throws IOException; - - void writeStructStart(int id) throws IOException; - void writeStructEnd() throws IOException; - - void writeNull() throws IOException; } diff --git a/briar-api/src/org/briarproject/api/transport/TransportConstants.java b/briar-api/src/org/briarproject/api/transport/TransportConstants.java index 8f05eb23ab9c9ecf44608671176c67ae1b861657..51444c4c791ec34cb2f7b50131264a0063889ea9 100644 --- a/briar-api/src/org/briarproject/api/transport/TransportConstants.java +++ b/briar-api/src/org/briarproject/api/transport/TransportConstants.java @@ -26,7 +26,7 @@ public interface TransportConstants { * support. Streams may be shorter than this length, but all transport * 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. */ int MAX_CLOCK_DIFFERENCE = 60 * 60 * 1000; // 1 hour diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java index 06402b1cce6a0dc2424d41929631bc7580119af8..13248ddca728067ff32657803212eef1a1038912 100644 --- a/briar-core/src/org/briarproject/db/JdbcDatabase.java +++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java @@ -64,8 +64,8 @@ import org.briarproject.api.transport.TemporarySecret; */ abstract class JdbcDatabase implements Database<Connection> { - private static final int SCHEMA_VERSION = 8; - private static final int MIN_SCHEMA_VERSION = 8; + private static final int SCHEMA_VERSION = 9; + private static final int MIN_SCHEMA_VERSION = 9; private static final String CREATE_SETTINGS = "CREATE TABLE settings" diff --git a/briar-core/src/org/briarproject/messaging/AuthorFactoryImpl.java b/briar-core/src/org/briarproject/messaging/AuthorFactoryImpl.java index 6fca9a6c8ebea5ed1b881e8bcf88be9070c6623d..e9c05a92a1c912e30507c746c425a11401e3de9e 100644 --- a/briar-core/src/org/briarproject/messaging/AuthorFactoryImpl.java +++ b/briar-core/src/org/briarproject/messaging/AuthorFactoryImpl.java @@ -1,7 +1,5 @@ package org.briarproject.messaging; -import static org.briarproject.api.messaging.Types.AUTHOR; - import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -45,10 +43,10 @@ class AuthorFactoryImpl implements AuthorFactory { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); try { - w.writeStructStart(AUTHOR); + w.writeListStart(); w.writeString(name); w.writeBytes(publicKey); - w.writeStructEnd(); + w.writeListEnd(); } catch(IOException e) { // Shouldn't happen with ByteArrayOutputStream throw new RuntimeException(); diff --git a/briar-core/src/org/briarproject/messaging/AuthorReader.java b/briar-core/src/org/briarproject/messaging/AuthorReader.java index b30e10920cdc17bc3dc91a21325f9b1e43cc9767..cdb1c958aee50458f7cc31aaf735f1abf9aa4ffc 100644 --- a/briar-core/src/org/briarproject/messaging/AuthorReader.java +++ b/briar-core/src/org/briarproject/messaging/AuthorReader.java @@ -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_PUBLIC_KEY_LENGTH; -import static org.briarproject.api.messaging.Types.AUTHOR; import java.io.IOException; @@ -13,9 +12,9 @@ import org.briarproject.api.crypto.CryptoComponent; import org.briarproject.api.crypto.MessageDigest; import org.briarproject.api.serial.DigestingConsumer; 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; @@ -23,16 +22,16 @@ class AuthorReader implements StructReader<Author> { messageDigest = crypto.getMessageDigest(); } - public Author readStruct(Reader r) throws IOException { + public Author readObject(Reader r) throws IOException { // Set up the reader DigestingConsumer digesting = new DigestingConsumer(messageDigest); r.addConsumer(digesting); // Read and digest the data - r.readStructStart(AUTHOR); + r.readListStart(); String name = r.readString(MAX_AUTHOR_NAME_LENGTH); if(name.length() == 0) throw new FormatException(); byte[] publicKey = r.readBytes(MAX_PUBLIC_KEY_LENGTH); - r.readStructEnd(); + r.readListEnd(); // Reset the reader r.removeConsumer(digesting); // Build and return the author diff --git a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java index 23177097f912900e73d18b20c320528d6aa5bda6..c64c768182eda51cfb6ed414ddb6d25c5e2bcbda 100644 --- a/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/messaging/DuplexOutgoingSession.java @@ -3,7 +3,7 @@ package org.briarproject.messaging; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; 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.util.Collection; @@ -260,7 +260,7 @@ class DuplexOutgoingSession implements MessagingSession, EventListener { if(interrupted) return; try { Collection<byte[]> b = db.generateRequestedBatch(contactId, - MAX_PACKET_LENGTH, maxLatency); + MAX_PAYLOAD_LENGTH, maxLatency); if(LOG.isLoggable(INFO)) LOG.info("Generated batch: " + (b != null)); if(b != null) writerTasks.add(new WriteBatch(b)); diff --git a/briar-core/src/org/briarproject/messaging/GroupFactoryImpl.java b/briar-core/src/org/briarproject/messaging/GroupFactoryImpl.java index ec88fca9c03dc4423f11a2b0d22a879d85c08f87..b2f3e0cad9e0895def2e98353ae03d1f96a5318e 100644 --- a/briar-core/src/org/briarproject/messaging/GroupFactoryImpl.java +++ b/briar-core/src/org/briarproject/messaging/GroupFactoryImpl.java @@ -1,7 +1,6 @@ package org.briarproject.messaging; 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.IOException; @@ -37,10 +36,10 @@ class GroupFactoryImpl implements GroupFactory { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); try { - w.writeStructStart(GROUP); + w.writeListStart(); w.writeString(name); w.writeBytes(salt); - w.writeStructEnd(); + w.writeListEnd(); } catch(IOException e) { // Shouldn't happen with ByteArrayOutputStream throw new RuntimeException(); diff --git a/briar-core/src/org/briarproject/messaging/GroupReader.java b/briar-core/src/org/briarproject/messaging/GroupReader.java index 771bfe6e648da54b28047422a1b6e43e2a8ffad1..1bfd090f8dbc03b9d784a713eeff50a389a5b70a 100644 --- a/briar-core/src/org/briarproject/messaging/GroupReader.java +++ b/briar-core/src/org/briarproject/messaging/GroupReader.java @@ -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.MAX_GROUP_NAME_LENGTH; -import static org.briarproject.api.messaging.Types.GROUP; import java.io.IOException; @@ -13,9 +12,9 @@ import org.briarproject.api.messaging.Group; import org.briarproject.api.messaging.GroupId; import org.briarproject.api.serial.DigestingConsumer; 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; @@ -23,16 +22,16 @@ class GroupReader implements StructReader<Group> { messageDigest = crypto.getMessageDigest(); } - public Group readStruct(Reader r) throws IOException { + public Group readObject(Reader r) throws IOException { DigestingConsumer digesting = new DigestingConsumer(messageDigest); // Read and digest the data r.addConsumer(digesting); - r.readStructStart(GROUP); + r.readListStart(); String name = r.readString(MAX_GROUP_NAME_LENGTH); if(name.length() == 0) throw new FormatException(); byte[] salt = r.readBytes(GROUP_SALT_LENGTH); if(salt.length != GROUP_SALT_LENGTH) throw new FormatException(); - r.readStructEnd(); + r.readListEnd(); r.removeConsumer(digesting); // Build and return the group GroupId id = new GroupId(messageDigest.digest()); diff --git a/briar-core/src/org/briarproject/messaging/MessageFactoryImpl.java b/briar-core/src/org/briarproject/messaging/MessageFactoryImpl.java index 4b144ad5b3095ea6a00ced620020b6e91b9d5fa6..03a1b7d3992cc0f192569844037bfa31c7878f55 100644 --- a/briar-core/src/org/briarproject/messaging/MessageFactoryImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessageFactoryImpl.java @@ -3,11 +3,8 @@ package org.briarproject.messaging; 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_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.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.IOException; @@ -77,7 +74,7 @@ class MessageFactoryImpl implements MessageFactory { ByteArrayOutputStream out = new ByteArrayOutputStream(); Writer w = writerFactory.createWriter(out); // Initialise the consumers - CountingConsumer counting = new CountingConsumer(MAX_PACKET_LENGTH); + CountingConsumer counting = new CountingConsumer(MAX_PAYLOAD_LENGTH); w.addConsumer(counting); Consumer digestingConsumer = new DigestingConsumer(messageDigest); w.addConsumer(digestingConsumer); @@ -88,7 +85,7 @@ class MessageFactoryImpl implements MessageFactory { w.addConsumer(signingConsumer); } // Write the message - w.writeStructStart(MESSAGE); + w.writeListStart(); if(parent == null) w.writeNull(); else w.writeBytes(parent.getBytes()); writeGroup(w, group); @@ -111,7 +108,7 @@ class MessageFactoryImpl implements MessageFactory { throw new IllegalArgumentException(); w.writeBytes(sig); } - w.writeStructEnd(); + w.writeListEnd(); // Hash the message, including the signature, to get the message ID w.removeConsumer(digestingConsumer); MessageId id = new MessageId(messageDigest.digest()); @@ -120,16 +117,16 @@ class MessageFactoryImpl implements MessageFactory { } private void writeGroup(Writer w, Group g) throws IOException { - w.writeStructStart(GROUP); + w.writeListStart(); w.writeString(g.getName()); w.writeBytes(g.getSalt()); - w.writeStructEnd(); + w.writeListEnd(); } private void writeAuthor(Writer w, Author a) throws IOException { - w.writeStructStart(AUTHOR); + w.writeListStart(); w.writeString(a.getName()); w.writeBytes(a.getPublicKey()); - w.writeStructEnd(); + w.writeListEnd(); } } diff --git a/briar-core/src/org/briarproject/messaging/MessageReader.java b/briar-core/src/org/briarproject/messaging/MessageReader.java index 198c34a750e00570f75a22737bf146a15e7f5336..6069eb8d49a54ec05313ea50784b7bba70165236 100644 --- a/briar-core/src/org/briarproject/messaging/MessageReader.java +++ b/briar-core/src/org/briarproject/messaging/MessageReader.java @@ -3,9 +3,8 @@ package org.briarproject.messaging; 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_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.Types.MESSAGE; import java.io.IOException; @@ -17,27 +16,27 @@ import org.briarproject.api.messaging.MessageId; import org.briarproject.api.messaging.UnverifiedMessage; import org.briarproject.api.serial.CopyingConsumer; import org.briarproject.api.serial.CountingConsumer; +import org.briarproject.api.serial.ObjectReader; 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 StructReader<Author> authorReader; + private final ObjectReader<Group> groupReader; + private final ObjectReader<Author> authorReader; - MessageReader(StructReader<Group> groupReader, - StructReader<Author> authorReader) { + MessageReader(ObjectReader<Group> groupReader, + ObjectReader<Author> authorReader) { this.groupReader = groupReader; this.authorReader = authorReader; } - public UnverifiedMessage readStruct(Reader r) throws IOException { + public UnverifiedMessage readObject(Reader r) throws IOException { CopyingConsumer copying = new CopyingConsumer(); - CountingConsumer counting = new CountingConsumer(MAX_PACKET_LENGTH); + CountingConsumer counting = new CountingConsumer(MAX_PAYLOAD_LENGTH); r.addConsumer(copying); r.addConsumer(counting); - // Read the start of the struct - r.readStructStart(MESSAGE); + // Read the start of the message + r.readListStart(); // Read the parent's message ID, if there is one MessageId parent = null; if(r.hasNull()) { @@ -48,11 +47,11 @@ class MessageReader implements StructReader<UnverifiedMessage> { parent = new MessageId(b); } // Read the group - Group group = groupReader.readStruct(r); + Group group = groupReader.readObject(r); // Read the author, if there is one Author author = null; if(r.hasNull()) r.readNull(); - else author = authorReader.readStruct(r); + else author = authorReader.readObject(r); // Read the content type String contentType = r.readString(MAX_CONTENT_TYPE_LENGTH); // Read the timestamp @@ -71,11 +70,12 @@ class MessageReader implements StructReader<UnverifiedMessage> { byte[] signature = null; if(author == null) r.readNull(); else signature = r.readBytes(MAX_SIGNATURE_LENGTH); - // Read the end of the struct - r.readStructEnd(); - // The signature will be verified later + // Read the end of the message + r.readListEnd(); + // Reset the reader r.removeConsumer(counting); r.removeConsumer(copying); + // Build and return the unverified message byte[] raw = copying.getCopy(); return new UnverifiedMessage(parent, group, author, contentType, timestamp, raw, signature, bodyStart, body.length, diff --git a/briar-core/src/org/briarproject/messaging/MessagingModule.java b/briar-core/src/org/briarproject/messaging/MessagingModule.java index e99c2a42c309ba5eb2c828db3fec19f6cf562fff..a209155b95fa79941f59a6983f0f1c5dec6cfc37 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingModule.java +++ b/briar-core/src/org/briarproject/messaging/MessagingModule.java @@ -14,7 +14,7 @@ import org.briarproject.api.messaging.PacketReaderFactory; import org.briarproject.api.messaging.PacketWriterFactory; import org.briarproject.api.messaging.SubscriptionUpdate; 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.Provides; @@ -34,25 +34,25 @@ public class MessagingModule extends AbstractModule { } @Provides - StructReader<Author> getAuthorReader(CryptoComponent crypto) { + ObjectReader<Author> getAuthorReader(CryptoComponent crypto) { return new AuthorReader(crypto); } @Provides - StructReader<Group> getGroupReader(CryptoComponent crypto) { + ObjectReader<Group> getGroupReader(CryptoComponent crypto) { return new GroupReader(crypto); } @Provides - StructReader<UnverifiedMessage> getMessageReader( - StructReader<Group> groupReader, - StructReader<Author> authorReader) { + ObjectReader<UnverifiedMessage> getMessageReader( + ObjectReader<Group> groupReader, + ObjectReader<Author> authorReader) { return new MessageReader(groupReader, authorReader); } @Provides - StructReader<SubscriptionUpdate> getSubscriptionUpdateReader( - StructReader<Group> groupReader) { + ObjectReader<SubscriptionUpdate> getSubscriptionUpdateReader( + ObjectReader<Group> groupReader) { return new SubscriptionUpdateReader(groupReader); } } diff --git a/briar-core/src/org/briarproject/messaging/PacketReaderFactoryImpl.java b/briar-core/src/org/briarproject/messaging/PacketReaderFactoryImpl.java index ec9a59dd2a2f7e539b537d90c66241087beed245..5e9879554a002830efb38549d19a85ce72b438b2 100644 --- a/briar-core/src/org/briarproject/messaging/PacketReaderFactoryImpl.java +++ b/briar-core/src/org/briarproject/messaging/PacketReaderFactoryImpl.java @@ -9,18 +9,18 @@ import org.briarproject.api.messaging.PacketReaderFactory; import org.briarproject.api.messaging.SubscriptionUpdate; import org.briarproject.api.messaging.UnverifiedMessage; import org.briarproject.api.serial.ReaderFactory; -import org.briarproject.api.serial.StructReader; +import org.briarproject.api.serial.ObjectReader; class PacketReaderFactoryImpl implements PacketReaderFactory { private final ReaderFactory readerFactory; - private final StructReader<UnverifiedMessage> messageReader; - private final StructReader<SubscriptionUpdate> subscriptionUpdateReader; + private final ObjectReader<UnverifiedMessage> messageReader; + private final ObjectReader<SubscriptionUpdate> subscriptionUpdateReader; @Inject PacketReaderFactoryImpl(ReaderFactory readerFactory, - StructReader<UnverifiedMessage> messageReader, - StructReader<SubscriptionUpdate> subscriptionUpdateReader) { + ObjectReader<UnverifiedMessage> messageReader, + ObjectReader<SubscriptionUpdate> subscriptionUpdateReader) { this.readerFactory = readerFactory; this.messageReader = messageReader; this.subscriptionUpdateReader = subscriptionUpdateReader; diff --git a/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java b/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java index b34244fd0f719fe7b8702077cf5e5923c7023979..8a13733f4e4efc31bfe3b5b7c7d0852002319686 100644 --- a/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java +++ b/briar-core/src/org/briarproject/messaging/PacketReaderImpl.java @@ -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_PROPERTY_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.Types.ACK; -import static org.briarproject.api.messaging.Types.MESSAGE; -import static org.briarproject.api.messaging.Types.OFFER; -import static org.briarproject.api.messaging.Types.REQUEST; -import static org.briarproject.api.messaging.Types.RETENTION_ACK; -import static org.briarproject.api.messaging.Types.RETENTION_UPDATE; -import static org.briarproject.api.messaging.Types.SUBSCRIPTION_ACK; -import static org.briarproject.api.messaging.Types.SUBSCRIPTION_UPDATE; -import static org.briarproject.api.messaging.Types.TRANSPORT_ACK; -import static org.briarproject.api.messaging.Types.TRANSPORT_UPDATE; +import static org.briarproject.api.messaging.MessagingConstants.HEADER_LENGTH; +import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH; +import static org.briarproject.api.messaging.MessagingConstants.PROTOCOL_VERSION; +import static org.briarproject.api.messaging.PacketTypes.ACK; +import static org.briarproject.api.messaging.PacketTypes.MESSAGE; +import static org.briarproject.api.messaging.PacketTypes.OFFER; +import static org.briarproject.api.messaging.PacketTypes.REQUEST; +import static org.briarproject.api.messaging.PacketTypes.RETENTION_ACK; +import static org.briarproject.api.messaging.PacketTypes.RETENTION_UPDATE; +import static org.briarproject.api.messaging.PacketTypes.SUBSCRIPTION_ACK; +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.InputStream; 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.TransportUpdate; 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.ReaderFactory; -import org.briarproject.api.serial.StructReader; +import org.briarproject.api.serial.ObjectReader; +import org.briarproject.util.ByteUtils; // This class is not thread-safe class PacketReaderImpl implements PacketReader { - private final StructReader<UnverifiedMessage> messageReader; - private final StructReader<SubscriptionUpdate> subscriptionUpdateReader; - private final Reader r; + private enum State { BUFFER_EMPTY, BUFFER_FULL, EOF }; + + 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, - StructReader<UnverifiedMessage> messageReader, - StructReader<SubscriptionUpdate> subscriptionUpdateReader, + ObjectReader<UnverifiedMessage> messageReader, + ObjectReader<SubscriptionUpdate> subscriptionUpdateReader, InputStream in) { + this.readerFactory = readerFactory; this.messageReader = messageReader; 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 { - return r.eof(); + if(state == State.BUFFER_EMPTY) readPacket(); + assert state != State.BUFFER_EMPTY; + return state == State.EOF; } public boolean hasAck() throws IOException { - return r.hasStruct(ACK); + return !eof() && header[1] == ACK; } public Ack readAck() throws IOException { + if(!hasAck()) throw new FormatException(); // Set up the reader - Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); - r.addConsumer(counting); - // Read the start of the struct - r.readStructStart(ACK); + InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength); + Reader r = readerFactory.createReader(bais); + // Read the start of the payload + r.readListStart(); // Read the message IDs List<MessageId> acked = new ArrayList<MessageId>(); r.readListStart(); @@ -86,32 +129,41 @@ class PacketReaderImpl implements PacketReader { } if(acked.isEmpty()) throw new FormatException(); r.readListEnd(); - // Read the end of the struct - r.readStructEnd(); - // Reset the reader - r.removeConsumer(counting); + // Read the end of the payload + r.readListEnd(); + if(!r.eof()) throw new FormatException(); + state = State.BUFFER_EMPTY; // Build and return the ack return new Ack(Collections.unmodifiableList(acked)); } public boolean hasMessage() throws IOException { - return r.hasStruct(MESSAGE); + return !eof() && header[1] == MESSAGE; } 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 { - return r.hasStruct(OFFER); + return !eof() && header[1] == OFFER; } public Offer readOffer() throws IOException { + if(!hasOffer()) throw new FormatException(); // Set up the reader - Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); - r.addConsumer(counting); - // Read the start of the struct - r.readStructStart(OFFER); + InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength); + Reader r = readerFactory.createReader(bais); + // Read the start of the payload + r.readListStart(); // Read the message IDs List<MessageId> offered = new ArrayList<MessageId>(); r.readListStart(); @@ -123,27 +175,28 @@ class PacketReaderImpl implements PacketReader { } if(offered.isEmpty()) throw new FormatException(); r.readListEnd(); - // Read the end of the struct - r.readStructEnd(); - // Reset the reader - r.removeConsumer(counting); + // Read the end of the payload + r.readListEnd(); + if(!r.eof()) throw new FormatException(); + state = State.BUFFER_EMPTY; // Build and return the offer return new Offer(Collections.unmodifiableList(offered)); } public boolean hasRequest() throws IOException { - return r.hasStruct(REQUEST); + return !eof() && header[1] == REQUEST; } public Request readRequest() throws IOException { + if(!hasRequest()) throw new FormatException(); // Set up the reader - Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); - r.addConsumer(counting); - // Read the start of the struct - r.readStructStart(REQUEST); + InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength); + Reader r = readerFactory.createReader(bais); + // Read the start of the payload + r.readListStart(); // Read the message IDs - List<MessageId> requested = new ArrayList<MessageId>(); r.readListStart(); + List<MessageId> requested = new ArrayList<MessageId>(); while(!r.hasListEnd()) { byte[] b = r.readBytes(UniqueId.LENGTH); if(b.length != UniqueId.LENGTH) @@ -152,85 +205,134 @@ class PacketReaderImpl implements PacketReader { } if(requested.isEmpty()) throw new FormatException(); r.readListEnd(); - // Read the end of the struct - r.readStructEnd(); - // Reset the reader - r.removeConsumer(counting); + // Read the end of the payload + r.readListEnd(); + if(!r.eof()) throw new FormatException(); + state = State.BUFFER_EMPTY; // Build and return the request return new Request(Collections.unmodifiableList(requested)); } public boolean hasRetentionAck() throws IOException { - return r.hasStruct(RETENTION_ACK); + return !eof() && header[1] == RETENTION_ACK; } 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(); 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); } public boolean hasRetentionUpdate() throws IOException { - return r.hasStruct(RETENTION_UPDATE); + return !eof() && header[1] == RETENTION_UPDATE; } 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(); if(retention < 0) throw new FormatException(); long version = r.readInteger(); 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); } public boolean hasSubscriptionAck() throws IOException { - return r.hasStruct(SUBSCRIPTION_ACK); + return !eof() && header[1] == SUBSCRIPTION_ACK; } 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(); 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); } public boolean hasSubscriptionUpdate() throws IOException { - return r.hasStruct(SUBSCRIPTION_UPDATE); + return !eof() && header[1] == SUBSCRIPTION_UPDATE; } 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 { - return r.hasStruct(TRANSPORT_ACK); + return !eof() && header[1] == TRANSPORT_ACK; } 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); if(idString.length() == 0) throw new FormatException(); TransportId id = new TransportId(idString); long version = r.readInteger(); 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); } public boolean hasTransportUpdate() throws IOException { - return r.hasStruct(TRANSPORT_UPDATE); + return !eof() && header[1] == TRANSPORT_UPDATE; } public TransportUpdate readTransportUpdate() throws IOException { + if(!hasTransportUpdate()) throw new FormatException(); // Set up the reader - Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); - r.addConsumer(counting); - // Read the start of the struct - r.readStructStart(TRANSPORT_UPDATE); + InputStream bais = new ByteArrayInputStream(payload, 0, payloadLength); + Reader r = readerFactory.createReader(bais); + // Read the start of the payload + r.readListStart(); // Read the transport ID String idString = r.readString(MAX_TRANSPORT_ID_LENGTH); if(idString.length() == 0) throw new FormatException(); @@ -249,10 +351,10 @@ class PacketReaderImpl implements PacketReader { // Read the version number long version = r.readInteger(); if(version < 0) throw new FormatException(); - // Read the end of the struct - r.readStructEnd(); - // Reset the reader - r.removeConsumer(counting); + // Read the end of the payload + r.readListEnd(); + if(!r.eof()) throw new FormatException(); + state = State.BUFFER_EMPTY; // Build and return the transport update return new TransportUpdate(id, new TransportProperties(p), version); } diff --git a/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java b/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java index 1ef8e348c92c4efc555f94c909c757fb674d079f..68787848ab104a5fa3ac97bf03f8331a9f2b6cec 100644 --- a/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java +++ b/briar-core/src/org/briarproject/messaging/PacketWriterImpl.java @@ -1,17 +1,19 @@ package org.briarproject.messaging; -import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; -import static org.briarproject.api.messaging.Types.ACK; -import static org.briarproject.api.messaging.Types.GROUP; -import static org.briarproject.api.messaging.Types.OFFER; -import static org.briarproject.api.messaging.Types.REQUEST; -import static org.briarproject.api.messaging.Types.RETENTION_ACK; -import static org.briarproject.api.messaging.Types.RETENTION_UPDATE; -import static org.briarproject.api.messaging.Types.SUBSCRIPTION_ACK; -import static org.briarproject.api.messaging.Types.SUBSCRIPTION_UPDATE; -import static org.briarproject.api.messaging.Types.TRANSPORT_ACK; -import static org.briarproject.api.messaging.Types.TRANSPORT_UPDATE; - +import static org.briarproject.api.messaging.MessagingConstants.HEADER_LENGTH; +import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH; +import static org.briarproject.api.messaging.MessagingConstants.PROTOCOL_VERSION; +import static org.briarproject.api.messaging.PacketTypes.ACK; +import static org.briarproject.api.messaging.PacketTypes.OFFER; +import static org.briarproject.api.messaging.PacketTypes.REQUEST; +import static org.briarproject.api.messaging.PacketTypes.RETENTION_ACK; +import static org.briarproject.api.messaging.PacketTypes.RETENTION_UPDATE; +import static org.briarproject.api.messaging.PacketTypes.SUBSCRIPTION_ACK; +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.ByteArrayOutputStream; import java.io.IOException; 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.MessageId; import org.briarproject.api.messaging.Offer; +import org.briarproject.api.messaging.PacketTypes; import org.briarproject.api.messaging.PacketWriter; import org.briarproject.api.messaging.Request; 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.Writer; import org.briarproject.api.serial.WriterFactory; +import org.briarproject.util.ByteUtils; // This class is not thread-safe class PacketWriterImpl implements PacketWriter { private final SerialComponent serial; + private final WriterFactory writerFactory; private final OutputStream out; - private final Writer w; + private final byte[] header; + private final ByteArrayOutputStream payload; PacketWriterImpl(SerialComponent serial, WriterFactory writerFactory, OutputStream out) { this.serial = serial; + this.writerFactory = writerFactory; 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) { - return getMaxMessagesForPacket(capacity, ACK); + return getMaxMessagesForPacket(capacity); } public int getMaxMessagesForRequest(long capacity) { - return getMaxMessagesForPacket(capacity, REQUEST); + return getMaxMessagesForPacket(capacity); } public int getMaxMessagesForOffer(long capacity) { - return getMaxMessagesForPacket(capacity, OFFER); + return getMaxMessagesForPacket(capacity); } - private int getMaxMessagesForPacket(long capacity, int structId) { - int packet = (int) Math.min(capacity, MAX_PACKET_LENGTH); - int overhead = serial.getSerialisedStructStartLength(structId) - + serial.getSerialisedListStartLength() - + serial.getSerialisedListEndLength() - + serial.getSerialisedStructEndLength(); + private int getMaxMessagesForPacket(long capacity) { + int payload = (int) Math.min(capacity - HEADER_LENGTH, + MAX_PAYLOAD_LENGTH); + int overhead = serial.getSerialisedListStartLength() * 2 + + serial.getSerialisedListEndLength() * 2; 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 { - w.writeStructStart(ACK); + assert payload.size() == 0; + Writer w = writerFactory.createWriter(payload); + w.writeListStart(); w.writeListStart(); for(MessageId m : a.getMessageIds()) w.writeBytes(m.getBytes()); w.writeListEnd(); - w.writeStructEnd(); + w.writeListEnd(); + writePacket(ACK); } public void writeMessage(byte[] raw) throws IOException { + header[1] = PacketTypes.MESSAGE; + ByteUtils.writeUint16(raw.length, header, 2); + out.write(header); out.write(raw); } public void writeOffer(Offer o) throws IOException { - w.writeStructStart(OFFER); + assert payload.size() == 0; + Writer w = writerFactory.createWriter(payload); + w.writeListStart(); w.writeListStart(); for(MessageId m : o.getMessageIds()) w.writeBytes(m.getBytes()); w.writeListEnd(); - w.writeStructEnd(); + w.writeListEnd(); + writePacket(OFFER); } public void writeRequest(Request r) throws IOException { - w.writeStructStart(REQUEST); + assert payload.size() == 0; + Writer w = writerFactory.createWriter(payload); + w.writeListStart(); w.writeListStart(); for(MessageId m : r.getMessageIds()) w.writeBytes(m.getBytes()); w.writeListEnd(); - w.writeStructEnd(); + w.writeListEnd(); + writePacket(REQUEST); } 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.writeStructEnd(); + w.writeListEnd(); + writePacket(RETENTION_ACK); } 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.getVersion()); - w.writeStructEnd(); + w.writeListEnd(); + writePacket(RETENTION_UPDATE); } 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.writeStructEnd(); + w.writeListEnd(); + writePacket(SUBSCRIPTION_ACK); } public void writeSubscriptionUpdate(SubscriptionUpdate u) throws IOException { - w.writeStructStart(SUBSCRIPTION_UPDATE); + assert payload.size() == 0; + Writer w = writerFactory.createWriter(payload); + w.writeListStart(); w.writeListStart(); for(Group g : u.getGroups()) { - w.writeStructStart(GROUP); + w.writeListStart(); w.writeString(g.getName()); w.writeBytes(g.getSalt()); - w.writeStructEnd(); + w.writeListEnd(); } w.writeListEnd(); w.writeInteger(u.getVersion()); - w.writeStructEnd(); + w.writeListEnd(); + writePacket(SUBSCRIPTION_UPDATE); } 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.writeInteger(a.getVersion()); - w.writeStructEnd(); + w.writeListEnd(); + writePacket(TRANSPORT_ACK); } 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.writeMap(u.getProperties()); w.writeInteger(u.getVersion()); - w.writeStructEnd(); + w.writeListEnd(); + writePacket(TRANSPORT_UPDATE); } public void flush() throws IOException { diff --git a/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java b/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java index 6d8dfabf1ae815bdebaba6fef642a40717c7368f..1a5df4a26ef6400a97e038b7c181498cecb95cea 100644 --- a/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/messaging/SimplexOutgoingSession.java @@ -2,7 +2,7 @@ package org.briarproject.messaging; import static java.util.logging.Level.INFO; 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.util.Collection; @@ -167,7 +167,7 @@ class SimplexOutgoingSession implements MessagingSession, EventListener { if(interrupted) return; try { Collection<byte[]> b = db.generateBatch(contactId, - MAX_PACKET_LENGTH, maxLatency); + MAX_PAYLOAD_LENGTH, maxLatency); if(LOG.isLoggable(INFO)) LOG.info("Generated batch: " + (b != null)); if(b == null) decrementOutstandingQueries(); diff --git a/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java b/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java index 983be4a049d0fb9e82fc37d2c465c6576d32cff9..67d7dd88c55db3a1aa825e52f3ac7d2583227dab 100644 --- a/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java +++ b/briar-core/src/org/briarproject/messaging/SubscriptionUpdateReader.java @@ -1,8 +1,7 @@ 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.Types.SUBSCRIPTION_UPDATE; import java.io.IOException; import java.util.ArrayList; @@ -17,29 +16,29 @@ import org.briarproject.api.messaging.GroupId; import org.briarproject.api.messaging.SubscriptionUpdate; import org.briarproject.api.serial.Consumer; import org.briarproject.api.serial.CountingConsumer; +import org.briarproject.api.serial.ObjectReader; 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; } - public SubscriptionUpdate readStruct(Reader r) throws IOException { + public SubscriptionUpdate readObject(Reader r) throws IOException { // Set up the reader - Consumer counting = new CountingConsumer(MAX_PACKET_LENGTH); + Consumer counting = new CountingConsumer(MAX_PAYLOAD_LENGTH); r.addConsumer(counting); - // Read the start of the struct - r.readStructStart(SUBSCRIPTION_UPDATE); + // Read the start of the update + r.readListStart(); // Read the subscriptions, rejecting duplicates List<Group> groups = new ArrayList<Group>(); Set<GroupId> ids = new HashSet<GroupId>(); r.readListStart(); 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 groups.add(g); } @@ -47,8 +46,8 @@ class SubscriptionUpdateReader implements StructReader<SubscriptionUpdate> { // Read the version number long version = r.readInteger(); if(version < 0) throw new FormatException(); - // Read the end of the struct - r.readStructEnd(); + // Read the end of the update + r.readListEnd(); // Reset the reader r.removeConsumer(counting); // Build and return the subscription update diff --git a/briar-core/src/org/briarproject/serial/ObjectTypes.java b/briar-core/src/org/briarproject/serial/ObjectTypes.java new file mode 100644 index 0000000000000000000000000000000000000000..69bd14174f9ccfe6e7d91244c741cdae0bbb311d --- /dev/null +++ b/briar-core/src/org/briarproject/serial/ObjectTypes.java @@ -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; +} diff --git a/briar-core/src/org/briarproject/serial/ReaderImpl.java b/briar-core/src/org/briarproject/serial/ReaderImpl.java index b8710776f6c712bf77a0211156670d620e9f8fae..efd4f88108456169a463a8b918f6bdc10a848b1f 100644 --- a/briar-core/src/org/briarproject/serial/ReaderImpl.java +++ b/briar-core/src/org/briarproject/serial/ReaderImpl.java @@ -1,23 +1,20 @@ package org.briarproject.serial; -import static org.briarproject.serial.Tag.BYTES_16; -import static org.briarproject.serial.Tag.BYTES_32; -import static org.briarproject.serial.Tag.BYTES_8; -import static org.briarproject.serial.Tag.END; -import static org.briarproject.serial.Tag.FALSE; -import static org.briarproject.serial.Tag.FLOAT; -import static org.briarproject.serial.Tag.INTEGER_16; -import static org.briarproject.serial.Tag.INTEGER_32; -import static org.briarproject.serial.Tag.INTEGER_64; -import static org.briarproject.serial.Tag.INTEGER_8; -import static org.briarproject.serial.Tag.LIST; -import static org.briarproject.serial.Tag.MAP; -import static org.briarproject.serial.Tag.NULL; -import static org.briarproject.serial.Tag.STRING_16; -import static org.briarproject.serial.Tag.STRING_32; -import static org.briarproject.serial.Tag.STRING_8; -import static org.briarproject.serial.Tag.STRUCT; -import static org.briarproject.serial.Tag.TRUE; +import static org.briarproject.serial.ObjectTypes.END; +import static org.briarproject.serial.ObjectTypes.FLOAT_64; +import static org.briarproject.serial.ObjectTypes.INT_16; +import static org.briarproject.serial.ObjectTypes.INT_32; +import static org.briarproject.serial.ObjectTypes.INT_64; +import static org.briarproject.serial.ObjectTypes.INT_8; +import static org.briarproject.serial.ObjectTypes.LIST; +import static org.briarproject.serial.ObjectTypes.MAP; +import static org.briarproject.serial.ObjectTypes.NULL; +import static org.briarproject.serial.ObjectTypes.RAW_16; +import static org.briarproject.serial.ObjectTypes.RAW_32; +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.InputStream; @@ -37,7 +34,7 @@ class ReaderImpl implements Reader { private final Collection<Consumer> consumers = new ArrayList<Consumer>(0); private boolean hasLookahead = false, eof = false; - private byte next, nextStructId; + private byte next; private byte[] buf = new byte[8]; ReaderImpl(InputStream in) { @@ -54,21 +51,12 @@ class ReaderImpl implements Reader { return; } 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; } private void consumeLookahead() throws IOException { assert hasLookahead; - for(Consumer c : consumers) { - c.write(next); - if(next == STRUCT) c.write(nextStructId); - } + for(Consumer c : consumers) c.write(next); hasLookahead = false; } @@ -101,11 +89,10 @@ class ReaderImpl implements Reader { if(hasBoolean()) skipBoolean(); else if(hasInteger()) skipInteger(); else if(hasFloat()) skipFloat(); - else if(hasString()) skipString(Integer.MAX_VALUE); - else if(hasBytes()) skipBytes(Integer.MAX_VALUE); + else if(hasString()) skipString(); + else if(hasBytes()) skipBytes(); else if(hasList()) skipList(); else if(hasMap()) skipMap(); - else if(hasStruct()) skipStruct(); else if(hasNull()) skipNull(); else throw new FormatException(); } @@ -127,36 +114,59 @@ class ReaderImpl implements Reader { 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 { if(!hasLookahead) readLookahead(); if(eof) return false; - return next == FALSE || next == TRUE; + return next == ObjectTypes.BOOLEAN; } public boolean readBoolean() throws IOException { if(!hasBoolean()) throw new FormatException(); 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 { if(!hasBoolean()) throw new FormatException(); + skip(1); hasLookahead = false; } public boolean hasInteger() throws IOException { if(!hasLookahead) readLookahead(); if(eof) return false; - return next == INTEGER_8 || next == INTEGER_16 || next == INTEGER_32 || - next == INTEGER_64; + return next == INT_8 || next == INT_16 || next == INT_32 || + next == INT_64; } public long readInteger() throws IOException { if(!hasInteger()) throw new FormatException(); consumeLookahead(); - if(next == INTEGER_8) return readInt8(true); - if(next == INTEGER_16) return readInt16(true); - if(next == INTEGER_32) return readInt32(true); + if(next == INT_8) return readInt8(true); + if(next == INT_16) return readInt16(true); + if(next == INT_32) return readInt32(true); return readInt64(true); } @@ -193,9 +203,9 @@ class ReaderImpl implements Reader { public void skipInteger() throws IOException { if(!hasInteger()) throw new FormatException(); - if(next == INTEGER_8) skip(1); - else if(next == INTEGER_16) skip(2); - else if(next == INTEGER_32) skip(4); + if(next == INT_8) skip(1); + else if(next == INT_16) skip(2); + else if(next == INT_32) skip(4); else skip(8); hasLookahead = false; } @@ -203,7 +213,7 @@ class ReaderImpl implements Reader { public boolean hasFloat() throws IOException { if(!hasLookahead) readLookahead(); if(eof) return false; - return next == FLOAT; + return next == FLOAT_64; } public double readFloat() throws IOException { @@ -244,10 +254,10 @@ class ReaderImpl implements Reader { throw new FormatException(); } - public void skipString(int maxLength) throws IOException { + public void skipString() throws IOException { if(!hasString()) throw new FormatException(); int length = readStringLength(false); - if(length < 0 || length > maxLength) throw new FormatException(); + if(length < 0) throw new FormatException(); skip(length); hasLookahead = false; } @@ -255,7 +265,7 @@ class ReaderImpl implements Reader { public boolean hasBytes() throws IOException { if(!hasLookahead) readLookahead(); 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 { @@ -270,16 +280,16 @@ class ReaderImpl implements Reader { } private int readBytesLength(boolean consume) throws IOException { - if(next == BYTES_8) return readInt8(consume); - if(next == BYTES_16) return readInt16(consume); - if(next == BYTES_32) return readInt32(consume); + if(next == RAW_8) return readInt8(consume); + if(next == RAW_16) return readInt16(consume); + if(next == RAW_32) return readInt32(consume); throw new FormatException(); } - public void skipBytes(int maxLength) throws IOException { + public void skipBytes() throws IOException { if(!hasBytes()) throw new FormatException(); int length = readBytesLength(false); - if(length < 0 || length > maxLength) throw new FormatException(); + if(length < 0) throw new FormatException(); skip(length); hasLookahead = false; } @@ -349,53 +359,4 @@ class ReaderImpl implements Reader { } 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; - } } diff --git a/briar-core/src/org/briarproject/serial/SerialComponentImpl.java b/briar-core/src/org/briarproject/serial/SerialComponentImpl.java index 8a7a42ab1f2aa4805e1c1f7133cdc1418fd4231c..ce6516260e5c65e2b6a7976985fa2c5ca8c9363f 100644 --- a/briar-core/src/org/briarproject/serial/SerialComponentImpl.java +++ b/briar-core/src/org/briarproject/serial/SerialComponentImpl.java @@ -15,16 +15,6 @@ class SerialComponentImpl implements SerialComponent { return 1; } - public int getSerialisedStructStartLength(int id) { - // STRUCT tag, 8-bit ID - return 2; - } - - public int getSerialisedStructEndLength() { - // END tag - return 1; - } - public int getSerialisedUniqueIdLength() { // BYTES_8, BYTES_16 or BYTES_32 tag, length, bytes return 1 + getLengthBytes(UniqueId.LENGTH) + UniqueId.LENGTH; diff --git a/briar-core/src/org/briarproject/serial/Tag.java b/briar-core/src/org/briarproject/serial/Tag.java deleted file mode 100644 index 9fe385dfaccf29371e318de45bebc1fa92e83dc1..0000000000000000000000000000000000000000 --- a/briar-core/src/org/briarproject/serial/Tag.java +++ /dev/null @@ -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; -} diff --git a/briar-core/src/org/briarproject/serial/WriterImpl.java b/briar-core/src/org/briarproject/serial/WriterImpl.java index 45995cdb0ef07697806671c69434b6debc5d084b..4b7a2de9371130eeafe4143cc85e4473a14bd586 100644 --- a/briar-core/src/org/briarproject/serial/WriterImpl.java +++ b/briar-core/src/org/briarproject/serial/WriterImpl.java @@ -1,18 +1,21 @@ package org.briarproject.serial; -import static org.briarproject.serial.Tag.BYTES_16; -import static org.briarproject.serial.Tag.BYTES_32; -import static org.briarproject.serial.Tag.BYTES_8; -import static org.briarproject.serial.Tag.FALSE; -import static org.briarproject.serial.Tag.FLOAT; -import static org.briarproject.serial.Tag.INTEGER_16; -import static org.briarproject.serial.Tag.INTEGER_32; -import static org.briarproject.serial.Tag.INTEGER_64; -import static org.briarproject.serial.Tag.INTEGER_8; -import static org.briarproject.serial.Tag.STRING_16; -import static org.briarproject.serial.Tag.STRING_32; -import static org.briarproject.serial.Tag.STRING_8; -import static org.briarproject.serial.Tag.TRUE; +import static org.briarproject.serial.ObjectTypes.BOOLEAN; +import static org.briarproject.serial.ObjectTypes.END; +import static org.briarproject.serial.ObjectTypes.FLOAT_64; +import static org.briarproject.serial.ObjectTypes.INT_16; +import static org.briarproject.serial.ObjectTypes.INT_32; +import static org.briarproject.serial.ObjectTypes.INT_64; +import static org.briarproject.serial.ObjectTypes.INT_8; +import static org.briarproject.serial.ObjectTypes.LIST; +import static org.briarproject.serial.ObjectTypes.MAP; +import static org.briarproject.serial.ObjectTypes.NULL; +import static org.briarproject.serial.ObjectTypes.RAW_16; +import static org.briarproject.serial.ObjectTypes.RAW_32; +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.OutputStream; @@ -52,23 +55,28 @@ class WriterImpl implements Writer { if(!consumers.remove(c)) throw new IllegalArgumentException(); } + public void writeNull() throws IOException { + write(NULL); + } + public void writeBoolean(boolean b) throws IOException { - if(b) write(TRUE); - else write(FALSE); + write(BOOLEAN); + if(b) write((byte) 1); + else write((byte) 0); } public void writeInteger(long i) throws IOException { if(i >= Byte.MIN_VALUE && i <= Byte.MAX_VALUE) { - write(INTEGER_8); + write(INT_8); write((byte) i); } else if(i >= Short.MIN_VALUE && i <= Short.MAX_VALUE) { - write(INTEGER_16); + write(INT_16); writeInt16((short) i); } else if(i >= Integer.MIN_VALUE && i <= Integer.MAX_VALUE) { - write(INTEGER_32); + write(INT_32); writeInt32((int) i); } else { - write(INTEGER_64); + write(INT_64); writeInt64(i); } } @@ -97,7 +105,7 @@ class WriterImpl implements Writer { } public void writeFloat(double d) throws IOException { - write(FLOAT); + write(FLOAT_64); writeInt64(Double.doubleToRawLongBits(d)); } @@ -118,22 +126,22 @@ class WriterImpl implements Writer { public void writeBytes(byte[] b) throws IOException { if(b.length <= Byte.MAX_VALUE) { - write(BYTES_8); + write(RAW_8); write((byte) b.length); } else if(b.length <= Short.MAX_VALUE) { - write(BYTES_16); + write(RAW_16); writeInt16((short) b.length); } else { - write(BYTES_32); + write(RAW_32); writeInt32(b.length); } write(b); } public void writeList(Collection<?> c) throws IOException { - write(Tag.LIST); + write(ObjectTypes.LIST); for(Object o : c) writeObject(o); - write(Tag.END); + write(ObjectTypes.END); } private void writeObject(Object o) throws IOException { @@ -154,42 +162,28 @@ class WriterImpl implements Writer { } public void writeListStart() throws IOException { - write(Tag.LIST); + write(LIST); } public void writeListEnd() throws IOException { - write(Tag.END); + write(END); } public void writeMap(Map<?, ?> m) throws IOException { - write(Tag.MAP); + write(MAP); for(Entry<?, ?> e : m.entrySet()) { writeObject(e.getKey()); writeObject(e.getValue()); } - write(Tag.END); + write(END); } public void writeMapStart() throws IOException { - write(Tag.MAP); + write(MAP); } public void writeMapEnd() throws IOException { - write(Tag.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); + write(END); } private void write(byte b) throws IOException { diff --git a/briar-tests/src/org/briarproject/messaging/ConstantsTest.java b/briar-tests/src/org/briarproject/messaging/ConstantsTest.java index 300190d1f338e7c6d9dd97ec2123e4dbc5a64dc5..affa0f573d418ed156caa8da7d1df368ca4157b0 100644 --- a/briar-tests/src/org/briarproject/messaging/ConstantsTest.java +++ b/briar-tests/src/org/briarproject/messaging/ConstantsTest.java @@ -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_CONTENT_TYPE_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 java.io.ByteArrayOutputStream; @@ -106,7 +106,7 @@ public class ConstantsTest extends BriarTestCase { @Test public void testMessageIdsFitIntoLargeAck() throws Exception { - testMessageIdsFitIntoAck(MAX_PACKET_LENGTH); + testMessageIdsFitIntoAck(MAX_PAYLOAD_LENGTH); } @Test @@ -139,12 +139,12 @@ public class ConstantsTest extends BriarTestCase { + MAX_PUBLIC_KEY_LENGTH + MAX_AUTHOR_NAME_LENGTH + MAX_PUBLIC_KEY_LENGTH + MAX_CONTENT_TYPE_LENGTH + MAX_BODY_LENGTH); - assertTrue(length <= MAX_PACKET_LENGTH); + assertTrue(length <= MAX_PAYLOAD_LENGTH); } @Test public void testMessageIdsFitIntoLargeOffer() throws Exception { - testMessageIdsFitIntoOffer(MAX_PACKET_LENGTH); + testMessageIdsFitIntoOffer(MAX_PAYLOAD_LENGTH); } @Test @@ -154,7 +154,7 @@ public class ConstantsTest extends BriarTestCase { @Test public void testMessageIdsFitIntoLargeRequest() throws Exception { - testMessageIdsFitIntoRequest(MAX_PACKET_LENGTH); + testMessageIdsFitIntoRequest(MAX_PAYLOAD_LENGTH); } @Test @@ -180,7 +180,7 @@ public class ConstantsTest extends BriarTestCase { PacketWriter writer = packetWriterFactory.createPacketWriter(out); writer.writeTransportUpdate(u); // Check the size of the serialised transport update - assertTrue(out.size() <= MAX_PACKET_LENGTH); + assertTrue(out.size() <= MAX_PAYLOAD_LENGTH); } @Test @@ -198,7 +198,7 @@ public class ConstantsTest extends BriarTestCase { PacketWriter writer = packetWriterFactory.createPacketWriter(out); writer.writeSubscriptionUpdate(u); // 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 { diff --git a/briar-tests/src/org/briarproject/messaging/PacketReaderImplTest.java b/briar-tests/src/org/briarproject/messaging/PacketReaderImplTest.java index 097f2dab19861ab8dd44ae107f5c6ad68f06114b..ec3562250a64237f926b4f02a65f7e8994ae46c9 100644 --- a/briar-tests/src/org/briarproject/messaging/PacketReaderImplTest.java +++ b/briar-tests/src/org/briarproject/messaging/PacketReaderImplTest.java @@ -1,9 +1,10 @@ package org.briarproject.messaging; -import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH; -import static org.briarproject.api.messaging.Types.ACK; -import static org.briarproject.api.messaging.Types.OFFER; -import static org.briarproject.api.messaging.Types.REQUEST; +import static org.briarproject.api.messaging.MessagingConstants.HEADER_LENGTH; +import static org.briarproject.api.messaging.MessagingConstants.MAX_PAYLOAD_LENGTH; +import static org.briarproject.api.messaging.PacketTypes.ACK; +import static org.briarproject.api.messaging.PacketTypes.OFFER; +import static org.briarproject.api.messaging.PacketTypes.REQUEST; import java.io.ByteArrayInputStream; 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.WriterFactory; import org.briarproject.serial.SerialModule; +import org.briarproject.util.ByteUtils; import org.junit.Test; import com.google.inject.Guice; @@ -137,85 +139,106 @@ public class PacketReaderImplTest extends BriarTestCase { private byte[] createAck(boolean tooBig) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(new byte[HEADER_LENGTH]); Writer w = writerFactory.createWriter(out); - w.writeStructStart(ACK); + w.writeListStart(); w.writeListStart(); while(out.size() + serial.getSerialisedUniqueIdLength() - + serial.getSerialisedListEndLength() - + serial.getSerialisedStructEndLength() - < MAX_PACKET_LENGTH) { + + serial.getSerialisedListEndLength() * 2 + < HEADER_LENGTH + MAX_PAYLOAD_LENGTH) { w.writeBytes(TestUtils.getRandomId()); } if(tooBig) w.writeBytes(TestUtils.getRandomId()); w.writeListEnd(); - w.writeStructEnd(); - assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH); - return out.toByteArray(); + w.writeListEnd(); + assertEquals(tooBig, out.size() > HEADER_LENGTH + MAX_PAYLOAD_LENGTH); + byte[] packet = out.toByteArray(); + packet[1] = ACK; + ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2); + return packet; } private byte[] createEmptyAck() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(new byte[HEADER_LENGTH]); Writer w = writerFactory.createWriter(out); - w.writeStructStart(ACK); + w.writeListStart(); w.writeListStart(); w.writeListEnd(); - w.writeStructEnd(); - return out.toByteArray(); + w.writeListEnd(); + byte[] packet = out.toByteArray(); + packet[1] = ACK; + ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2); + return packet; } private byte[] createOffer(boolean tooBig) throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(new byte[HEADER_LENGTH]); Writer w = writerFactory.createWriter(out); - w.writeStructStart(OFFER); + w.writeListStart(); w.writeListStart(); while(out.size() + serial.getSerialisedUniqueIdLength() - + serial.getSerialisedListEndLength() - + serial.getSerialisedStructEndLength() - < MAX_PACKET_LENGTH) { + + serial.getSerialisedListEndLength() * 2 + < HEADER_LENGTH + MAX_PAYLOAD_LENGTH) { w.writeBytes(TestUtils.getRandomId()); } if(tooBig) w.writeBytes(TestUtils.getRandomId()); w.writeListEnd(); - w.writeStructEnd(); - assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH); - return out.toByteArray(); + w.writeListEnd(); + assertEquals(tooBig, out.size() > HEADER_LENGTH + MAX_PAYLOAD_LENGTH); + byte[] packet = out.toByteArray(); + packet[1] = OFFER; + ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2); + return packet; } private byte[] createEmptyOffer() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(new byte[HEADER_LENGTH]); Writer w = writerFactory.createWriter(out); - w.writeStructStart(OFFER); w.writeListStart(); + w.writeListStart(); + w.writeListEnd(); w.writeListEnd(); - w.writeStructEnd(); - 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 { ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(new byte[HEADER_LENGTH]); Writer w = writerFactory.createWriter(out); - w.writeStructStart(REQUEST); + w.writeListStart(); w.writeListStart(); while(out.size() + serial.getSerialisedUniqueIdLength() - + serial.getSerialisedListEndLength() - + serial.getSerialisedStructEndLength() - < MAX_PACKET_LENGTH) { + + serial.getSerialisedListEndLength() * 2 + < HEADER_LENGTH + MAX_PAYLOAD_LENGTH) { w.writeBytes(TestUtils.getRandomId()); } if(tooBig) w.writeBytes(TestUtils.getRandomId()); w.writeListEnd(); - w.writeStructEnd(); - assertEquals(tooBig, out.size() > MAX_PACKET_LENGTH); - return out.toByteArray(); + w.writeListEnd(); + assertEquals(tooBig, out.size() > HEADER_LENGTH + MAX_PAYLOAD_LENGTH); + byte[] packet = out.toByteArray(); + packet[1] = REQUEST; + ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2); + return packet; } private byte[] createEmptyRequest() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); + out.write(new byte[HEADER_LENGTH]); Writer w = writerFactory.createWriter(out); - w.writeStructStart(REQUEST); w.writeListStart(); + w.writeListStart(); + w.writeListEnd(); w.writeListEnd(); - w.writeStructEnd(); - return out.toByteArray(); + byte[] packet = out.toByteArray(); + packet[1] = REQUEST; + ByteUtils.writeUint16(packet.length - HEADER_LENGTH, packet, 2); + return packet; } } diff --git a/briar-tests/src/org/briarproject/serial/ReaderImplTest.java b/briar-tests/src/org/briarproject/serial/ReaderImplTest.java index 54210b540ac084c638294fa7a7243ac638bfca50..6b093c2e02dd31740fcaa2bd6b75f21b9cc94950 100644 --- a/briar-tests/src/org/briarproject/serial/ReaderImplTest.java +++ b/briar-tests/src/org/briarproject/serial/ReaderImplTest.java @@ -15,9 +15,29 @@ public class ReaderImplTest extends BriarTestCase { private ByteArrayInputStream in = 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 public void testReadBoolean() throws Exception { - setContents("00" + "01"); + setContents("11" + "00" + "11" + "01"); assertFalse(r.readBoolean()); assertTrue(r.readBoolean()); assertTrue(r.eof()); @@ -25,7 +45,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipBoolean() throws Exception { - setContents("00" + "01"); + setContents("11" + "00" + "11" + "01"); r.skipBoolean(); r.skipBoolean(); assertTrue(r.eof()); @@ -33,8 +53,8 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadInt8() throws Exception { - setContents("02" + "00" + "02" + "FF" - + "02" + "7F" + "02" + "80"); + setContents("21" + "00" + "21" + "FF" + + "21" + "7F" + "21" + "80"); assertEquals(0, r.readInteger()); assertEquals(-1, r.readInteger()); assertEquals(Byte.MAX_VALUE, r.readInteger()); @@ -44,15 +64,15 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipInt8() throws Exception { - setContents("02" + "00"); + setContents("21" + "00"); r.skipInteger(); assertTrue(r.eof()); } @Test public void testReadInt16() throws Exception { - setContents("03" + "0080" + "03" + "FF7F" - + "03" + "7FFF" + "03" + "8000"); + setContents("22" + "0080" + "22" + "FF7F" + + "22" + "7FFF" + "22" + "8000"); assertEquals(Byte.MAX_VALUE + 1, r.readInteger()); assertEquals(Byte.MIN_VALUE - 1, r.readInteger()); assertEquals(Short.MAX_VALUE, r.readInteger()); @@ -62,15 +82,15 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipInt16() throws Exception { - setContents("03" + "0080"); + setContents("22" + "0080"); r.skipInteger(); assertTrue(r.eof()); } @Test public void testReadInt32() throws Exception { - setContents("04" + "00008000" + "04" + "FFFF7FFF" - + "04" + "7FFFFFFF" + "04" + "80000000"); + setContents("24" + "00008000" + "24" + "FFFF7FFF" + + "24" + "7FFFFFFF" + "24" + "80000000"); assertEquals(Short.MAX_VALUE + 1, r.readInteger()); assertEquals(Short.MIN_VALUE - 1, r.readInteger()); assertEquals(Integer.MAX_VALUE, r.readInteger()); @@ -80,15 +100,15 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipInt32() throws Exception { - setContents("04" + "00008000"); + setContents("24" + "00008000"); r.skipInteger(); assertTrue(r.eof()); } @Test public void testReadInt64() throws Exception { - setContents("05" + "0000000080000000" + "05" + "FFFFFFFF7FFFFFFF" - + "05" + "7FFFFFFFFFFFFFFF" + "05" + "8000000000000000"); + setContents("28" + "0000000080000000" + "28" + "FFFFFFFF7FFFFFFF" + + "28" + "7FFFFFFFFFFFFFFF" + "28" + "8000000000000000"); assertEquals(Integer.MAX_VALUE + 1L, r.readInteger()); assertEquals(Integer.MIN_VALUE - 1L, r.readInteger()); assertEquals(Long.MAX_VALUE, r.readInteger()); @@ -98,7 +118,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipInt64() throws Exception { - setContents("05" + "0000000080000000"); + setContents("28" + "0000000080000000"); r.skipInteger(); assertTrue(r.eof()); } @@ -106,39 +126,39 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testIntegersMustHaveMinimalLength() throws Exception { // INTEGER_16 could be encoded as INTEGER_8 - setContents("02" + "7F" + "03" + "007F"); + setContents("21" + "7F" + "22" + "007F"); assertEquals(Byte.MAX_VALUE, r.readInteger()); try { r.readInteger(); fail(); } catch(FormatException expected) {} - setContents("02" + "80" + "03" + "FF80"); + setContents("21" + "80" + "22" + "FF80"); assertEquals(Byte.MIN_VALUE, r.readInteger()); try { r.readInteger(); fail(); } catch(FormatException expected) {} // INTEGER_32 could be encoded as INTEGER_16 - setContents("03" + "7FFF" + "04" + "00007FFF"); + setContents("22" + "7FFF" + "24" + "00007FFF"); assertEquals(Short.MAX_VALUE, r.readInteger()); try { r.readInteger(); fail(); } catch(FormatException expected) {} - setContents("03" + "8000" + "04" + "FFFF8000"); + setContents("22" + "8000" + "24" + "FFFF8000"); assertEquals(Short.MIN_VALUE, r.readInteger()); try { r.readInteger(); fail(); } catch(FormatException expected) {} // INTEGER_64 could be encoded as INTEGER_32 - setContents("04" + "7FFFFFFF" + "05" + "000000007FFFFFFF"); + setContents("24" + "7FFFFFFF" + "28" + "000000007FFFFFFF"); assertEquals(Integer.MAX_VALUE, r.readInteger()); try { r.readInteger(); fail(); } catch(FormatException expected) {} - setContents("04" + "80000000" + "05" + "FFFFFFFF80000000"); + setContents("24" + "80000000" + "28" + "FFFFFFFF80000000"); assertEquals(Integer.MIN_VALUE, r.readInteger()); try { r.readInteger(); @@ -150,10 +170,10 @@ public class ReaderImplTest extends BriarTestCase { public void testReadFloat() throws Exception { // http://babbage.cs.qc.edu/IEEE-754/Decimal.html // http://steve.hollasch.net/cgindex/coding/ieeefloat.html - setContents("06" + "0000000000000000" + "06" + "3FF0000000000000" - + "06" + "4000000000000000" + "06" + "BFF0000000000000" - + "06" + "8000000000000000" + "06" + "FFF0000000000000" - + "06" + "7FF0000000000000" + "06" + "7FF8000000000000"); + setContents("38" + "0000000000000000" + "38" + "3FF0000000000000" + + "38" + "4000000000000000" + "38" + "BFF0000000000000" + + "38" + "8000000000000000" + "38" + "FFF0000000000000" + + "38" + "7FF0000000000000" + "38" + "7FF8000000000000"); assertEquals(0.0, r.readFloat()); assertEquals(1.0, r.readFloat()); assertEquals(2.0, r.readFloat()); @@ -167,7 +187,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipFloat() throws Exception { - setContents("06" + "0000000000000000"); + setContents("38" + "0000000000000000"); r.skipFloat(); assertTrue(r.eof()); } @@ -177,8 +197,8 @@ public class ReaderImplTest extends BriarTestCase { String longest = TestUtils.createRandomString(Byte.MAX_VALUE); String longHex = StringUtils.toHexString(longest.getBytes("UTF-8")); // "foo", the empty string, and 127 random letters - setContents("07" + "03" + "666F6F" + "07" + "00" + - "07" + "7F" + longHex); + setContents("41" + "03" + "666F6F" + "41" + "00" + + "41" + "7F" + longHex); assertEquals("foo", r.readString(Integer.MAX_VALUE)); assertEquals("", r.readString(Integer.MAX_VALUE)); assertEquals(longest, r.readString(Integer.MAX_VALUE)); @@ -188,7 +208,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadString8ChecksMaxLength() throws Exception { // "foo" twice - setContents("07" + "03" + "666F6F" + "07" + "03" + "666F6F"); + setContents("41" + "03" + "666F6F" + "41" + "03" + "666F6F"); assertEquals("foo", r.readString(3)); assertTrue(r.hasString()); try { @@ -202,26 +222,14 @@ public class ReaderImplTest extends BriarTestCase { String longest = TestUtils.createRandomString(Byte.MAX_VALUE); String longHex = StringUtils.toHexString(longest.getBytes("UTF-8")); // "foo", the empty string, and 127 random letters - setContents("07" + "03" + "666F6F" + "07" + "00" + - "07" + "7F" + longHex); - r.skipString(Integer.MAX_VALUE); - r.skipString(Integer.MAX_VALUE); - r.skipString(Integer.MAX_VALUE); + setContents("41" + "03" + "666F6F" + "41" + "00" + + "41" + "7F" + longHex); + r.skipString(); + r.skipString(); + r.skipString(); 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 public void testReadString16() throws Exception { 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 longHex = StringUtils.toHexString(longest.getBytes("UTF-8")); // 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(longest, r.readString(Integer.MAX_VALUE)); assertTrue(r.eof()); @@ -240,7 +248,7 @@ public class ReaderImplTest extends BriarTestCase { 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); + setContents("42" + "0080" + shortHex + "42" + "0080" + shortHex); assertEquals(shortest, r.readString(Byte.MAX_VALUE + 1)); assertTrue(r.hasString()); try { @@ -256,32 +264,18 @@ public class ReaderImplTest extends BriarTestCase { String longest = TestUtils.createRandomString(Short.MAX_VALUE); String longHex = StringUtils.toHexString(longest.getBytes("UTF-8")); // 128 random letters and 2^15 - 1 random letters - setContents("08" + "0080" + shortHex + "08" + "7FFF" + longHex); - r.skipString(Integer.MAX_VALUE); - r.skipString(Integer.MAX_VALUE); + setContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex); + r.skipString(); + r.skipString(); 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 public void testReadString32() throws Exception { String shortest = TestUtils.createRandomString(Short.MAX_VALUE + 1); String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8")); // 2^15 random letters - setContents("09" + "00008000" + shortHex); + setContents("44" + "00008000" + shortHex); assertEquals(shortest, r.readString(Integer.MAX_VALUE)); assertTrue(r.eof()); } @@ -291,8 +285,8 @@ public class ReaderImplTest extends BriarTestCase { 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); + setContents("44" + "00008000" + shortHex + + "44" + "00008000" + shortHex); assertEquals(shortest, r.readString(Short.MAX_VALUE + 1)); assertTrue(r.hasString()); try { @@ -306,34 +300,19 @@ public class ReaderImplTest extends BriarTestCase { 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(Integer.MAX_VALUE); - r.skipString(Integer.MAX_VALUE); + setContents("44" + "00008000" + shortHex + + "44" + "00008000" + shortHex); + r.skipString(); + r.skipString(); 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 public void testStringsMustHaveMinimalLength() throws Exception { // STRING_16 could be encoded as STRING_8 String longest8 = TestUtils.createRandomString(Byte.MAX_VALUE); 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)); try { r.readString(Integer.MAX_VALUE); @@ -342,7 +321,7 @@ public class ReaderImplTest extends BriarTestCase { // STRING_32 could be encoded as STRING_16 String longest16 = TestUtils.createRandomString(Short.MAX_VALUE); 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)); try { r.readString(Integer.MAX_VALUE); @@ -355,8 +334,8 @@ public class ReaderImplTest extends BriarTestCase { byte[] longest = new byte[Byte.MAX_VALUE]; String longHex = StringUtils.toHexString(longest); // {1, 2, 3}, {}, and 127 zero bytes - setContents("0A" + "03" + "010203" + "0A" + "00" + - "0A" + "7F" + longHex); + setContents("51" + "03" + "010203" + "51" + "00" + + "51" + "7F" + longHex); assertArrayEquals(new byte[] {1, 2, 3}, r.readBytes(Integer.MAX_VALUE)); assertArrayEquals(new byte[0], r.readBytes(Integer.MAX_VALUE)); assertArrayEquals(longest, r.readBytes(Integer.MAX_VALUE)); @@ -366,7 +345,7 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadBytes8ChecksMaxLength() throws Exception { // {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)); assertTrue(r.hasBytes()); try { @@ -380,26 +359,14 @@ public class ReaderImplTest extends BriarTestCase { byte[] longest = new byte[Byte.MAX_VALUE]; String longHex = StringUtils.toHexString(longest); // {1, 2, 3}, {}, and 127 zero bytes - setContents("0A" + "03" + "010203" + "0A" + "00" + - "0A" + "7F" + longHex); - r.skipBytes(Integer.MAX_VALUE); - r.skipBytes(Integer.MAX_VALUE); - r.skipBytes(Integer.MAX_VALUE); + setContents("51" + "03" + "010203" + "51" + "00" + + "51" + "7F" + longHex); + r.skipBytes(); + r.skipBytes(); + r.skipBytes(); 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 public void testReadBytes16() throws Exception { byte[] shortest = new byte[Byte.MAX_VALUE + 1]; @@ -407,7 +374,7 @@ public class ReaderImplTest extends BriarTestCase { byte[] longest = new byte[Short.MAX_VALUE]; String longHex = StringUtils.toHexString(longest); // 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(longest, r.readBytes(Integer.MAX_VALUE)); assertTrue(r.eof()); @@ -418,7 +385,7 @@ public class ReaderImplTest extends BriarTestCase { byte[] shortest = new byte[Byte.MAX_VALUE + 1]; String shortHex = StringUtils.toHexString(shortest); // 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)); assertTrue(r.hasBytes()); try { @@ -434,32 +401,18 @@ public class ReaderImplTest extends BriarTestCase { byte[] longest = new byte[Short.MAX_VALUE]; String longHex = StringUtils.toHexString(longest); // 128 zero bytes and 2^15 - 1 zero bytes - setContents("0B" + "0080" + shortHex + "0B" + "7FFF" + longHex); - r.skipBytes(Integer.MAX_VALUE); - r.skipBytes(Integer.MAX_VALUE); + setContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex); + r.skipBytes(); + r.skipBytes(); 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 public void testReadBytes32() throws Exception { byte[] shortest = new byte[Short.MAX_VALUE + 1]; String shortHex = StringUtils.toHexString(shortest); // 2^15 zero bytes - setContents("0C" + "00008000" + shortHex); + setContents("54" + "00008000" + shortHex); assertArrayEquals(shortest, r.readBytes(Integer.MAX_VALUE)); assertTrue(r.eof()); } @@ -469,8 +422,8 @@ public class ReaderImplTest extends BriarTestCase { 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); + setContents("54" + "00008000" + shortHex + + "54" + "00008000" + shortHex); assertArrayEquals(shortest, r.readBytes(Short.MAX_VALUE + 1)); assertTrue(r.hasBytes()); try { @@ -484,43 +437,28 @@ public class ReaderImplTest extends BriarTestCase { 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(Integer.MAX_VALUE); - r.skipBytes(Integer.MAX_VALUE); + setContents("54" + "00008000" + shortHex + + "54" + "00008000" + shortHex); + r.skipBytes(); + r.skipBytes(); 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 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]; 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)); try { r.readBytes(Integer.MAX_VALUE); fail(); } 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]; 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)); try { r.readBytes(Integer.MAX_VALUE); @@ -531,9 +469,9 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testReadList() throws Exception { // A list containing 1, "foo", and 128 - setContents("0D" + "02" + "01" + - "07" + "03" + "666F6F" + - "03" + "0080" + "10"); + setContents("60" + "21" + "01" + + "41" + "03" + "666F6F" + + "22" + "0080" + "80"); r.readListStart(); assertFalse(r.hasListEnd()); assertEquals(1, r.readInteger()); @@ -549,25 +487,25 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipList() throws Exception { // A list containing 1, "foo", and 128 - setContents("0D" + "02" + "01" + - "07" + "03" + "666F6F" + - "03" + "0080" + "10"); + setContents("60" + "21" + "01" + + "41" + "03" + "666F6F" + + "22" + "0080" + "80"); r.skipList(); assertTrue(r.eof()); } @Test public void testReadMap() throws Exception { - // A map containing "foo" -> 123 and byte[0] -> null - setContents("0E" + "07" + "03" + "666F6F" + "02" + "7B" + - "0A" + "00" + "11" + "10"); + // A map containing "foo" -> 123 and "bar" -> null + setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" + + "41" + "03" + "626172" + "00" + "80"); r.readMapStart(); assertFalse(r.hasMapEnd()); assertEquals("foo", r.readString(1000)); assertFalse(r.hasMapEnd()); assertEquals(123, r.readInteger()); assertFalse(r.hasMapEnd()); - assertArrayEquals(new byte[0], r.readBytes(1000)); + assertEquals("bar", r.readString(1000)); assertFalse(r.hasMapEnd()); assertTrue(r.hasNull()); r.readNull(); @@ -578,58 +516,18 @@ public class ReaderImplTest extends BriarTestCase { @Test public void testSkipMap() throws Exception { - // A map containing "foo" -> 123 and byte[0] -> null - setContents("0E" + "07" + "03" + "666F6F" + "02" + "7B" + - "0A" + "00" + "11" + "10"); + // A map containing "foo" -> 123 and "bar" -> null + setContents("70" + "41" + "03" + "666F6F" + "21" + "7B" + + "41" + "03" + "626172" + "00" + "80"); r.skipMap(); assertTrue(r.eof()); } @Test - public void testReadStruct() throws Exception { - // Two empty structs with IDs 0 and 255 - setContents("0F00" + "10" + "0FFF" + "10"); - r.readStructStart(0); - 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(""); + public void testSkipNestedListsAndMaps() throws Exception { + // A list containing a map containing two empty lists + setContents("60" + "70" + "60" + "80" + "60" + "80" + "80" + "80"); + r.skipList(); assertTrue(r.eof()); } diff --git a/briar-tests/src/org/briarproject/serial/WriterImplTest.java b/briar-tests/src/org/briarproject/serial/WriterImplTest.java index 6535bd2cbb83fc8001898461f88f462f60a22616..4a73af42c6a97a7279b6dcc31130f640e920521a 100644 --- a/briar-tests/src/org/briarproject/serial/WriterImplTest.java +++ b/briar-tests/src/org/briarproject/serial/WriterImplTest.java @@ -19,18 +19,25 @@ public class WriterImplTest extends BriarTestCase { private ByteArrayOutputStream out = null; private WriterImpl w = null; + @Override @Before public void setUp() { out = new ByteArrayOutputStream(); w = new WriterImpl(out); } + @Test + public void testWriteNull() throws IOException { + w.writeNull(); + checkContents("00"); + } + @Test public void testWriteBoolean() throws IOException { w.writeBoolean(true); w.writeBoolean(false); - // TRUE tag, FALSE tag - checkContents("01" + "00"); + // BOOLEAN tag, 1, BOOLEAN tag, 0 + checkContents("11" + "01" + "11" + "00"); } @Test @@ -46,11 +53,11 @@ public class WriterImplTest extends BriarTestCase { w.writeInteger(Long.MAX_VALUE); w.writeInteger(Long.MIN_VALUE); // INTEGER_8 tag, 0, INTEGER_8 tag, -1, etc - checkContents("02" + "00" + "02" + "FF" + - "02" + "7F" + "02" + "80" + - "03" + "7FFF" + "03" + "8000" + - "04" + "7FFFFFFF" + "04" + "80000000" + - "05" + "7FFFFFFFFFFFFFFF" + "05" + "8000000000000000"); + checkContents("21" + "00" + "21" + "FF" + + "21" + "7F" + "21" + "80" + + "22" + "7FFF" + "22" + "8000" + + "24" + "7FFFFFFF" + "24" + "80000000" + + "28" + "7FFFFFFFFFFFFFFF" + "28" + "8000000000000000"); } @Test @@ -65,10 +72,10 @@ public class WriterImplTest extends BriarTestCase { w.writeFloat(Double.NEGATIVE_INFINITY); // 1 2047 0 -> 0xFFF00000... w.writeFloat(Double.POSITIVE_INFINITY); // 0 2047 0 -> 0x7FF00000... w.writeFloat(Double.NaN); // 0 2047 1 -> 0x7FF8000000000000 - checkContents("06" + "0000000000000000" + "06" + "3FF0000000000000" - + "06" + "4000000000000000" + "06" + "BFF0000000000000" - + "06" + "8000000000000000" + "06" + "FFF0000000000000" - + "06" + "7FF0000000000000" + "06" + "7FF8000000000000"); + checkContents("38" + "0000000000000000" + "38" + "3FF0000000000000" + + "38" + "4000000000000000" + "38" + "BFF0000000000000" + + "38" + "8000000000000000" + "38" + "FFF0000000000000" + + "38" + "7FF0000000000000" + "38" + "7FF8000000000000"); } @Test @@ -79,8 +86,8 @@ public class WriterImplTest extends BriarTestCase { w.writeString(longest); // STRING_8 tag, length 16, UTF-8 bytes, STRING_8 tag, length 127, // UTF-8 bytes - checkContents("07" + "10" + "666F6F206261722062617A2062616D20" + - "07" + "7F" + longHex); + checkContents("41" + "10" + "666F6F206261722062617A2062616D20" + + "41" + "7F" + longHex); } @Test @@ -93,7 +100,7 @@ public class WriterImplTest extends BriarTestCase { w.writeString(longest); // STRING_16 tag, length 128, UTF-8 bytes, STRING_16 tag, // length 2^15 - 1, UTF-8 bytes - checkContents("08" + "0080" + shortHex + "08" + "7FFF" + longHex); + checkContents("42" + "0080" + shortHex + "42" + "7FFF" + longHex); } @Test @@ -102,7 +109,7 @@ public class WriterImplTest extends BriarTestCase { String shortHex = StringUtils.toHexString(shortest.getBytes("UTF-8")); w.writeString(shortest); // STRING_32 tag, length 2^15, UTF-8 bytes - checkContents("09" + "00008000" + shortHex); + checkContents("44" + "00008000" + shortHex); } @Test @@ -111,8 +118,8 @@ public class WriterImplTest extends BriarTestCase { String longHex = StringUtils.toHexString(longest); w.writeBytes(new byte[] {1, 2, 3}); w.writeBytes(longest); - // BYTES_8 tag, length 3, bytes, BYTES_8 tag, length 127, bytes - checkContents("0A" + "03" + "010203" + "0A" + "7F" + longHex); + // RAW_8 tag, length 3, bytes, RAW_8 tag, length 127, bytes + checkContents("51" + "03" + "010203" + "51" + "7F" + longHex); } @Test @@ -123,8 +130,8 @@ public class WriterImplTest extends BriarTestCase { String longHex = StringUtils.toHexString(longest); w.writeBytes(shortest); w.writeBytes(longest); - // BYTES_16 tag, length 128, bytes, BYTES_16 tag, length 2^15 - 1, bytes - checkContents("0B" + "0080" + shortHex + "0B" + "7FFF" + longHex); + // RAW_16 tag, length 128, bytes, RAW_16 tag, length 2^15 - 1, bytes + checkContents("52" + "0080" + shortHex + "52" + "7FFF" + longHex); } @Test @@ -132,8 +139,8 @@ public class WriterImplTest extends BriarTestCase { byte[] shortest = new byte[Short.MAX_VALUE + 1]; String shortHex = StringUtils.toHexString(shortest); w.writeBytes(shortest); - // BYTES_32 tag, length 2^15, bytes - checkContents("0C" + "00008000" + shortHex); + // RAW_32 tag, length 2^15, bytes + checkContents("54" + "00008000" + shortHex); } @Test @@ -142,7 +149,7 @@ public class WriterImplTest extends BriarTestCase { for(int i = 0; i < 3; i++) l.add(i); w.writeList(l); // 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 @@ -153,20 +160,20 @@ public class WriterImplTest extends BriarTestCase { l.add(2); w.writeList(l); // 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 public void testWriteMap() throws IOException { // Use LinkedHashMap to get predictable iteration order - Map<Object, Object> m = new LinkedHashMap<Object, Object>(); - for(int i = 0; i < 4; i++) m.put(i, i + 1); + Map<String, Object> m = new LinkedHashMap<String, Object>(); + for(int i = 0; i < 4; i++) m.put(String.valueOf(i), i); w.writeMap(m); - // MAP tag, entries as integers, END tag - checkContents("0E" + "02" + "00" + "02" + "01" + - "02" + "01" + "02" + "02" + - "02" + "02" + "02" + "03" + - "02" + "03" + "02" + "04" + "10"); + // MAP tag, keys as strings and values as integers, END tag + checkContents("70" + "41" + "01" + "30" + "21" + "00" + + "41" + "01" + "31" + "21" + "01" + + "41" + "01" + "32" + "21" + "02" + + "41" + "01" + "33" + "21" + "03" + "80"); } @Test @@ -177,9 +184,9 @@ public class WriterImplTest extends BriarTestCase { w.writeInteger(128); w.writeListEnd(); // LIST tag, 1 as integer, "foo" as string, 128 as integer, END tag - checkContents("0D" + "02" + "01" + - "07" + "03" + "666F6F" + - "03" + "0080" + "10"); + checkContents("60" + "21" + "01" + + "41" + "03" + "666F6F" + + "22" + "0080" + "80"); } @Test @@ -187,42 +194,30 @@ public class WriterImplTest extends BriarTestCase { w.writeMapStart(); w.writeString("foo"); w.writeInteger(123); - w.writeBytes(new byte[0]); + w.writeString("bar"); w.writeNull(); w.writeMapEnd(); - // MAP tag, "foo" as string, 123 as integer, {} as bytes, NULL tag, - // END tag - checkContents("0E" + "07" + "03" + "666F6F" + - "02" + "7B" + "0A" + "00" + "11" + "10"); + // MAP tag, "foo" as string, 123 as integer, "bar" as string, + // NULL tag, END tag + checkContents("70" + "41" + "03" + "666F6F" + + "21" + "7B" + "41" + "03" + "626172" + "00" + "80"); } @Test public void testWriteNestedMapsAndLists() throws IOException { - Map<Object, Object> m = new LinkedHashMap<Object, Object>(); - m.put("foo", 123); - List<Object> l = new ArrayList<Object>(); - l.add((byte) 1); - Map<Object, Object> m1 = new LinkedHashMap<Object, Object>(); - m1.put(m, l); - w.writeMap(m1); - // MAP tag, MAP tag, "foo" as string, 123 as integer, END tag, - // LIST tag, 1 as integer, END tag, END tag - checkContents("0E" + "0E" + "07" + "03" + "666F6F" + - "02" + "7B" + "10" + "0D" + "02" + "01" + "10" + "10"); - } - - @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"); + Map<String, Object> inner = new LinkedHashMap<String, Object>(); + inner.put("bar", new byte[0]); + List<Object> list = new ArrayList<Object>(); + list.add(1); + list.add(inner); + Map<String, Object> outer = new LinkedHashMap<String, Object>(); + outer.put("foo", list); + w.writeMap(outer); + // MAP tag, "foo" as string, LIST tag, 1 as integer, MAP tag, + // "bar" as string, {} as raw, END tag, END tag, END tag + checkContents("70" + "41" + "03" + "666F6F" + "60" + + "21" + "01" + "70" + "41" + "03" + "626172" + "51" + "00" + + "80" + "80" + "80"); } private void checkContents(String hex) throws IOException {