Massive refactoring to merge handling of simplex and duplex connections.

This commit is contained in:
akwizgran
2014-11-04 16:51:25 +00:00
parent b24f153704
commit 7b8181e309
67 changed files with 1981 additions and 2288 deletions

View File

@@ -45,8 +45,6 @@ import org.briarproject.crypto.CryptoModule;
import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.messaging.duplex.DuplexMessagingModule;
import org.briarproject.messaging.simplex.SimplexMessagingModule;
import org.briarproject.reliability.ReliabilityModule;
import org.briarproject.serial.SerialModule;
import org.briarproject.transport.TransportModule;
@@ -81,7 +79,6 @@ public class ProtocolIntegrationTest extends BriarTestCase {
new TestLifecycleModule(), new TestSystemModule(),
new TestUiModule(), new CryptoModule(), new DatabaseModule(),
new EventModule(), new MessagingModule(),
new DuplexMessagingModule(), new SimplexMessagingModule(),
new ReliabilityModule(), new SerialModule(),
new TransportModule());
streamReaderFactory = i.getInstance(StreamReaderFactory.class);
@@ -125,29 +122,29 @@ public class ProtocolIntegrationTest extends BriarTestCase {
ByteArrayOutputStream out = new ByteArrayOutputStream();
StreamContext ctx = new StreamContext(contactId, transportId,
secret.clone(), 0, true);
StreamWriter conn = streamWriterFactory.createStreamWriter(
out, MAX_FRAME_LENGTH, Long.MAX_VALUE, ctx, false, true);
OutputStream out1 = conn.getOutputStream();
PacketWriter writer = packetWriterFactory.createPacketWriter(out1,
StreamWriter streamWriter = streamWriterFactory.createStreamWriter(out,
MAX_FRAME_LENGTH, ctx);
OutputStream out1 = streamWriter.getOutputStream();
PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out1,
false);
writer.writeAck(new Ack(messageIds));
packetWriter.writeAck(new Ack(messageIds));
writer.writeMessage(message.getSerialised());
writer.writeMessage(message1.getSerialised());
packetWriter.writeMessage(message.getSerialised());
packetWriter.writeMessage(message1.getSerialised());
writer.writeOffer(new Offer(messageIds));
packetWriter.writeOffer(new Offer(messageIds));
writer.writeRequest(new Request(messageIds));
packetWriter.writeRequest(new Request(messageIds));
SubscriptionUpdate su = new SubscriptionUpdate(Arrays.asList(group), 1);
writer.writeSubscriptionUpdate(su);
packetWriter.writeSubscriptionUpdate(su);
TransportUpdate tu = new TransportUpdate(transportId,
transportProperties, 1);
writer.writeTransportUpdate(tu);
packetWriter.writeTransportUpdate(tu);
writer.flush();
packetWriter.flush();
return out.toByteArray();
}
@@ -158,44 +155,44 @@ public class ProtocolIntegrationTest extends BriarTestCase {
// FIXME: Check that the expected tag was received
StreamContext ctx = new StreamContext(contactId, transportId,
secret.clone(), 0, false);
StreamReader conn = streamReaderFactory.createStreamReader(
in, MAX_FRAME_LENGTH, ctx, true, true);
InputStream in1 = conn.getInputStream();
PacketReader reader = packetReaderFactory.createPacketReader(in1);
StreamReader streamReader = streamReaderFactory.createStreamReader(in,
MAX_FRAME_LENGTH, ctx);
InputStream in1 = streamReader.getInputStream();
PacketReader packetReader = packetReaderFactory.createPacketReader(in1);
// Read the ack
assertTrue(reader.hasAck());
Ack a = reader.readAck();
assertTrue(packetReader.hasAck());
Ack a = packetReader.readAck();
assertEquals(messageIds, a.getMessageIds());
// Read and verify the messages
assertTrue(reader.hasMessage());
UnverifiedMessage m = reader.readMessage();
assertTrue(packetReader.hasMessage());
UnverifiedMessage m = packetReader.readMessage();
checkMessageEquality(message, messageVerifier.verifyMessage(m));
assertTrue(reader.hasMessage());
m = reader.readMessage();
assertTrue(packetReader.hasMessage());
m = packetReader.readMessage();
checkMessageEquality(message1, messageVerifier.verifyMessage(m));
assertFalse(reader.hasMessage());
assertFalse(packetReader.hasMessage());
// Read the offer
assertTrue(reader.hasOffer());
Offer o = reader.readOffer();
assertTrue(packetReader.hasOffer());
Offer o = packetReader.readOffer();
assertEquals(messageIds, o.getMessageIds());
// Read the request
assertTrue(reader.hasRequest());
Request req = reader.readRequest();
assertTrue(packetReader.hasRequest());
Request req = packetReader.readRequest();
assertEquals(messageIds, req.getMessageIds());
// Read the subscription update
assertTrue(reader.hasSubscriptionUpdate());
SubscriptionUpdate su = reader.readSubscriptionUpdate();
assertTrue(packetReader.hasSubscriptionUpdate());
SubscriptionUpdate su = packetReader.readSubscriptionUpdate();
assertEquals(Arrays.asList(group), su.getGroups());
assertEquals(1, su.getVersion());
// Read the transport update
assertTrue(reader.hasTransportUpdate());
TransportUpdate tu = reader.readTransportUpdate();
assertTrue(packetReader.hasTransportUpdate());
TransportUpdate tu = packetReader.readTransportUpdate();
assertEquals(transportId, tu.getId());
assertEquals(transportProperties, tu.getProperties());
assertEquals(1, tu.getVersion());

View File

@@ -25,10 +25,8 @@ public class KeyDerivationTest extends BriarTestCase {
@Test
public void testKeysAreDistinct() {
List<SecretKey> keys = new ArrayList<SecretKey>();
keys.add(crypto.deriveFrameKey(secret, 0, false, false));
keys.add(crypto.deriveFrameKey(secret, 0, false, true));
keys.add(crypto.deriveFrameKey(secret, 0, true, false));
keys.add(crypto.deriveFrameKey(secret, 0, true, true));
keys.add(crypto.deriveFrameKey(secret, 0, true));
keys.add(crypto.deriveFrameKey(secret, 0, false));
keys.add(crypto.deriveTagKey(secret, true));
keys.add(crypto.deriveTagKey(secret, false));
for(int i = 0; i < 4; i++) {

View File

@@ -46,8 +46,6 @@ import org.briarproject.api.messaging.TransportUpdate;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule;
import org.briarproject.messaging.duplex.DuplexMessagingModule;
import org.briarproject.messaging.simplex.SimplexMessagingModule;
import org.briarproject.serial.SerialModule;
import org.briarproject.transport.TransportModule;
import org.junit.Test;
@@ -67,8 +65,7 @@ public class ConstantsTest extends BriarTestCase {
Injector i = Guice.createInjector(new TestDatabaseModule(),
new TestLifecycleModule(), new TestSystemModule(),
new CryptoModule(), new DatabaseModule(), new EventModule(),
new MessagingModule(), new DuplexMessagingModule(),
new SimplexMessagingModule(), new SerialModule(),
new MessagingModule(), new SerialModule(),
new TransportModule());
crypto = i.getInstance(CryptoComponent.class);
groupFactory = i.getInstance(GroupFactory.class);

View File

@@ -1,4 +1,4 @@
package org.briarproject.messaging.simplex;
package org.briarproject.messaging;
import static org.briarproject.api.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.messaging.MessagingConstants.GROUP_SALT_LENGTH;
@@ -30,9 +30,9 @@ import org.briarproject.api.messaging.GroupFactory;
import org.briarproject.api.messaging.Message;
import org.briarproject.api.messaging.MessageFactory;
import org.briarproject.api.messaging.MessageVerifier;
import org.briarproject.api.messaging.MessagingSession;
import org.briarproject.api.messaging.PacketReaderFactory;
import org.briarproject.api.messaging.PacketWriterFactory;
import org.briarproject.api.transport.ConnectionRegistry;
import org.briarproject.api.transport.Endpoint;
import org.briarproject.api.transport.StreamContext;
import org.briarproject.api.transport.StreamReaderFactory;
@@ -41,8 +41,6 @@ import org.briarproject.api.transport.TagRecogniser;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.messaging.duplex.DuplexMessagingModule;
import org.briarproject.plugins.ImmediateExecutor;
import org.briarproject.serial.SerialModule;
import org.briarproject.transport.TransportModule;
@@ -88,8 +86,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
return Guice.createInjector(new TestDatabaseModule(dir),
new TestLifecycleModule(), new TestSystemModule(),
new CryptoModule(), new DatabaseModule(), new EventModule(),
new MessagingModule(), new DuplexMessagingModule(),
new SimplexMessagingModule(), new SerialModule(),
new MessagingModule(), new SerialModule(),
new TransportModule());
}
@@ -140,29 +137,26 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
Message message = messageFactory.createAnonymousMessage(null, group,
contentType, timestamp, body);
db.addLocalMessage(message);
// Create an outgoing simplex connection
// Create an outgoing messaging session
ByteArrayOutputStream out = new ByteArrayOutputStream();
ConnectionRegistry connRegistry =
alice.getInstance(ConnectionRegistry.class);
StreamWriterFactory connWriterFactory =
StreamWriterFactory streamWriterFactory =
alice.getInstance(StreamWriterFactory.class);
PacketWriterFactory packetWriterFactory =
alice.getInstance(PacketWriterFactory.class);
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, Long.MAX_VALUE, Long.MAX_VALUE);
TestTransportConnectionWriter transport =
new TestTransportConnectionWriter(out);
StreamContext ctx = km.getStreamContext(contactId, transportId);
assertNotNull(ctx);
OutgoingSimplexConnection simplex = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
MessagingSession session = new SinglePassOutgoingSession(db,
new ImmediateExecutor(), streamWriterFactory,
packetWriterFactory, ctx, transport);
// Write whatever needs to be written
simplex.write();
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
session.run();
transport.dispose(false);
// Clean up
km.stop();
db.close();
// Return the contents of the simplex connection
// Return the contents of the stream
return out.toByteArray();
}
@@ -204,28 +198,24 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
assertEquals(tag.length, read);
StreamContext ctx = rec.recogniseTag(transportId, tag);
assertNotNull(ctx);
// Create an incoming simplex connection
// Create an incoming messaging session
MessageVerifier messageVerifier =
bob.getInstance(MessageVerifier.class);
ConnectionRegistry connRegistry =
bob.getInstance(ConnectionRegistry.class);
StreamReaderFactory connWriterFactory =
StreamReaderFactory streamReaderFactory =
bob.getInstance(StreamReaderFactory.class);
PacketReaderFactory packetWriterFactory =
PacketReaderFactory packetReaderFactory =
bob.getInstance(PacketReaderFactory.class);
TestSimplexTransportReader transport =
new TestSimplexTransportReader(in);
IncomingSimplexConnection simplex = new IncomingSimplexConnection(
TestTransportConnectionReader transport =
new TestTransportConnectionReader(in);
MessagingSession session = new IncomingSession(db,
new ImmediateExecutor(), new ImmediateExecutor(),
messageVerifier, db, connRegistry, connWriterFactory,
packetWriterFactory, ctx, transport);
messageVerifier, streamReaderFactory, packetReaderFactory,
ctx, transport);
// No messages should have been added yet
assertFalse(listener.messageAdded);
// Read whatever needs to be read
simplex.read();
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
assertTrue(transport.getRecognised());
session.run();
transport.dispose(false, true);
// The private message from Alice should have been added
assertTrue(listener.messageAdded);
// Clean up

View File

@@ -1,9 +1,7 @@
package org.briarproject.messaging.simplex;
package org.briarproject.messaging;
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
import static org.briarproject.api.transport.TransportConstants.HEADER_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MAC_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH;
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
import java.io.ByteArrayOutputStream;
@@ -23,14 +21,12 @@ import org.briarproject.api.db.DatabaseComponent;
import org.briarproject.api.db.DatabaseExecutor;
import org.briarproject.api.messaging.Ack;
import org.briarproject.api.messaging.MessageId;
import org.briarproject.api.messaging.MessagingSession;
import org.briarproject.api.messaging.PacketWriterFactory;
import org.briarproject.api.transport.ConnectionRegistry;
import org.briarproject.api.transport.StreamContext;
import org.briarproject.api.transport.StreamWriterFactory;
import org.briarproject.crypto.CryptoModule;
import org.briarproject.event.EventModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.messaging.duplex.DuplexMessagingModule;
import org.briarproject.serial.SerialModule;
import org.briarproject.transport.TransportModule;
import org.jmock.Expectations;
@@ -42,39 +38,37 @@ import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
public class OutgoingSimplexConnectionTest extends BriarTestCase {
public class SinglePassOutgoingSessionTest extends BriarTestCase {
// FIXME: This is an integration test, not a unit test
private final Mockery context;
private final DatabaseComponent db;
private final ConnectionRegistry connRegistry;
private final StreamWriterFactory connWriterFactory;
private final Executor dbExecutor;
private final StreamWriterFactory streamWriterFactory;
private final PacketWriterFactory packetWriterFactory;
private final ContactId contactId;
private final MessageId messageId;
private final TransportId transportId;
private final byte[] secret;
public OutgoingSimplexConnectionTest() {
public SinglePassOutgoingSessionTest() {
context = new Mockery();
db = context.mock(DatabaseComponent.class);
dbExecutor = Executors.newSingleThreadExecutor();
Module testModule = new AbstractModule() {
@Override
public void configure() {
bind(DatabaseComponent.class).toInstance(db);
bind(Executor.class).annotatedWith(
DatabaseExecutor.class).toInstance(
Executors.newCachedThreadPool());
DatabaseExecutor.class).toInstance(dbExecutor);
}
};
Injector i = Guice.createInjector(testModule,
new TestLifecycleModule(), new TestSystemModule(),
new CryptoModule(), new EventModule(), new MessagingModule(),
new DuplexMessagingModule(), new SimplexMessagingModule(),
new SerialModule(), new TransportModule());
connRegistry = i.getInstance(ConnectionRegistry.class);
connWriterFactory = i.getInstance(StreamWriterFactory.class);
streamWriterFactory = i.getInstance(StreamWriterFactory.class);
packetWriterFactory = i.getInstance(PacketWriterFactory.class);
contactId = new ContactId(234);
messageId = new MessageId(TestUtils.getRandomId());
@@ -83,34 +77,15 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase {
new Random().nextBytes(secret);
}
@Test
public void testConnectionTooShort() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, MAX_PACKET_LENGTH, Long.MAX_VALUE);
StreamContext ctx = new StreamContext(contactId, transportId,
secret, 0, true);
OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
connection.write();
// Nothing should have been written
assertEquals(0, out.size());
// The transport should have been disposed with exception == true
assertTrue(transport.getDisposed());
assertTrue(transport.getException());
}
@Test
public void testNothingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, MIN_STREAM_LENGTH, Long.MAX_VALUE);
TestTransportConnectionWriter writer =
new TestTransportConnectionWriter(out);
StreamContext ctx = new StreamContext(contactId, transportId,
secret, 0, true);
OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
MessagingSession session = new SinglePassOutgoingSession(db, dbExecutor,
streamWriterFactory, packetWriterFactory, ctx, writer);
context.checking(new Expectations() {{
// No transport acks to send
oneOf(db).generateTransportAcks(contactId);
@@ -141,25 +116,22 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase {
with(any(long.class)));
will(returnValue(null));
}});
connection.write();
session.run();
// Only the tag and an empty final frame should have been written
assertEquals(TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH, out.size());
// The transport should have been disposed with exception == false
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
context.assertIsSatisfied();
}
@Test
public void testSomethingToSend() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
TestSimplexTransportWriter transport = new TestSimplexTransportWriter(
out, MIN_STREAM_LENGTH, Long.MAX_VALUE);
TestTransportConnectionWriter writer =
new TestTransportConnectionWriter(out);
StreamContext ctx = new StreamContext(contactId, transportId,
secret, 0, true);
OutgoingSimplexConnection connection = new OutgoingSimplexConnection(db,
connRegistry, connWriterFactory, packetWriterFactory, ctx,
transport);
MessagingSession session = new SinglePassOutgoingSession(db, dbExecutor,
streamWriterFactory, packetWriterFactory,
ctx, writer);
final byte[] raw = new byte[1234];
context.checking(new Expectations() {{
// No transport acks to send
@@ -198,13 +170,10 @@ public class OutgoingSimplexConnectionTest extends BriarTestCase {
with(any(long.class)));
will(returnValue(null));
}});
connection.write();
session.run();
// Something should have been written
int overhead = TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH;
assertTrue(out.size() > overhead + UniqueId.LENGTH + raw.length);
// The transport should have been disposed with exception == false
assertTrue(transport.getDisposed());
assertFalse(transport.getException());
context.assertIsSatisfied();
}
}

