Implemented PacketReader, renamed Packet{Reader,Writer}Factory in the

protocol component to Protocol{Reader,Writer}Factory.
This commit is contained in:
akwizgran
2011-08-12 21:55:22 +02:00
parent 4dcf9a70a1
commit 0504a2d6fd
17 changed files with 281 additions and 65 deletions

View File

@@ -0,0 +1,26 @@
package net.sf.briar.api.protocol.writers;
import java.io.InputStream;
import net.sf.briar.api.protocol.Ack;
import net.sf.briar.api.protocol.Batch;
import net.sf.briar.api.protocol.Offer;
import net.sf.briar.api.protocol.Request;
import net.sf.briar.api.protocol.SubscriptionUpdate;
import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.api.serial.ObjectReader;
public interface ProtocolReaderFactory {
ObjectReader<Ack> createAckReader(InputStream in);
ObjectReader<Batch> createBatchReader(InputStream in);
ObjectReader<Offer> createOfferReader(InputStream in);
ObjectReader<Request> createRequestReader(InputStream in);
ObjectReader<SubscriptionUpdate> createSubscriptionReader(InputStream in);
ObjectReader<TransportUpdate> createTransportReader(InputStream in);
}

View File

@@ -2,7 +2,7 @@ package net.sf.briar.api.protocol.writers;
import java.io.OutputStream; import java.io.OutputStream;
public interface PacketWriterFactory { public interface ProtocolWriterFactory {
AckWriter createAckWriter(OutputStream out); AckWriter createAckWriter(OutputStream out);

View File

@@ -8,9 +8,9 @@ public interface ConnectionWindow {
int getBitmap(); int getBitmap();
boolean isSeen(long connectionNumber); boolean isSeen(long connection);
void setSeen(long connectionNumber); void setSeen(long connection);
Collection<Long> getUnseenConnectionNumbers(); Collection<Long> getUnseenConnectionNumbers();
} }

View File

@@ -6,7 +6,7 @@ import javax.crypto.SecretKey;
public interface PacketWriterFactory { public interface PacketWriterFactory {
PacketWriter createPacketWriter(OutputStream out, int transportIdentifier, PacketWriter createPacketWriter(OutputStream out, int transportId,
long connectionNumber, SecretKey macKey, SecretKey tagKey, long connection, SecretKey macKey, SecretKey tagKey,
SecretKey packetKey); SecretKey packetKey);
} }

View File

@@ -7,7 +7,7 @@ import net.sf.briar.api.crypto.CryptoComponent;
import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.AckWriter;
import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.BatchWriter;
import net.sf.briar.api.protocol.writers.OfferWriter; import net.sf.briar.api.protocol.writers.OfferWriter;
import net.sf.briar.api.protocol.writers.PacketWriterFactory; import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
import net.sf.briar.api.protocol.writers.RequestWriter; import net.sf.briar.api.protocol.writers.RequestWriter;
import net.sf.briar.api.protocol.writers.SubscriptionWriter; import net.sf.briar.api.protocol.writers.SubscriptionWriter;
import net.sf.briar.api.protocol.writers.TransportWriter; import net.sf.briar.api.protocol.writers.TransportWriter;
@@ -15,13 +15,13 @@ import net.sf.briar.api.serial.WriterFactory;
import com.google.inject.Inject; import com.google.inject.Inject;
class PacketWriterFactoryImpl implements PacketWriterFactory { class ProtocolWriterFactoryImpl implements ProtocolWriterFactory {
private final MessageDigest messageDigest; private final MessageDigest messageDigest;
private final WriterFactory writerFactory; private final WriterFactory writerFactory;
@Inject @Inject
PacketWriterFactoryImpl(CryptoComponent crypto, ProtocolWriterFactoryImpl(CryptoComponent crypto,
WriterFactory writerFactory) { WriterFactory writerFactory) {
messageDigest = crypto.getMessageDigest(); messageDigest = crypto.getMessageDigest();
this.writerFactory = writerFactory; this.writerFactory = writerFactory;

View File

@@ -1,6 +1,6 @@
package net.sf.briar.protocol.writers; package net.sf.briar.protocol.writers;
import net.sf.briar.api.protocol.writers.PacketWriterFactory; import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
import com.google.inject.AbstractModule; import com.google.inject.AbstractModule;
@@ -8,6 +8,6 @@ public class WritersModule extends AbstractModule {
@Override @Override
protected void configure() { protected void configure() {
bind(PacketWriterFactory.class).to(PacketWriterFactoryImpl.class); bind(ProtocolWriterFactory.class).to(ProtocolWriterFactoryImpl.class);
} }
} }

View File

@@ -76,9 +76,8 @@ DatabaseListener {
initialised = true; initialised = true;
} }
private synchronized byte[] calculateTag(ContactId c, private synchronized byte[] calculateTag(ContactId c, long connection) {
long connectionNumber) { byte[] tag = TagEncoder.encodeTag(transportId, connection, 0L);
byte[] tag = TagEncoder.encodeTag(transportId, connectionNumber, 0L);
Cipher cipher = contactToCipher.get(c); Cipher cipher = contactToCipher.get(c);
assert cipher != null; assert cipher != null;
try { try {
@@ -97,25 +96,25 @@ DatabaseListener {
if(!initialised) initialise(); if(!initialised) initialise();
Bytes b = new Bytes(tag); Bytes b = new Bytes(tag);
ContactId contactId = tagToContact.remove(b); ContactId contactId = tagToContact.remove(b);
Long connectionNumber = tagToConnectionNumber.remove(b); Long connection = tagToConnectionNumber.remove(b);
assert (contactId == null) == (connectionNumber == null); assert (contactId == null) == (connection == null);
if(contactId == null) return null; if(contactId == null) return null;
// The tag was expected - update and save the connection window // The tag was expected - update and save the connection window
ConnectionWindow w = contactToWindow.get(contactId); ConnectionWindow w = contactToWindow.get(contactId);
assert w != null; assert w != null;
w.setSeen(connectionNumber); w.setSeen(connection);
db.setConnectionWindow(contactId, transportId, w); db.setConnectionWindow(contactId, transportId, w);
// Update the set of expected tags // Update the set of expected tags
Map<Long, Bytes> oldTags = contactToTags.remove(contactId); Map<Long, Bytes> oldTags = contactToTags.remove(contactId);
assert oldTags != null; assert oldTags != null;
assert oldTags.containsKey(connectionNumber); assert oldTags.containsKey(connection);
Map<Long, Bytes> newTags = new HashMap<Long, Bytes>(); Map<Long, Bytes> newTags = new HashMap<Long, Bytes>();
for(Long unseen : w.getUnseenConnectionNumbers()) { for(Long unseen : w.getUnseenConnectionNumbers()) {
Bytes expectedTag = oldTags.get(unseen); Bytes expectedTag = oldTags.get(unseen);
if(expectedTag == null) { if(expectedTag == null) {
expectedTag = new Bytes(calculateTag(contactId, unseen)); expectedTag = new Bytes(calculateTag(contactId, unseen));
tagToContact.put(expectedTag, contactId); tagToContact.put(expectedTag, contactId);
tagToConnectionNumber.put(expectedTag, connectionNumber); tagToConnectionNumber.put(expectedTag, connection);
} }
newTags.put(unseen, expectedTag); newTags.put(unseen, expectedTag);
} }

View File

@@ -23,29 +23,29 @@ class ConnectionWindowImpl implements ConnectionWindow {
return bitmap; return bitmap;
} }
public boolean isSeen(long connectionNumber) { public boolean isSeen(long connection) {
int offset = getOffset(connectionNumber); int offset = getOffset(connection);
int mask = 0x80000000 >>> offset; int mask = 0x80000000 >>> offset;
return (bitmap & mask) != 0; return (bitmap & mask) != 0;
} }
private int getOffset(long connectionNumber) { private int getOffset(long connection) {
if(connectionNumber < 0L) throw new IllegalArgumentException(); if(connection < 0L) throw new IllegalArgumentException();
if(connectionNumber > Constants.MAX_32_BIT_UNSIGNED) if(connection > Constants.MAX_32_BIT_UNSIGNED)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
int offset = (int) (connectionNumber - centre) + 16; int offset = (int) (connection - centre) + 16;
if(offset < 0 || offset > 31) throw new IllegalArgumentException(); if(offset < 0 || offset > 31) throw new IllegalArgumentException();
return offset; return offset;
} }
public void setSeen(long connectionNumber) { public void setSeen(long connection) {
int offset = getOffset(connectionNumber); int offset = getOffset(connection);
int mask = 0x80000000 >>> offset; int mask = 0x80000000 >>> offset;
if((bitmap & mask) != 0) throw new IllegalArgumentException(); if((bitmap & mask) != 0) throw new IllegalArgumentException();
bitmap |= mask; bitmap |= mask;
// If the new connection number is above the centre, slide the window // If the new connection number is above the centre, slide the window
if(connectionNumber >= centre) { if(connection >= centre) {
centre = connectionNumber + 1; centre = connection + 1;
bitmap <<= offset - 16 + 1; bitmap <<= offset - 16 + 1;
} }
} }

View File

@@ -0,0 +1,126 @@
package net.sf.briar.transport;
import java.io.IOException;
import java.io.InputStream;
import javax.crypto.Mac;
import net.sf.briar.api.protocol.Ack;
import net.sf.briar.api.protocol.Batch;
import net.sf.briar.api.protocol.Offer;
import net.sf.briar.api.protocol.Request;
import net.sf.briar.api.protocol.SubscriptionUpdate;
import net.sf.briar.api.protocol.Tags;
import net.sf.briar.api.protocol.TransportUpdate;
import net.sf.briar.api.protocol.writers.ProtocolReaderFactory;
import net.sf.briar.api.serial.Reader;
import net.sf.briar.api.serial.ReaderFactory;
import net.sf.briar.api.transport.PacketReader;
class PacketReaderImpl implements PacketReader {
private final Reader reader;
private final PacketDecrypter decrypter;
private final Mac mac;
private final int transportId;
private final long connection;
private long packet = 0L;
private boolean betweenPackets = true;
PacketReaderImpl(byte[] firstTag, ReaderFactory readerFactory,
ProtocolReaderFactory protocol, PacketDecrypter decrypter, Mac mac,
int transportId, long connection) {
InputStream in = decrypter.getInputStream();
reader = readerFactory.createReader(in);
reader.addObjectReader(Tags.ACK, protocol.createAckReader(in));
reader.addObjectReader(Tags.BATCH, protocol.createBatchReader(in));
reader.addObjectReader(Tags.OFFER, protocol.createOfferReader(in));
reader.addObjectReader(Tags.REQUEST, protocol.createRequestReader(in));
reader.addObjectReader(Tags.SUBSCRIPTIONS,
protocol.createSubscriptionReader(in));
reader.addObjectReader(Tags.TRANSPORTS,
protocol.createTransportReader(in));
this.decrypter = decrypter;
this.mac = mac;
this.transportId = transportId;
this.connection = connection;
}
public boolean eof() throws IOException {
return reader.eof();
}
public boolean hasAck() throws IOException {
if(betweenPackets) readTag();
return reader.hasUserDefined(Tags.ACK);
}
private void readTag() throws IOException {
assert betweenPackets;
if(packet > Constants.MAX_32_BIT_UNSIGNED)
throw new IllegalStateException();
byte[] tag = decrypter.readTag();
if(!TagDecoder.decodeTag(tag, transportId, connection, packet))
throw new IOException();
mac.update(tag);
packet++;
betweenPackets = false;
}
public Ack readAck() throws IOException {
if(betweenPackets) readTag();
return reader.readUserDefined(Tags.ACK, Ack.class);
}
public boolean hasBatch() throws IOException {
if(betweenPackets) readTag();
return reader.hasUserDefined(Tags.BATCH);
}
public Batch readBatch() throws IOException {
if(betweenPackets) readTag();
return reader.readUserDefined(Tags.BATCH, Batch.class);
}
public boolean hasOffer() throws IOException {
if(betweenPackets) readTag();
return reader.hasUserDefined(Tags.OFFER);
}
public Offer readOffer() throws IOException {
if(betweenPackets) readTag();
return reader.readUserDefined(Tags.OFFER, Offer.class);
}
public boolean hasRequest() throws IOException {
if(betweenPackets) readTag();
return reader.hasUserDefined(Tags.REQUEST);
}
public Request readRequest() throws IOException {
if(betweenPackets) readTag();
return reader.readUserDefined(Tags.REQUEST, Request.class);
}
public boolean hasSubscriptionUpdate() throws IOException {
if(betweenPackets) readTag();
return reader.hasUserDefined(Tags.SUBSCRIPTIONS);
}
public SubscriptionUpdate readSubscriptionUpdate() throws IOException {
if(betweenPackets) readTag();
return reader.readUserDefined(Tags.SUBSCRIPTIONS,
SubscriptionUpdate.class);
}
public boolean hasTransportUpdate() throws IOException {
if(betweenPackets) readTag();
return reader.hasUserDefined(Tags.TRANSPORTS);
}
public TransportUpdate readTransportUpdate() throws IOException {
if(betweenPackets) readTag();
return reader.readUserDefined(Tags.TRANSPORTS, TransportUpdate.class);
}
}

View File

@@ -21,9 +21,9 @@ class PacketWriterFactoryImpl implements PacketWriterFactory {
this.crypto = crypto; this.crypto = crypto;
} }
public PacketWriter createPacketWriter(OutputStream out, public PacketWriter createPacketWriter(OutputStream out, int transportId,
int transportIdentifier, long connectionNumber, SecretKey macKey, long connection, SecretKey macKey, SecretKey tagKey,
SecretKey tagKey, SecretKey packetKey) { SecretKey packetKey) {
Mac mac = crypto.getMac(); Mac mac = crypto.getMac();
try { try {
mac.init(macKey); mac.init(macKey);
@@ -32,7 +32,7 @@ class PacketWriterFactoryImpl implements PacketWriterFactory {
} }
PacketEncrypter e = new PacketEncrypterImpl(out, crypto.getTagCipher(), PacketEncrypter e = new PacketEncrypterImpl(out, crypto.getTagCipher(),
crypto.getPacketCipher(), tagKey, packetKey); crypto.getPacketCipher(), tagKey, packetKey);
return new PacketWriterImpl(e, mac, transportIdentifier, return new PacketWriterImpl(e, mac, transportId,
connectionNumber); connection);
} }
} }

View File

@@ -12,25 +12,25 @@ class PacketWriterImpl extends FilterOutputStream implements PacketWriter {
private final PacketEncrypter encrypter; private final PacketEncrypter encrypter;
private final Mac mac; private final Mac mac;
private final int transportIdentifier; private final int transportId;
private final long connectionNumber; private final long connection;
private long packetNumber = 0L; private long packet = 0L;
private boolean betweenPackets = true; private boolean betweenPackets = true;
PacketWriterImpl(PacketEncrypter encrypter, Mac mac, PacketWriterImpl(PacketEncrypter encrypter, Mac mac, int transportId,
int transportIdentifier, long connectionNumber) { long connection) {
super(encrypter.getOutputStream()); super(encrypter.getOutputStream());
this.encrypter = encrypter; this.encrypter = encrypter;
this.mac = mac; this.mac = mac;
if(transportIdentifier < 0) throw new IllegalArgumentException(); if(transportId < 0) throw new IllegalArgumentException();
if(transportIdentifier > Constants.MAX_16_BIT_UNSIGNED) if(transportId > Constants.MAX_16_BIT_UNSIGNED)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.transportIdentifier = transportIdentifier; this.transportId = transportId;
if(connectionNumber < 0L) throw new IllegalArgumentException(); if(connection < 0L) throw new IllegalArgumentException();
if(connectionNumber > Constants.MAX_32_BIT_UNSIGNED) if(connection > Constants.MAX_32_BIT_UNSIGNED)
throw new IllegalArgumentException(); throw new IllegalArgumentException();
this.connectionNumber = connectionNumber; this.connection = connection;
} }
public OutputStream getOutputStream() { public OutputStream getOutputStream() {
@@ -69,14 +69,15 @@ class PacketWriterImpl extends FilterOutputStream implements PacketWriter {
} }
private void writeTag() throws IOException { private void writeTag() throws IOException {
if(packetNumber > Constants.MAX_32_BIT_UNSIGNED) assert betweenPackets;
if(packet > Constants.MAX_32_BIT_UNSIGNED)
throw new IllegalStateException(); throw new IllegalStateException();
byte[] tag = TagEncoder.encodeTag(transportIdentifier, connectionNumber, byte[] tag = TagEncoder.encodeTag(transportId, connection,
packetNumber); packet);
// Write the tag to the encrypter and start calculating the MAC // Write the tag to the encrypter and start calculating the MAC
encrypter.writeTag(tag); encrypter.writeTag(tag);
mac.update(tag); mac.update(tag);
packetNumber++; packet++;
betweenPackets = false; betweenPackets = false;
} }
} }

View File

@@ -0,0 +1,33 @@
package net.sf.briar.transport;
class TagDecoder {
static boolean decodeTag(byte[] tag, int transportId, long connection,
long packet) {
if(tag.length != Constants.TAG_BYTES) return false;
// First 16 bits must be zero
if(readUint16(tag, 0) != 0) return false;
// Transport identifier is encoded as an unsigned 16-bit integer
if(readUint16(tag, 2) != transportId) return false;
// Connection number is encoded as an unsigned 32-bit integer
if(readUint32(tag, 4) != connection) return false;
// Packet number is encoded as an unsigned 32-bit integer
if(readUint32(tag, 8) != packet) return false;
// Last 32 bits must be zero
if(readUint32(tag, 12) != 0L) return false;
return true;
}
// Package access for testing
static int readUint16(byte[] b, int offset) {
assert b.length >= offset + 2;
return ((b[offset] & 0xFF) << 8) | (b[offset + 1] & 0xFF);
}
// Package access for testing
static long readUint32(byte[] b, int offset) {
assert b.length >= offset + 4;
return ((b[offset] & 0xFFL) << 24) | ((b[offset + 1] & 0xFFL) << 16)
| ((b[offset + 2] & 0xFFL) << 8) | (b[offset + 3] & 0xFFL);
}
}

View File

@@ -1,16 +1,16 @@
package net.sf.briar.transport; package net.sf.briar.transport;
public class TagEncoder { class TagEncoder {
static byte[] encodeTag(int transportIdentifier, long connectionNumber, static byte[] encodeTag(int transportId, long connection,
long packetNumber) { long packet) {
byte[] tag = new byte[Constants.TAG_BYTES]; byte[] tag = new byte[Constants.TAG_BYTES];
// Encode the transport identifier as an unsigned 16-bit integer // Encode the transport identifier as an unsigned 16-bit integer
writeUint16(transportIdentifier, tag, 2); writeUint16(transportId, tag, 2);
// Encode the connection number as an unsigned 32-bit integer // Encode the connection number as an unsigned 32-bit integer
writeUint32(connectionNumber, tag, 4); writeUint32(connection, tag, 4);
// Encode the packet number as an unsigned 32-bit integer // Encode the packet number as an unsigned 32-bit integer
writeUint32(packetNumber, tag, 8); writeUint32(packet, tag, 8);
return tag; return tag;
} }

View File

@@ -37,6 +37,7 @@
<test name='net.sf.briar.transport.PacketDecrypterImplTest'/> <test name='net.sf.briar.transport.PacketDecrypterImplTest'/>
<test name='net.sf.briar.transport.PacketEncrypterImplTest'/> <test name='net.sf.briar.transport.PacketEncrypterImplTest'/>
<test name='net.sf.briar.transport.PacketWriterImplTest'/> <test name='net.sf.briar.transport.PacketWriterImplTest'/>
<test name='net.sf.briar.transport.TagDecoderTest'/>
<test name='net.sf.briar.transport.TagEncoderTest'/> <test name='net.sf.briar.transport.TagEncoderTest'/>
<test name='net.sf.briar.util.FileUtilsTest'/> <test name='net.sf.briar.util.FileUtilsTest'/>
<test name='net.sf.briar.util.StringUtilsTest'/> <test name='net.sf.briar.util.StringUtilsTest'/>

View File

@@ -34,7 +34,7 @@ import net.sf.briar.api.protocol.UniqueId;
import net.sf.briar.api.protocol.writers.AckWriter; import net.sf.briar.api.protocol.writers.AckWriter;
import net.sf.briar.api.protocol.writers.BatchWriter; import net.sf.briar.api.protocol.writers.BatchWriter;
import net.sf.briar.api.protocol.writers.OfferWriter; import net.sf.briar.api.protocol.writers.OfferWriter;
import net.sf.briar.api.protocol.writers.PacketWriterFactory; import net.sf.briar.api.protocol.writers.ProtocolWriterFactory;
import net.sf.briar.api.protocol.writers.RequestWriter; import net.sf.briar.api.protocol.writers.RequestWriter;
import net.sf.briar.api.protocol.writers.SubscriptionWriter; import net.sf.briar.api.protocol.writers.SubscriptionWriter;
import net.sf.briar.api.protocol.writers.TransportWriter; import net.sf.briar.api.protocol.writers.TransportWriter;
@@ -60,7 +60,7 @@ public class FileReadWriteTest extends TestCase {
private final long start = System.currentTimeMillis(); private final long start = System.currentTimeMillis();
private final ReaderFactory readerFactory; private final ReaderFactory readerFactory;
private final PacketWriterFactory packetWriterFactory; private final ProtocolWriterFactory protocolWriterFactory;
private final CryptoComponent crypto; private final CryptoComponent crypto;
private final AckReader ackReader; private final AckReader ackReader;
private final BatchReader batchReader; private final BatchReader batchReader;
@@ -81,7 +81,7 @@ public class FileReadWriteTest extends TestCase {
new ProtocolModule(), new SerialModule(), new ProtocolModule(), new SerialModule(),
new WritersModule()); new WritersModule());
readerFactory = i.getInstance(ReaderFactory.class); readerFactory = i.getInstance(ReaderFactory.class);
packetWriterFactory = i.getInstance(PacketWriterFactory.class); protocolWriterFactory = i.getInstance(ProtocolWriterFactory.class);
crypto = i.getInstance(CryptoComponent.class); crypto = i.getInstance(CryptoComponent.class);
assertEquals(crypto.getMessageDigest().getDigestLength(), assertEquals(crypto.getMessageDigest().getDigestLength(),
UniqueId.LENGTH); UniqueId.LENGTH);
@@ -126,39 +126,39 @@ public class FileReadWriteTest extends TestCase {
public void testWriteFile() throws Exception { public void testWriteFile() throws Exception {
FileOutputStream out = new FileOutputStream(file); FileOutputStream out = new FileOutputStream(file);
AckWriter a = packetWriterFactory.createAckWriter(out); AckWriter a = protocolWriterFactory.createAckWriter(out);
assertTrue(a.writeBatchId(ack)); assertTrue(a.writeBatchId(ack));
a.finish(); a.finish();
BatchWriter b = packetWriterFactory.createBatchWriter(out); BatchWriter b = protocolWriterFactory.createBatchWriter(out);
assertTrue(b.writeMessage(message.getBytes())); assertTrue(b.writeMessage(message.getBytes()));
assertTrue(b.writeMessage(message1.getBytes())); assertTrue(b.writeMessage(message1.getBytes()));
assertTrue(b.writeMessage(message2.getBytes())); assertTrue(b.writeMessage(message2.getBytes()));
assertTrue(b.writeMessage(message3.getBytes())); assertTrue(b.writeMessage(message3.getBytes()));
b.finish(); b.finish();
OfferWriter o = packetWriterFactory.createOfferWriter(out); OfferWriter o = protocolWriterFactory.createOfferWriter(out);
assertTrue(o.writeMessageId(message.getId())); assertTrue(o.writeMessageId(message.getId()));
assertTrue(o.writeMessageId(message1.getId())); assertTrue(o.writeMessageId(message1.getId()));
assertTrue(o.writeMessageId(message2.getId())); assertTrue(o.writeMessageId(message2.getId()));
assertTrue(o.writeMessageId(message3.getId())); assertTrue(o.writeMessageId(message3.getId()));
o.finish(); o.finish();
RequestWriter r = packetWriterFactory.createRequestWriter(out); RequestWriter r = protocolWriterFactory.createRequestWriter(out);
BitSet requested = new BitSet(4); BitSet requested = new BitSet(4);
requested.set(1); requested.set(1);
requested.set(3); requested.set(3);
r.writeBitmap(requested, 4); r.writeBitmap(requested, 4);
SubscriptionWriter s = SubscriptionWriter s =
packetWriterFactory.createSubscriptionWriter(out); protocolWriterFactory.createSubscriptionWriter(out);
// Use a LinkedHashMap for predictable iteration order // Use a LinkedHashMap for predictable iteration order
Map<Group, Long> subs = new LinkedHashMap<Group, Long>(); Map<Group, Long> subs = new LinkedHashMap<Group, Long>();
subs.put(group, 0L); subs.put(group, 0L);
subs.put(group1, 0L); subs.put(group1, 0L);
s.writeSubscriptions(subs); s.writeSubscriptions(subs);
TransportWriter t = packetWriterFactory.createTransportWriter(out); TransportWriter t = protocolWriterFactory.createTransportWriter(out);
t.writeTransports(transports); t.writeTransports(transports);
out.close(); out.close();

View File

@@ -0,0 +1,30 @@
package net.sf.briar.transport;
import junit.framework.TestCase;
import net.sf.briar.util.StringUtils;
import org.junit.Test;
public class TagDecoderTest extends TestCase {
@Test
public void testReadUint16() {
byte[] b = StringUtils.fromHexString("000000");
assertEquals(0, TagDecoder.readUint16(b, 1));
b = StringUtils.fromHexString("000001");
assertEquals(1, TagDecoder.readUint16(b, 1));
b = StringUtils.fromHexString("00FFFF");
assertEquals(65535, TagDecoder.readUint16(b, 1));
}
@Test
public void testReadUint32() {
byte[] b = StringUtils.fromHexString("0000000000");
assertEquals(0L, TagDecoder.readUint32(b, 1));
b = StringUtils.fromHexString("0000000001");
assertEquals(1L, TagDecoder.readUint32(b, 1));
b = StringUtils.fromHexString("00FFFFFFFF");
assertEquals(4294967295L, TagDecoder.readUint32(b, 1));
}
}

View File

@@ -9,7 +9,7 @@ import junit.framework.TestCase;
public class TagEncoderTest extends TestCase { public class TagEncoderTest extends TestCase {
@Test @Test
public void testWriteUint16() throws Exception { public void testWriteUint16() {
byte[] b = new byte[3]; byte[] b = new byte[3];
TagEncoder.writeUint16(0, b, 1); TagEncoder.writeUint16(0, b, 1);
assertEquals("000000", StringUtils.toHexString(b)); assertEquals("000000", StringUtils.toHexString(b));
@@ -20,7 +20,7 @@ public class TagEncoderTest extends TestCase {
} }
@Test @Test
public void testWriteUint32() throws Exception { public void testWriteUint32() {
byte[] b = new byte[5]; byte[] b = new byte[5];
TagEncoder.writeUint32(0L, b, 1); TagEncoder.writeUint32(0L, b, 1);
assertEquals("0000000000", StringUtils.toHexString(b)); assertEquals("0000000000", StringUtils.toHexString(b));