View File

@@ -0,0 +1,35 @@
package org.briarproject.messaging;
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import java.io.InputStream;
import org.briarproject.api.plugins.TransportConnectionReader;
class TestTransportConnectionReader implements TransportConnectionReader {
private final InputStream in;
private boolean disposed = false;
TestTransportConnectionReader(InputStream in) {
this.in = in;
}
public int getMaxFrameLength() {
return MAX_FRAME_LENGTH;
}
public long getMaxLatency() {
return Long.MAX_VALUE;
}
public InputStream getInputStream() {
return in;
}
public void dispose(boolean exception, boolean recognised) {
assert !disposed;
disposed = true;
}
}

View File

@@ -0,0 +1,40 @@
package org.briarproject.messaging;
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import org.briarproject.api.plugins.TransportConnectionWriter;
class TestTransportConnectionWriter implements TransportConnectionWriter {
private final ByteArrayOutputStream out;
private boolean disposed = false;
TestTransportConnectionWriter(ByteArrayOutputStream out) {
this.out = out;
}
public long getCapacity() {
return Long.MAX_VALUE;
}
public int getMaxFrameLength() {
return MAX_FRAME_LENGTH;
}
public long getMaxLatency() {
return Long.MAX_VALUE;
}
public OutputStream getOutputStream() {
return out;
}
public void dispose(boolean exception) {
assert !disposed;
disposed = true;
}
}

View File

@@ -1,45 +0,0 @@
package org.briarproject.messaging.simplex;
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import java.io.InputStream;
import org.briarproject.api.plugins.simplex.SimplexTransportReader;
class TestSimplexTransportReader implements SimplexTransportReader {
private final InputStream in;
private boolean disposed = false, exception = false, recognised = false;
TestSimplexTransportReader(InputStream in) {
this.in = in;
}
public int getMaxFrameLength() {
return MAX_FRAME_LENGTH;
}
public InputStream getInputStream() {
return in;
}
public void dispose(boolean exception, boolean recognised) {
assert !disposed;
disposed = true;
this.exception = exception;
this.recognised = recognised;
}
boolean getDisposed() {
return disposed;
}
boolean getException() {
return exception;
}
boolean getRecognised() {
return recognised;
}
}

View File

@@ -1,53 +0,0 @@
package org.briarproject.messaging.simplex;
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import org.briarproject.api.plugins.simplex.SimplexTransportWriter;
class TestSimplexTransportWriter implements SimplexTransportWriter {
private final ByteArrayOutputStream out;
private final long capacity, maxLatency;
private boolean disposed = false, exception = false;
TestSimplexTransportWriter(ByteArrayOutputStream out, long capacity,
long maxLatency) {
this.out = out;
this.capacity = capacity;
this.maxLatency = maxLatency;
}
public long getCapacity() {
return capacity;
}
public int getMaxFrameLength() {
return MAX_FRAME_LENGTH;
}
public long getMaxLatency() {
return maxLatency;
}
public OutputStream getOutputStream() {
return out;
}
public void dispose(boolean exception) {
assert !disposed;
disposed = true;
this.exception = exception;
}
boolean getDisposed() {
return disposed;
}
boolean getException() {
return exception;
}
}

View File

@@ -7,6 +7,8 @@ import java.util.Scanner;
import org.briarproject.api.ContactId;
import org.briarproject.api.crypto.PseudoRandom;
import org.briarproject.api.plugins.TransportConnectionReader;
import org.briarproject.api.plugins.TransportConnectionWriter;
import org.briarproject.api.plugins.duplex.DuplexPlugin;
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
@@ -21,12 +23,14 @@ abstract class DuplexTest {
protected void sendChallengeReceiveResponse(DuplexTransportConnection d) {
assert plugin != null;
TransportConnectionReader r = d.getReader();
TransportConnectionWriter w = d.getWriter();
try {
PrintStream out = new PrintStream(d.getOutputStream());
PrintStream out = new PrintStream(w.getOutputStream());
out.println(CHALLENGE);
out.flush();
System.out.println("Sent challenge: " + CHALLENGE);
Scanner in = new Scanner(d.getInputStream());
Scanner in = new Scanner(r.getInputStream());
if(in.hasNextLine()) {
String response = in.nextLine();
System.out.println("Received response: " + response);
@@ -38,11 +42,13 @@ abstract class DuplexTest {
} else {
System.out.println("No response");
}
d.dispose(false, true);
r.dispose(false, true);
w.dispose(false);
} catch(IOException e) {
e.printStackTrace();
try {
d.dispose(true, true);
r.dispose(true, true);
w.dispose(true);
} catch(IOException e1) {
e1.printStackTrace();
}
@@ -51,13 +57,16 @@ abstract class DuplexTest {
protected void receiveChallengeSendResponse(DuplexTransportConnection d) {
assert plugin != null;
TransportConnectionReader r = d.getReader();
TransportConnectionWriter w = d.getWriter();
try {
Scanner in = new Scanner(d.getInputStream());
Scanner in = new Scanner(r.getInputStream());
if(in.hasNextLine()) {
String challenge = in.nextLine();
System.out.println("Received challenge: " + challenge);
if(CHALLENGE.equals(challenge)) {
PrintStream out = new PrintStream(d.getOutputStream());
PrintStream out = new PrintStream(w.getOutputStream());
out.println(RESPONSE);
out.flush();
System.out.println("Sent response: " + RESPONSE);
@@ -67,11 +76,13 @@ abstract class DuplexTest {
} else {
System.out.println("No challenge");
}
d.dispose(false, true);
r.dispose(false, true);
w.dispose(false);
} catch(IOException e) {
e.printStackTrace();
try {
d.dispose(true, true);
r.dispose(true, true);
w.dispose(true);
} catch(IOException e1) {
e1.printStackTrace();
}

View File

@@ -15,8 +15,8 @@ import org.briarproject.BriarTestCase;
import org.briarproject.TestFileUtils;
import org.briarproject.TestUtils;
import org.briarproject.api.ContactId;
import org.briarproject.api.plugins.TransportConnectionWriter;
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
import org.briarproject.api.plugins.simplex.SimplexTransportWriter;
import org.briarproject.api.system.FileUtils;
import org.briarproject.plugins.ImmediateExecutor;
import org.briarproject.plugins.file.RemovableDriveMonitor.Callback;
@@ -32,6 +32,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
private final ContactId contactId = new ContactId(234);
private final FileUtils fileUtils = new TestFileUtils();
@Override
@Before
public void setUp() {
testDir.mkdirs();
@@ -253,7 +254,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
fileUtils, callback, finder, monitor, MAX_FRAME_LENGTH, 0);
plugin.start();
SimplexTransportWriter writer = plugin.createWriter(contactId);
TransportConnectionWriter writer = plugin.createWriter(contactId);
assertNotNull(writer);
// The output file should exist and should be empty
File[] files = drive1.listFiles();
@@ -352,6 +353,7 @@ public class RemovableDrivePluginTest extends BriarTestCase {
context.assertIsSatisfied();
}
@Override
@After
public void tearDown() {
TestUtils.deleteTestDirectory(testDir);

View File

@@ -278,7 +278,8 @@ public class ModemPluginTest extends BriarTestCase {
public Object invoke(Invocation invocation) throws Throwable {
DuplexTransportConnection conn =
(DuplexTransportConnection) invocation.getParameter(1);
conn.dispose(false, true);
conn.getReader().dispose(false, true);
conn.getWriter().dispose(false);
invoked.countDown();
return null;
}

View File

@@ -148,7 +148,8 @@ public class LanTcpPluginTest extends BriarTestCase {
assertTrue(latch.await(5, SECONDS));
assertFalse(error.get());
// Clean up
d.dispose(false, true);
d.getReader().dispose(false, true);
d.getWriter().dispose(false);
ss.close();
plugin.stop();
}

View File

@@ -25,8 +25,6 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase {
// FIXME: This is an integration test, not a unit test
private static final int FRAME_LENGTH = 1024;
private static final int MAX_PAYLOAD_LENGTH =
FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH;
private final CryptoComponent crypto;
private final AuthenticatedCipher frameCipher;
@@ -56,7 +54,7 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase {
// Check that the actual tag and ciphertext match what's expected
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
10 * FRAME_LENGTH, frameCipher, frameKey, FRAME_LENGTH, tag);
frameCipher, frameKey, FRAME_LENGTH, tag);
o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], payloadLength, false);
byte[] actual = out.toByteArray();
assertEquals(TAG_LENGTH + FRAME_LENGTH, actual.length);
@@ -67,93 +65,14 @@ public class OutgoingEncryptionLayerTest extends BriarTestCase {
}
@Test
public void testInitiatorClosesConnectionWithoutWriting() throws Exception {
public void testCloseConnectionWithoutWriting() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Initiator's constructor
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
FRAME_LENGTH, tag);
frameCipher, crypto.generateSecretKey(), FRAME_LENGTH, tag);
// Write an empty final frame without having written any other frames
o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], 0, true);
// The tag and the empty frame should be written to the output stream
assertEquals(TAG_LENGTH + HEADER_LENGTH + MAC_LENGTH, out.size());
}
@Test
public void testResponderClosesConnectionWithoutWriting() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Responder's constructor
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
FRAME_LENGTH);
// Write an empty final frame without having written any other frames
o.writeFrame(new byte[FRAME_LENGTH - MAC_LENGTH], 0, true);
// An empty final frame should be written to the output stream
assertEquals(HEADER_LENGTH + MAC_LENGTH, out.size());
}
@Test
public void testRemainingCapacityWithTag() throws Exception {
int MAX_PAYLOAD_LENGTH = FRAME_LENGTH - HEADER_LENGTH - MAC_LENGTH;
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Initiator's constructor
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
FRAME_LENGTH, tag);
// There should be space for nine full frames and one partial frame
byte[] frame = new byte[FRAME_LENGTH - MAC_LENGTH];
assertEquals(10 * MAX_PAYLOAD_LENGTH - TAG_LENGTH,
o.getRemainingCapacity());
// Write nine frames, each containing a partial payload
for(int i = 0; i < 9; i++) {
o.writeFrame(frame, 123, false);
assertEquals((9 - i) * MAX_PAYLOAD_LENGTH - TAG_LENGTH,
o.getRemainingCapacity());
}
// Write the final frame, which will not be padded
o.writeFrame(frame, 123, true);
int finalFrameLength = HEADER_LENGTH + 123 + MAC_LENGTH;
assertEquals(MAX_PAYLOAD_LENGTH - TAG_LENGTH - finalFrameLength,
o.getRemainingCapacity());
}
@Test
public void testRemainingCapacityWithoutTag() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// Responder's constructor
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
10 * FRAME_LENGTH, frameCipher, crypto.generateSecretKey(),
FRAME_LENGTH);
// There should be space for ten full frames
assertEquals(10 * MAX_PAYLOAD_LENGTH, o.getRemainingCapacity());
// Write nine frames, each containing a partial payload
byte[] frame = new byte[FRAME_LENGTH - MAC_LENGTH];
for(int i = 0; i < 9; i++) {
o.writeFrame(frame, 123, false);
assertEquals((9 - i) * MAX_PAYLOAD_LENGTH,
o.getRemainingCapacity());
}
// Write the final frame, which will not be padded
o.writeFrame(frame, 123, true);
int finalFrameLength = HEADER_LENGTH + 123 + MAC_LENGTH;
assertEquals(MAX_PAYLOAD_LENGTH - finalFrameLength,
o.getRemainingCapacity());
}
@Test
public void testRemainingCapacityLimitedByFrameNumbers() throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
// The connection has plenty of space so we're limited by frame numbers
OutgoingEncryptionLayer o = new OutgoingEncryptionLayer(out,
Long.MAX_VALUE, frameCipher, crypto.generateSecretKey(),
FRAME_LENGTH);
// There should be enough frame numbers for 2^32 frames
assertEquals((1L << 32) * MAX_PAYLOAD_LENGTH, o.getRemainingCapacity());
// Write a frame containing a partial payload
byte[] frame = new byte[FRAME_LENGTH - MAC_LENGTH];
o.writeFrame(frame, 123, false);
// There should be enough frame numbers for 2^32 - 1 frames
assertEquals(((1L << 32) - 1) * MAX_PAYLOAD_LENGTH,
o.getRemainingCapacity());
}
}

View File

@@ -1,12 +1,11 @@
package org.briarproject.transport;
import static org.briarproject.api.messaging.MessagingConstants.MAX_PACKET_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MAX_FRAME_LENGTH;
import static org.briarproject.api.transport.TransportConstants.MIN_STREAM_LENGTH;
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
import static org.junit.Assert.assertArrayEquals;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Random;
@@ -14,13 +13,9 @@ import java.util.Random;
import org.briarproject.BriarTestCase;
import org.briarproject.TestLifecycleModule;
import org.briarproject.TestSystemModule;
import org.briarproject.api.ContactId;
import org.briarproject.api.TransportId;
import org.briarproject.api.crypto.AuthenticatedCipher;
import org.briarproject.api.crypto.CryptoComponent;
import org.briarproject.api.crypto.SecretKey;
import org.briarproject.api.transport.StreamContext;
import org.briarproject.api.transport.StreamWriter;
import org.briarproject.api.transport.StreamWriterFactory;
import org.briarproject.crypto.CryptoModule;
import org.junit.Test;
@@ -35,13 +30,10 @@ public class TransportIntegrationTest extends BriarTestCase {
private final int FRAME_LENGTH = 2048;
private final CryptoComponent crypto;
private final StreamWriterFactory streamWriterFactory;
private final ContactId contactId;
private final TransportId transportId;
private final AuthenticatedCipher frameCipher;
private final Random random;
private final byte[] secret;
private final SecretKey frameKey;
private final SecretKey tagKey, frameKey;
public TransportIntegrationTest() {
Module testModule = new AbstractModule() {
@@ -54,15 +46,13 @@ public class TransportIntegrationTest extends BriarTestCase {
Injector i = Guice.createInjector(testModule, new CryptoModule(),
new TestLifecycleModule(), new TestSystemModule());
crypto = i.getInstance(CryptoComponent.class);
streamWriterFactory = i.getInstance(StreamWriterFactory.class);
contactId = new ContactId(234);
transportId = new TransportId("id");
frameCipher = crypto.getFrameCipher();
random = new Random();
// Since we're sending frames to ourselves, we only need outgoing keys
secret = new byte[32];
random.nextBytes(secret);
frameKey = crypto.deriveFrameKey(secret, 0, true, true);
tagKey = crypto.deriveTagKey(secret, true);
frameKey = crypto.deriveFrameKey(secret, 0, true);
}
@Test
@@ -76,6 +66,9 @@ public class TransportIntegrationTest extends BriarTestCase {
}
private void testWriteAndRead(boolean initiator) throws Exception {
// Encode the tag
byte[] tag = new byte[TAG_LENGTH];
crypto.encodeTag(tag, tagKey, 0);
// Generate two random frames
byte[] frame = new byte[1234];
random.nextBytes(frame);
@@ -83,87 +76,46 @@ public class TransportIntegrationTest extends BriarTestCase {
random.nextBytes(frame1);
// Copy the frame key - the copy will be erased
SecretKey frameCopy = frameKey.copy();
// Write the frames
// Write the tag and the frames
ByteArrayOutputStream out = new ByteArrayOutputStream();
FrameWriter encryptionOut = new OutgoingEncryptionLayer(out,
Long.MAX_VALUE, frameCipher, frameCopy, FRAME_LENGTH);
StreamWriterImpl writer = new StreamWriterImpl(encryptionOut,
FrameWriter frameWriter = new OutgoingEncryptionLayer(out,
frameCipher, frameCopy, FRAME_LENGTH, tag);
StreamWriterImpl streamWriter = new StreamWriterImpl(frameWriter,
FRAME_LENGTH);
OutputStream out1 = writer.getOutputStream();
OutputStream out1 = streamWriter.getOutputStream();
out1.write(frame);
out1.flush();
out1.write(frame1);
out1.flush();
byte[] output = out.toByteArray();
assertEquals(FRAME_LENGTH * 2, output.length);
// Read the tag and the frames back
assertEquals(TAG_LENGTH + FRAME_LENGTH * 2, output.length);
// Read the tag back
ByteArrayInputStream in = new ByteArrayInputStream(output);
FrameReader encryptionIn = new IncomingEncryptionLayer(in, frameCipher,
byte[] recoveredTag = new byte[tag.length];
read(in, recoveredTag);
assertArrayEquals(tag, recoveredTag);
// Read the frames back
FrameReader frameReader = new IncomingEncryptionLayer(in, frameCipher,
frameKey, FRAME_LENGTH);
StreamReaderImpl reader = new StreamReaderImpl(encryptionIn,
StreamReaderImpl streamReader = new StreamReaderImpl(frameReader,
FRAME_LENGTH);
InputStream in1 = reader.getInputStream();
byte[] recovered = new byte[frame.length];
InputStream in1 = streamReader.getInputStream();
byte[] recoveredFrame = new byte[frame.length];
read(in1, recoveredFrame);
assertArrayEquals(frame, recoveredFrame);
byte[] recoveredFrame1 = new byte[frame1.length];
read(in1, recoveredFrame1);
assertArrayEquals(frame1, recoveredFrame1);
streamWriter.close();
streamReader.close();
}
private void read(InputStream in, byte[] dest) throws IOException {
int offset = 0;
while(offset < recovered.length) {
int read = in1.read(recovered, offset, recovered.length - offset);
while(offset < dest.length) {
int read = in.read(dest, offset, dest.length - offset);
if(read == -1) break;
offset += read;
}
assertEquals(recovered.length, offset);
assertArrayEquals(frame, recovered);
byte[] recovered1 = new byte[frame1.length];
offset = 0;
while(offset < recovered1.length) {
int read = in1.read(recovered1, offset, recovered1.length - offset);
if(read == -1) break;
offset += read;
}
assertEquals(recovered1.length, offset);
assertArrayEquals(frame1, recovered1);
writer.close();
reader.close();
}
@Test
public void testOverheadWithTag() throws Exception {
ByteArrayOutputStream out =
new ByteArrayOutputStream(MIN_STREAM_LENGTH);
StreamContext ctx = new StreamContext(contactId, transportId,
secret, 0, true);
StreamWriter w = streamWriterFactory.createStreamWriter(out,
MAX_FRAME_LENGTH, MIN_STREAM_LENGTH, ctx, false, true);
// Check that the connection writer thinks there's room for a packet
long capacity = w.getRemainingCapacity();
assertTrue(capacity > MAX_PACKET_LENGTH);
assertTrue(capacity < MIN_STREAM_LENGTH);
// Check that there really is room for a packet
byte[] payload = new byte[MAX_PACKET_LENGTH];
w.getOutputStream().write(payload);
w.getOutputStream().close();
long used = out.size();
assertTrue(used > MAX_PACKET_LENGTH);
assertTrue(used <= MIN_STREAM_LENGTH);
}
@Test
public void testOverheadWithoutTag() throws Exception {
ByteArrayOutputStream out =
new ByteArrayOutputStream(MIN_STREAM_LENGTH);
StreamContext ctx = new StreamContext(contactId, transportId,
secret, 0, true);
StreamWriter w = streamWriterFactory.createStreamWriter(out,
MAX_FRAME_LENGTH, MIN_STREAM_LENGTH, ctx, false, false);
// Check that the connection writer thinks there's room for a packet
long capacity = w.getRemainingCapacity();
assertTrue(capacity > MAX_PACKET_LENGTH);
assertTrue(capacity < MIN_STREAM_LENGTH);
// Check that there really is room for a packet
byte[] payload = new byte[MAX_PACKET_LENGTH];
w.getOutputStream().write(payload);
w.getOutputStream().close();
long used = out.size();
assertTrue(used > MAX_PACKET_LENGTH);
assertTrue(used <= MIN_STREAM_LENGTH);
}
}