diff --git a/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingComponent.java b/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingComponent.java index 1d0a7d70f348b403f8c5712a265385ae706a3483..ea5ae968972378d332fd4f1b062ac72f8e277cff 100644 --- a/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingComponent.java @@ -1,6 +1,7 @@ package org.briarproject.sync; import org.briarproject.TestDatabaseModule; +import org.briarproject.TestPluginsModule; import org.briarproject.TestSystemModule; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.db.DatabaseComponent; @@ -23,6 +24,7 @@ import org.briarproject.event.EventModule; import org.briarproject.identity.IdentityModule; import org.briarproject.lifecycle.LifecycleModule; import org.briarproject.messaging.MessagingModule; +import org.briarproject.plugins.PluginsModule; import org.briarproject.transport.TransportModule; import javax.inject.Singleton; @@ -30,23 +32,37 @@ import javax.inject.Singleton; import dagger.Component; @Singleton -@Component(modules = {TestDatabaseModule.class, TestSystemModule.class, - LifecycleModule.class, ContactModule.class, CryptoModule.class, - DatabaseModule.class, EventModule.class, SyncModule.class, - DataModule.class, TransportModule.class, IdentityModule.class, - MessagingModule.class, ClientsModule.class}) +@Component(modules = {TestDatabaseModule.class, TestPluginsModule.class, + TestSystemModule.class, LifecycleModule.class, ContactModule.class, + CryptoModule.class, DatabaseModule.class, EventModule.class, + SyncModule.class, DataModule.class, TransportModule.class, + IdentityModule.class, MessagingModule.class, ClientsModule.class, + PluginsModule.class}) public interface SimplexMessagingComponent { + void inject(SimplexMessagingIntegrationTest testCase); - LifecycleManager getLifeCycleManager(); + + LifecycleManager getLifecycleManager(); + DatabaseComponent getDatabaseComponent(); + IdentityManager getIdentityManager(); + ContactManager getContactManager(); + MessagingManager getMessagingManager(); + KeyManager getKeyManager(); + PrivateMessageFactory getPrivateMessageFactory(); + PacketWriterFactory getPacketWriterFactory(); + EventBus getEventBus(); + StreamWriterFactory getStreamWriterFactory(); + StreamReaderFactory getStreamReaderFactory(); + PacketReaderFactory getPacketReaderFactory(); } diff --git a/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingIntegrationTest.java index 9ad9df0f2832ef25573aacb2b6e3c5158b9a3ed4..01f615511151b54caac2c6770873708ed38f6208 100644 --- a/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingIntegrationTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/sync/SimplexMessagingIntegrationTest.java @@ -4,12 +4,10 @@ import org.briarproject.BriarTestCase; import org.briarproject.ImmediateExecutor; import org.briarproject.TestDatabaseModule; import org.briarproject.TestUtils; -import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.db.DatabaseComponent; -import org.briarproject.api.db.Transaction; import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; @@ -36,27 +34,26 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; -import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; -import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.io.OutputStream; -public class SimplexMessagingIntegrationTest extends BriarTestCase { +import static org.briarproject.TestPluginsModule.MAX_LATENCY; +import static org.briarproject.TestPluginsModule.TRANSPORT_ID; +import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; +import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; - private static final int MAX_LATENCY = 2 * 60 * 1000; // 2 minutes +public class SimplexMessagingIntegrationTest extends BriarTestCase { private final File testDir = TestUtils.getTestDirectory(); private final File aliceDir = new File(testDir, "alice"); private final File bobDir = new File(testDir, "bob"); - private final TransportId transportId = new TransportId("id"); private final SecretKey master = TestUtils.createSecretKey(); private final long timestamp = System.currentTimeMillis(); private final AuthorId aliceId = new AuthorId(TestUtils.getRandomId()); @@ -80,7 +77,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { private byte[] write() throws Exception { // Instantiate Alice's services - LifecycleManager lifecycleManager = alice.getLifeCycleManager(); + LifecycleManager lifecycleManager = alice.getLifecycleManager(); DatabaseComponent db = alice.getDatabaseComponent(); IdentityManager identityManager = alice.getIdentityManager(); ContactManager contactManager = alice.getContactManager(); @@ -97,14 +94,6 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Start the lifecycle manager lifecycleManager.startServices(); lifecycleManager.waitForStartup(); - // Add a transport - Transaction txn = db.startTransaction(); - try { - db.addTransport(txn, transportId, MAX_LATENCY); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } // Add an identity for Alice LocalAuthor aliceAuthor = new LocalAuthor(aliceId, "Alice", new byte[MAX_PUBLIC_KEY_LENGTH], new byte[123], timestamp); @@ -122,7 +111,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { groupId, timestamp, null, "text/plain", body); messagingManager.addLocalMessage(message); // Get a stream context - StreamContext ctx = keyManager.getStreamContext(contactId, transportId); + StreamContext ctx = keyManager.getStreamContext(contactId, + TRANSPORT_ID); assertNotNull(ctx); // Create a stream writer ByteArrayOutputStream out = new ByteArrayOutputStream(); @@ -132,8 +122,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { PacketWriter packetWriter = packetWriterFactory.createPacketWriter( streamWriter); SyncSession session = new SimplexOutgoingSession(db, - new ImmediateExecutor(), eventBus, contactId, transportId, - MAX_LATENCY, packetWriter); + new ImmediateExecutor(), eventBus, contactId, MAX_LATENCY, + packetWriter); // Write whatever needs to be written session.run(); streamWriter.close(); @@ -148,7 +138,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { private void read(byte[] stream) throws Exception { // Instantiate Bob's services - LifecycleManager lifecycleManager = bob.getLifeCycleManager(); + LifecycleManager lifecycleManager = bob.getLifecycleManager(); DatabaseComponent db = bob.getDatabaseComponent(); IdentityManager identityManager = bob.getIdentityManager(); ContactManager contactManager = bob.getContactManager(); @@ -162,14 +152,6 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Start the lifecyle manager lifecycleManager.startServices(); lifecycleManager.waitForStartup(); - // Add a transport - Transaction txn = db.startTransaction(); - try { - db.addTransport(txn, transportId, MAX_LATENCY); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } // Add an identity for Bob LocalAuthor bobAuthor = new LocalAuthor(bobId, "Bob", new byte[MAX_PUBLIC_KEY_LENGTH], new byte[123], timestamp); @@ -188,7 +170,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { byte[] tag = new byte[TAG_LENGTH]; int read = in.read(tag); assertEquals(tag.length, read); - StreamContext ctx = keyManager.getStreamContext(transportId, tag); + StreamContext ctx = keyManager.getStreamContext(TRANSPORT_ID, tag); assertNotNull(ctx); // Create a stream reader InputStream streamReader = streamReaderFactory.createStreamReader( @@ -197,7 +179,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { PacketReader packetReader = packetReaderFactory.createPacketReader( streamReader); SyncSession session = new IncomingSession(db, new ImmediateExecutor(), - eventBus, contactId, transportId, packetReader); + eventBus, contactId, packetReader); // No messages should have been added yet assertFalse(listener.messageAdded); // Read whatever needs to be read diff --git a/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java b/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java index 7718122f011489613a21bba5d61a3717aace09f7..feccd77ff41d90df68d1e644826213798da9024d 100644 --- a/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java +++ b/briar-android/src/org/briarproject/plugins/AndroidPluginsModule.java @@ -7,9 +7,8 @@ import org.briarproject.android.api.AndroidExecutor; import org.briarproject.api.event.EventBus; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.plugins.BackoffFactory; -import org.briarproject.api.plugins.duplex.DuplexPluginConfig; +import org.briarproject.api.plugins.PluginConfig; import org.briarproject.api.plugins.duplex.DuplexPluginFactory; -import org.briarproject.api.plugins.simplex.SimplexPluginConfig; import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.system.LocationUtils; import org.briarproject.plugins.droidtooth.DroidtoothPluginFactory; @@ -29,17 +28,8 @@ import dagger.Provides; public class AndroidPluginsModule { @Provides - SimplexPluginConfig provideSimplexPluginConfig() { - return new SimplexPluginConfig() { - public Collection<SimplexPluginFactory> getFactories() { - return Collections.emptyList(); - } - }; - } - - @Provides - public DuplexPluginConfig provideDuplexPluginConfig( - @IoExecutor Executor ioExecutor, AndroidExecutor androidExecutor, + public PluginConfig providePluginConfig(@IoExecutor Executor ioExecutor, + AndroidExecutor androidExecutor, SecureRandom random, BackoffFactory backoffFactory, Application app, LocationUtils locationUtils, EventBus eventBus) { Context appContext = app.getApplicationContext(); @@ -49,13 +39,19 @@ public class AndroidPluginsModule { locationUtils, eventBus); DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor, backoffFactory, appContext); - final Collection<DuplexPluginFactory> factories = + final Collection<DuplexPluginFactory> duplex = Arrays.asList(bluetooth, tor, lan); - return new DuplexPluginConfig() { - public Collection<DuplexPluginFactory> getFactories() { - return factories; + return new PluginConfig() { + + @Override + public Collection<DuplexPluginFactory> getDuplexFactories() { + return duplex; + } + + @Override + public Collection<SimplexPluginFactory> getSimplexFactories() { + return Collections.emptyList(); } }; } - } diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java index 229aba22722481cbb67b91e49a1aa6fcd3c66d39..ee7acf26ba47c4fb39128f3eede571189c39e4f7 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothPluginFactory.java @@ -2,8 +2,8 @@ package org.briarproject.plugins.droidtooth; import android.content.Context; -import org.briarproject.api.TransportId; import org.briarproject.android.api.AndroidExecutor; +import org.briarproject.api.TransportId; import org.briarproject.api.plugins.Backoff; import org.briarproject.api.plugins.BackoffFactory; import org.briarproject.api.plugins.duplex.DuplexPlugin; @@ -40,6 +40,10 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory { return DroidtoothPlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); diff --git a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java index dfb5b41f31e892a5d351f590e082b8591d79c761..e4db5673d219c82a65e44105c7e8f8f945a544fe 100644 --- a/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/droidtooth/DroidtoothTransportConnection.java @@ -1,16 +1,16 @@ package org.briarproject.plugins.droidtooth; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.concurrent.atomic.AtomicBoolean; +import android.bluetooth.BluetoothSocket; import org.briarproject.api.plugins.Plugin; import org.briarproject.api.plugins.TransportConnectionReader; import org.briarproject.api.plugins.TransportConnectionWriter; import org.briarproject.api.plugins.duplex.DuplexTransportConnection; -import android.bluetooth.BluetoothSocket; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.concurrent.atomic.AtomicBoolean; class DroidtoothTransportConnection implements DuplexTransportConnection { @@ -39,10 +39,6 @@ class DroidtoothTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public long getMaxLatency() { - return plugin.getMaxLatency(); - } - public InputStream getInputStream() throws IOException { return socket.getInputStream(); } diff --git a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java index 0813ebfdd71dc460f9038f20ff314dcc749f50fd..16d456ad3b22e47a2e128e45afd55705dccba3dc 100644 --- a/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tcp/AndroidLanTcpPluginFactory.java @@ -34,6 +34,10 @@ public class AndroidLanTcpPluginFactory implements DuplexPluginFactory { return LanTcpPlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); diff --git a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java index 3c6a749867b89366a086e6dfddf518e4337a76df..836dd48b61ff0aace079062dd32024d899762307 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorPluginFactory.java @@ -44,6 +44,10 @@ public class TorPluginFactory implements DuplexPluginFactory { return TorPlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { // Check that we have a Tor binary for this architecture diff --git a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java index a847bc912377c23cb44b3bdd0101650826695213..f6d806c880f8c859704a10ad0b71b5f7a13b32a6 100644 --- a/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java +++ b/briar-android/src/org/briarproject/plugins/tor/TorTransportConnection.java @@ -1,16 +1,16 @@ package org.briarproject.plugins.tor; +import org.briarproject.api.plugins.Plugin; +import org.briarproject.api.plugins.TransportConnectionReader; +import org.briarproject.api.plugins.TransportConnectionWriter; +import org.briarproject.api.plugins.duplex.DuplexTransportConnection; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.concurrent.atomic.AtomicBoolean; -import org.briarproject.api.plugins.Plugin; -import org.briarproject.api.plugins.TransportConnectionReader; -import org.briarproject.api.plugins.TransportConnectionWriter; -import org.briarproject.api.plugins.duplex.DuplexTransportConnection; - class TorTransportConnection implements DuplexTransportConnection { private final Plugin plugin; @@ -38,10 +38,6 @@ class TorTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public long getMaxLatency() { - return plugin.getMaxLatency(); - } - public InputStream getInputStream() throws IOException { return socket.getInputStream(); } diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java index 08bc9692f9a9f9d77f3d2dbe4724c7d1a539c35a..2292bc0ba258a674251de8cdb5b6ebee64750251 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java @@ -26,10 +26,6 @@ import java.util.Map; /** * Encapsulates the database implementation and exposes high-level operations * to other components. - * <p/> - * This interface's methods are blocking, but they do not call out into other - * components except to broadcast {@link org.briarproject.api.event.Event - * Events}, so they can safely be called while holding locks. */ public interface DatabaseComponent { @@ -45,8 +41,12 @@ public interface DatabaseComponent { /** * Starts a new transaction and returns an object representing it. + * <p/> + * This method acquires locks, so it must not be called while holding a + * lock. + * @param readOnly true if the transaction will only be used for reading. */ - Transaction startTransaction() throws DbException; + Transaction startTransaction(boolean readOnly) throws DbException; /** * Ends a transaction. If the transaction is marked as complete, the @@ -142,70 +142,97 @@ public interface DatabaseComponent { /** * Returns the contact with the given ID. + * <p/> + * Read-only. */ Contact getContact(Transaction txn, ContactId c) throws DbException; /** * Returns all contacts. + * <p/> + * Read-only. */ Collection<Contact> getContacts(Transaction txn) throws DbException; /** * Returns all contacts associated with the given local pseudonym. + * <p/> + * Read-only. */ Collection<ContactId> getContacts(Transaction txn, AuthorId a) throws DbException; /** * Returns the unique ID for this device. + * <p/> + * Read-only. */ DeviceId getDeviceId(Transaction txn) throws DbException; /** * Returns the group with the given ID. + * <p/> + * Read-only. */ Group getGroup(Transaction txn, GroupId g) throws DbException; /** * Returns the metadata for the given group. + * <p/> + * Read-only. */ Metadata getGroupMetadata(Transaction txn, GroupId g) throws DbException; /** * Returns all groups belonging to the given client. + * <p/> + * Read-only. */ Collection<Group> getGroups(Transaction txn, ClientId c) throws DbException; /** * Returns the local pseudonym with the given ID. + * <p/> + * Read-only. */ LocalAuthor getLocalAuthor(Transaction txn, AuthorId a) throws DbException; /** * Returns all local pseudonyms. + * <p/> + * Read-only. */ Collection<LocalAuthor> getLocalAuthors(Transaction txn) throws DbException; /** * Returns the IDs of any messages that need to be validated by the given * client. + * <p/> + * Read-only. */ Collection<MessageId> getMessagesToValidate(Transaction txn, ClientId c) throws DbException; /** - * Returns the message with the given ID, in serialised form. + * Returns the message with the given ID, in serialised form, or null if + * the message has been deleted. + * <p/> + * Read-only. */ byte[] getRawMessage(Transaction txn, MessageId m) throws DbException; /** * Returns the metadata for all messages in the given group. + * <p/> + * Read-only. */ Map<MessageId, Metadata> getMessageMetadata(Transaction txn, GroupId g) throws DbException; /** * Returns the metadata for the given message. + * <p/> + * Read-only. */ Metadata getMessageMetadata(Transaction txn, MessageId m) throws DbException; @@ -213,6 +240,8 @@ public interface DatabaseComponent { /** * Returns the status of all messages in the given group with respect to * the given contact. + * <p/> + * Read-only. */ Collection<MessageStatus> getMessageStatus(Transaction txn, ContactId c, GroupId g) throws DbException; @@ -220,27 +249,27 @@ public interface DatabaseComponent { /** * Returns the status of the given message with respect to the given * contact. + * <p/> + * Read-only. */ MessageStatus getMessageStatus(Transaction txn, ContactId c, MessageId m) throws DbException; /** * Returns all settings in the given namespace. + * <p/> + * Read-only. */ Settings getSettings(Transaction txn, String namespace) throws DbException; /** * Returns all transport keys for the given transport. + * <p/> + * Read-only. */ Map<ContactId, TransportKeys> getTransportKeys(Transaction txn, TransportId t) throws DbException; - /** - * Returns the maximum latencies in milliseconds of all transports. - */ - Map<TransportId, Integer> getTransportLatencies(Transaction txn) - throws DbException; - /** * Increments the outgoing stream counter for the given contact and * transport in the given rotation period . @@ -250,6 +279,8 @@ public interface DatabaseComponent { /** * Returns true if the given group is visible to the given contact. + * <p/> + * Read-only. */ boolean isVisibleToContact(Transaction txn, ContactId c, GroupId g) throws DbException; diff --git a/briar-api/src/org/briarproject/api/db/Transaction.java b/briar-api/src/org/briarproject/api/db/Transaction.java index cb89f142ca3461582180f53f9ffb9e557e0cdc64..15297a5734cc0524345c679835f1212e7e029f86 100644 --- a/briar-api/src/org/briarproject/api/db/Transaction.java +++ b/briar-api/src/org/briarproject/api/db/Transaction.java @@ -12,12 +12,14 @@ import java.util.List; public class Transaction { private final Object txn; + private final boolean readOnly; private List<Event> events = null; private boolean complete = false; - public Transaction(Object txn) { + public Transaction(Object txn, boolean readOnly) { this.txn = txn; + this.readOnly = readOnly; } /** @@ -28,6 +30,13 @@ public class Transaction { return txn; } + /** + * Returns true if the transaction can only be used for reading. + */ + public boolean isReadOnly() { + return readOnly; + } + /** * Attaches an event to be broadcast when the transaction has been * committed. diff --git a/briar-api/src/org/briarproject/api/event/TransportAddedEvent.java b/briar-api/src/org/briarproject/api/event/TransportAddedEvent.java deleted file mode 100644 index b775ce6c9e5dd88c112f6821fe157b4a0e68d853..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/event/TransportAddedEvent.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.briarproject.api.event; - -import org.briarproject.api.TransportId; - -/** An event that is broadcast when a transport is added. */ -public class TransportAddedEvent extends Event { - - private final TransportId transportId; - private final int maxLatency; - - public TransportAddedEvent(TransportId transportId, int maxLatency) { - this.transportId = transportId; - this.maxLatency = maxLatency; - } - - public TransportId getTransportId() { - return transportId; - } - - public int getMaxLatency() { - return maxLatency; - } -} diff --git a/briar-api/src/org/briarproject/api/event/TransportRemovedEvent.java b/briar-api/src/org/briarproject/api/event/TransportRemovedEvent.java deleted file mode 100644 index a0162d595e6a9705a5d8d4c03ee141cad4642284..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/event/TransportRemovedEvent.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.briarproject.api.event; - -import org.briarproject.api.TransportId; - -/** An event that is broadcast when a transport is removed. */ -public class TransportRemovedEvent extends Event { - - private final TransportId transportId; - - public TransportRemovedEvent(TransportId transportId) { - this.transportId = transportId; - } - - public TransportId getTransportId() { - return transportId; - } -} diff --git a/briar-api/src/org/briarproject/api/plugins/PluginConfig.java b/briar-api/src/org/briarproject/api/plugins/PluginConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..7fda14476e8b3c900d1755e1bf948a5420fce46b --- /dev/null +++ b/briar-api/src/org/briarproject/api/plugins/PluginConfig.java @@ -0,0 +1,13 @@ +package org.briarproject.api.plugins; + +import org.briarproject.api.plugins.duplex.DuplexPluginFactory; +import org.briarproject.api.plugins.simplex.SimplexPluginFactory; + +import java.util.Collection; + +public interface PluginConfig { + + Collection<DuplexPluginFactory> getDuplexFactories(); + + Collection<SimplexPluginFactory> getSimplexFactories(); +} diff --git a/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java b/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java index e071c4432b0b8d5eeccd0f014294b25281ed262a..e2b2855dea9bec5c5a764946f59c8ccbc256bd2f 100644 --- a/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java +++ b/briar-api/src/org/briarproject/api/plugins/TransportConnectionReader.java @@ -9,10 +9,9 @@ import java.io.InputStream; */ public interface TransportConnectionReader { - /** Returns the maximum latency of the transport in milliseconds. */ - long getMaxLatency(); - - /** Returns an input stream for reading from the transport connection. */ + /** + * Returns an input stream for reading from the transport connection. + */ InputStream getInputStream() throws IOException; /** @@ -20,10 +19,13 @@ public interface TransportConnectionReader { * simplex, the connection is closed. If the transport is duplex, the * connection is closed if <tt>exception</tt> is true or the other side of * the connection has been marked as closed. - * @param exception true if the connection is being closed because of an - * exception. This may affect how resources are disposed of. + * + * @param exception true if the connection is being closed because of an + * exception. This may affect how resources are disposed + * of. * @param recognised true if the connection is definitely a Briar transport - * connection. This may affect how resources are disposed of. + * connection. This may affect how resources are disposed + * of. */ void dispose(boolean exception, boolean recognised) throws IOException; } diff --git a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPluginConfig.java b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPluginConfig.java deleted file mode 100644 index fc17637196d37fbf7e489dfeb8a4f2a3716c65fa..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPluginConfig.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.briarproject.api.plugins.duplex; - -import java.util.Collection; - -public interface DuplexPluginConfig { - - Collection<DuplexPluginFactory> getFactories(); -} diff --git a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPluginFactory.java b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPluginFactory.java index 9e8cf7021759764dc4125e17e7f0b7e475b507fe..914402e3ca8f5666ee428a267bc2487d4260102a 100644 --- a/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPluginFactory.java +++ b/briar-api/src/org/briarproject/api/plugins/duplex/DuplexPluginFactory.java @@ -2,12 +2,23 @@ package org.briarproject.api.plugins.duplex; import org.briarproject.api.TransportId; -/** Factory for creating a plugin for a duplex transport. */ +/** + * Factory for creating a plugin for a duplex transport. + */ public interface DuplexPluginFactory { - /** Returns the plugin's transport identifier. */ + /** + * Returns the plugin's transport identifier. + */ TransportId getId(); - /** Creates and returns a plugin, or null if no plugin can be created. */ + /** + * Returns the maximum latency of the transport in milliseconds. + */ + int getMaxLatency(); + + /** + * Creates and returns a plugin, or null if no plugin can be created. + */ DuplexPlugin createPlugin(DuplexPluginCallback callback); } diff --git a/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPluginConfig.java b/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPluginConfig.java deleted file mode 100644 index 59f4f6a079be3605d613dcf81bbcf671d5e75083..0000000000000000000000000000000000000000 --- a/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPluginConfig.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.briarproject.api.plugins.simplex; - -import java.util.Collection; - -public interface SimplexPluginConfig { - - Collection<SimplexPluginFactory> getFactories(); -} diff --git a/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPluginFactory.java b/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPluginFactory.java index bc5c955a52114a8ba732751b2ad8a0cf126c5586..38277550abfdc61311b68ac1e7975e0a6aff748d 100644 --- a/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPluginFactory.java +++ b/briar-api/src/org/briarproject/api/plugins/simplex/SimplexPluginFactory.java @@ -2,12 +2,23 @@ package org.briarproject.api.plugins.simplex; import org.briarproject.api.TransportId; -/** Factory for creating a plugin for a simplex transport. */ +/** + * Factory for creating a plugin for a simplex transport. + */ public interface SimplexPluginFactory { - /** Returns the plugin's transport identifier. */ + /** + * Returns the plugin's transport identifier. + */ TransportId getId(); - /** Creates and returns a plugin, or null if no plugin can be created. */ + /** + * Returns the maximum latency of the transport in milliseconds. + */ + int getMaxLatency(); + + /** + * Creates and returns a plugin, or null if no plugin can be created. + */ SimplexPlugin createPlugin(SimplexPluginCallback callback); } diff --git a/briar-api/src/org/briarproject/api/sync/SyncSessionFactory.java b/briar-api/src/org/briarproject/api/sync/SyncSessionFactory.java index b5db6a3493e9beba4af9ffcb9130325888de1c61..db5954ffedff642501d50301273972fc01521dd8 100644 --- a/briar-api/src/org/briarproject/api/sync/SyncSessionFactory.java +++ b/briar-api/src/org/briarproject/api/sync/SyncSessionFactory.java @@ -1,6 +1,5 @@ package org.briarproject.api.sync; -import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import java.io.InputStream; @@ -8,12 +7,11 @@ import java.io.OutputStream; public interface SyncSessionFactory { - SyncSession createIncomingSession(ContactId c, TransportId t, - InputStream in); + SyncSession createIncomingSession(ContactId c, InputStream in); - SyncSession createSimplexOutgoingSession(ContactId c, TransportId t, - int maxLatency, OutputStream out); + SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency, + OutputStream out); - SyncSession createDuplexOutgoingSession(ContactId c, TransportId t, - int maxLatency, int maxIdleTime, OutputStream out); + SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency, + int maxIdleTime, OutputStream out); } diff --git a/briar-api/src/org/briarproject/api/transport/KeyManager.java b/briar-api/src/org/briarproject/api/transport/KeyManager.java index 7cfd4d1eb98f1d978b68b330c8d66eac2f7d125d..8ee0578a860ab84eedde2a456d38822c3ee9338a 100644 --- a/briar-api/src/org/briarproject/api/transport/KeyManager.java +++ b/briar-api/src/org/briarproject/api/transport/KeyManager.java @@ -26,12 +26,14 @@ public interface KeyManager { * contact over the given transport, or null if an error occurs or the * contact does not support the transport. */ - StreamContext getStreamContext(ContactId c, TransportId t); + StreamContext getStreamContext(ContactId c, TransportId t) + throws DbException; /** * Looks up the given tag and returns a {@link StreamContext} for reading * from the corresponding stream, or null if an error occurs or the tag was * unexpected. */ - StreamContext getStreamContext(TransportId t, byte[] tag); + StreamContext getStreamContext(TransportId t, byte[] tag) + throws DbException; } diff --git a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java index 40640c17ab397c780f6cd97ad0253ec3af946009..5c64dc98feba454d705a5703587f315c2d39bae2 100644 --- a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java +++ b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java @@ -57,7 +57,7 @@ class ClientHelperImpl implements ClientHelper { @Override public void addLocalMessage(Message m, ClientId c, BdfDictionary metadata, boolean shared) throws DbException, FormatException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { addLocalMessage(txn, m, c, metadata, shared); txn.setComplete(); @@ -89,7 +89,7 @@ class ClientHelperImpl implements ClientHelper { public BdfDictionary getMessageAsDictionary(MessageId m) throws DbException, FormatException { BdfDictionary dictionary; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { dictionary = getMessageAsDictionary(txn, m); txn.setComplete(); @@ -112,7 +112,7 @@ class ClientHelperImpl implements ClientHelper { public BdfList getMessageAsList(MessageId m) throws DbException, FormatException { BdfList list; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { list = getMessageAsList(txn, m); txn.setComplete(); @@ -135,7 +135,7 @@ class ClientHelperImpl implements ClientHelper { public BdfDictionary getGroupMetadataAsDictionary(GroupId g) throws DbException, FormatException { BdfDictionary dictionary; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { dictionary = getGroupMetadataAsDictionary(txn, g); txn.setComplete(); @@ -156,7 +156,7 @@ class ClientHelperImpl implements ClientHelper { public BdfDictionary getMessageMetadataAsDictionary(MessageId m) throws DbException, FormatException { BdfDictionary dictionary; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { dictionary = getMessageMetadataAsDictionary(txn, m); txn.setComplete(); @@ -177,7 +177,7 @@ class ClientHelperImpl implements ClientHelper { public Map<MessageId, BdfDictionary> getMessageMetatataAsDictionary( GroupId g) throws DbException, FormatException { Map<MessageId, BdfDictionary> map; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { map = getMessageMetadataAsDictionary(txn, g); txn.setComplete(); @@ -201,7 +201,7 @@ class ClientHelperImpl implements ClientHelper { @Override public void mergeGroupMetadata(GroupId g, BdfDictionary metadata) throws DbException, FormatException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { mergeGroupMetadata(txn, g, metadata); txn.setComplete(); @@ -219,7 +219,7 @@ class ClientHelperImpl implements ClientHelper { @Override public void mergeMessageMetadata(MessageId m, BdfDictionary metadata) throws DbException, FormatException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { mergeMessageMetadata(txn, m, metadata); txn.setComplete(); diff --git a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java index df75b73e1a17fbce161b1c527086dd2808233710..7ff709b70c9062f79d9cb29c72979a405daadae0 100644 --- a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java +++ b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java @@ -51,7 +51,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { long timestamp, boolean alice, boolean active) throws DbException { ContactId c; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { c = db.addContact(txn, remote, local, active); keyManager.addContact(txn, c, master, timestamp, alice); @@ -68,7 +68,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { @Override public Contact getContact(ContactId c) throws DbException { Contact contact; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { contact = db.getContact(txn, c); txn.setComplete(); @@ -81,7 +81,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { @Override public Collection<Contact> getActiveContacts() throws DbException { Collection<Contact> contacts; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { contacts = db.getContacts(txn); txn.setComplete(); @@ -95,7 +95,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { @Override public void removeContact(ContactId c) throws DbException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { removeContact(txn, c); txn.setComplete(); @@ -107,7 +107,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { @Override public void setContactActive(ContactId c, boolean active) throws DbException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.setContactActive(txn, c, active); txn.setComplete(); diff --git a/briar-core/src/org/briarproject/db/Database.java b/briar-core/src/org/briarproject/db/Database.java index 2544a96702e2b7b075cf55f4629b26c228e92dfe..bcd1b7f44865297b41dd97cd1ee657aa7adf0fe3 100644 --- a/briar-core/src/org/briarproject/db/Database.java +++ b/briar-core/src/org/briarproject/db/Database.java @@ -118,38 +118,52 @@ interface Database<T> { /** * Returns true if the database contains the given contact for the given * local pseudonym. + * <p/> + * Read-only. */ boolean containsContact(T txn, AuthorId remote, AuthorId local) throws DbException; /** * Returns true if the database contains the given contact. + * <p/> + * Read-only. */ boolean containsContact(T txn, ContactId c) throws DbException; /** * Returns true if the database contains the given group. + * <p/> + * Read-only. */ boolean containsGroup(T txn, GroupId g) throws DbException; /** * Returns true if the database contains the given local pseudonym. + * <p/> + * Read-only. */ boolean containsLocalAuthor(T txn, AuthorId a) throws DbException; /** * Returns true if the database contains the given message. + * <p/> + * Read-only. */ boolean containsMessage(T txn, MessageId m) throws DbException; /** * Returns true if the database contains the given transport. + * <p/> + * Read-only. */ boolean containsTransport(T txn, TransportId t) throws DbException; /** * Returns true if the database contains the given group and the group is * visible to the given contact. + * <p/> + * Read-only. */ boolean containsVisibleGroup(T txn, ContactId c, GroupId g) throws DbException; @@ -157,12 +171,16 @@ interface Database<T> { /** * Returns true if the database contains the given message and the message * is visible to the given contact. + * <p/> + * Read-only. */ boolean containsVisibleMessage(T txn, ContactId c, MessageId m) throws DbException; /** * Returns the number of messages offered by the given contact. + * <p/> + * Read-only. */ int countOfferedMessages(T txn, ContactId c) throws DbException; @@ -171,35 +189,39 @@ interface Database<T> { * {@link #removeMessage(Object, MessageId)}, the message ID and any other * associated data are not deleted, and * {@link #containsMessage(Object, MessageId)} will continue to return true. - * <p> - * Locking: write. */ void deleteMessage(T txn, MessageId m) throws DbException; /** * Deletes any metadata associated with the given message. - * <p> - * Locking: write. */ void deleteMessageMetadata(T txn, MessageId m) throws DbException; /** * Returns the contact with the given ID. + * <p/> + * Read-only. */ Contact getContact(T txn, ContactId c) throws DbException; /** * Returns all contacts. + * <p/> + * Read-only. */ Collection<Contact> getContacts(T txn) throws DbException; /** * Returns all contacts associated with the given local pseudonym. + * <p/> + * Read-only. */ Collection<ContactId> getContacts(T txn, AuthorId a) throws DbException; /** * Returns the unique ID for this device. + * <p/> + * Read-only. */ DeviceId getDeviceId(T txn) throws DbException; @@ -212,48 +234,66 @@ interface Database<T> { /** * Returns the group with the given ID. + * <p/> + * Read-only. */ Group getGroup(T txn, GroupId g) throws DbException; /** * Returns the metadata for the given group. + * <p/> + * Read-only. */ Metadata getGroupMetadata(T txn, GroupId g) throws DbException; /** * Returns all groups belonging to the given client. + * <p/> + * Read-only. */ Collection<Group> getGroups(T txn, ClientId c) throws DbException; /** * Returns the local pseudonym with the given ID. + * <p/> + * Read-only. */ LocalAuthor getLocalAuthor(T txn, AuthorId a) throws DbException; /** * Returns all local pseudonyms. + * <p/> + * Read-only. */ Collection<LocalAuthor> getLocalAuthors(T txn) throws DbException; /** * Returns the IDs of all messages in the given group. + * <p/> + * Read-only. */ Collection<MessageId> getMessageIds(T txn, GroupId g) throws DbException; /** * Returns the metadata for all messages in the given group. + * <p/> + * Read-only. */ Map<MessageId, Metadata> getMessageMetadata(T txn, GroupId g) throws DbException; /** * Returns the metadata for the given message. + * <p/> + * Read-only. */ Metadata getMessageMetadata(T txn, MessageId m) throws DbException; /** * Returns the status of all messages in the given group with respect * to the given contact. + * <p/> + * Read-only. */ Collection<MessageStatus> getMessageStatus(T txn, ContactId c, GroupId g) throws DbException; @@ -261,6 +301,8 @@ interface Database<T> { /** * Returns the status of the given message with respect to the given * contact. + * <p/> + * Read-only. */ MessageStatus getMessageStatus(T txn, ContactId c, MessageId m) throws DbException; @@ -268,6 +310,8 @@ interface Database<T> { /** * Returns the IDs of some messages received from the given contact that * need to be acknowledged, up to the given number of messages. + * <p/> + * Read-only. */ Collection<MessageId> getMessagesToAck(T txn, ContactId c, int maxMessages) throws DbException; @@ -275,6 +319,8 @@ interface Database<T> { /** * Returns the IDs of some messages that are eligible to be offered to the * given contact, up to the given number of messages. + * <p/> + * Read-only. */ Collection<MessageId> getMessagesToOffer(T txn, ContactId c, int maxMessages) throws DbException; @@ -282,6 +328,8 @@ interface Database<T> { /** * Returns the IDs of some messages that are eligible to be sent to the * given contact, up to the given total length. + * <p/> + * Read-only. */ Collection<MessageId> getMessagesToSend(T txn, ContactId c, int maxLength) throws DbException; @@ -289,6 +337,8 @@ interface Database<T> { /** * Returns the IDs of some messages that are eligible to be requested from * the given contact, up to the given number of messages. + * <p/> + * Read-only. */ Collection<MessageId> getMessagesToRequest(T txn, ContactId c, int maxMessages) throws DbException; @@ -296,12 +346,17 @@ interface Database<T> { /** * Returns the IDs of any messages that need to be validated by the given * client. + * <p/> + * Read-only. */ Collection<MessageId> getMessagesToValidate(T txn, ClientId c) throws DbException; /** - * Returns the message with the given ID, in serialised form. + * Returns the message with the given ID, in serialised form, or null if + * the message has been deleted. + * <p/> + * Read-only. */ byte[] getRawMessage(T txn, MessageId m) throws DbException; @@ -309,28 +364,31 @@ interface Database<T> { * Returns the IDs of some messages that are eligible to be sent to the * given contact and have been requested by the contact, up to the given * total length. + * <p/> + * Read-only. */ Collection<MessageId> getRequestedMessagesToSend(T txn, ContactId c, int maxLength) throws DbException; /** * Returns all settings in the given namespace. + * <p/> + * Read-only. */ Settings getSettings(T txn, String namespace) throws DbException; /** * Returns all transport keys for the given transport. + * <p/> + * Read-only. */ Map<ContactId, TransportKeys> getTransportKeys(T txn, TransportId t) throws DbException; - /** - * Returns the maximum latencies in milliseconds of all transports. - */ - Map<TransportId, Integer> getTransportLatencies(T txn) throws DbException; - /** * Returns the IDs of all contacts to which the given group is visible. + * <p/> + * Read-only. */ Collection<ContactId> getVisibility(T txn, GroupId g) throws DbException; diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index a912407513482683afdb1e4f97fd61d025b981c5..d00159903596c83da6d3750dc115571dcab6215e 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -33,8 +33,6 @@ import org.briarproject.api.event.MessageValidatedEvent; import org.briarproject.api.event.MessagesAckedEvent; import org.briarproject.api.event.MessagesSentEvent; import org.briarproject.api.event.SettingsUpdatedEvent; -import org.briarproject.api.event.TransportAddedEvent; -import org.briarproject.api.event.TransportRemovedEvent; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.LocalAuthor; @@ -61,6 +59,8 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Logger; import javax.inject.Inject; @@ -80,6 +80,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { private final EventBus eventBus; private final ShutdownManager shutdown; private final AtomicBoolean closed = new AtomicBoolean(false); + private final ReadWriteLock lock = new ReentrantReadWriteLock(true); private volatile int shutdownHandle = -1; @@ -117,18 +118,33 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { db.close(); } - public Transaction startTransaction() throws DbException { - return new Transaction(db.startTransaction()); + public Transaction startTransaction(boolean readOnly) throws DbException { + if (readOnly) lock.readLock().lock(); + else lock.writeLock().lock(); + try { + return new Transaction(db.startTransaction(), readOnly); + } catch (DbException e) { + if (readOnly) lock.readLock().unlock(); + else lock.writeLock().unlock(); + throw e; + } catch (RuntimeException e) { + if (readOnly) lock.readLock().unlock(); + else lock.writeLock().unlock(); + throw e; + } } public void endTransaction(Transaction transaction) throws DbException { - T txn = txnClass.cast(transaction.unbox()); - if (transaction.isComplete()) { - db.commitTransaction(txn); - for (Event e : transaction.getEvents()) eventBus.broadcast(e); - } else { - db.abortTransaction(txn); + try { + T txn = txnClass.cast(transaction.unbox()); + if (transaction.isComplete()) db.commitTransaction(txn); + else db.abortTransaction(txn); + } finally { + if (transaction.isReadOnly()) lock.readLock().unlock(); + else lock.writeLock().unlock(); } + if (transaction.isComplete()) + for (Event e : transaction.getEvents()) eventBus.broadcast(e); } private T unbox(Transaction transaction) { @@ -138,6 +154,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public ContactId addContact(Transaction transaction, Author remote, AuthorId local, boolean active) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsLocalAuthor(txn, local)) throw new NoSuchLocalAuthorException(); @@ -150,6 +167,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { } public void addGroup(Transaction transaction, Group g) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsGroup(txn, g.getId())) { db.addGroup(txn, g); @@ -159,6 +177,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void addLocalAuthor(Transaction transaction, LocalAuthor a) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsLocalAuthor(txn, a.getId())) { db.addLocalAuthor(txn, a); @@ -168,6 +187,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void addLocalMessage(Transaction transaction, Message m, ClientId c, Metadata meta, boolean shared) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsGroup(txn, m.getGroupId())) throw new NoSuchGroupException(); @@ -191,15 +211,15 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void addTransport(Transaction transaction, TransportId t, int maxLatency) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); - if (!db.containsTransport(txn, t)) { + if (!db.containsTransport(txn, t)) db.addTransport(txn, t, maxLatency); - transaction.attach(new TransportAddedEvent(t, maxLatency)); - } } public void addTransportKeys(Transaction transaction, ContactId c, TransportKeys k) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -210,6 +230,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void deleteMessage(Transaction transaction, MessageId m) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsMessage(txn, m)) throw new NoSuchMessageException(); @@ -218,6 +239,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void deleteMessageMetadata(Transaction transaction, MessageId m) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsMessage(txn, m)) throw new NoSuchMessageException(); @@ -226,6 +248,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public Ack generateAck(Transaction transaction, ContactId c, int maxMessages) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -237,6 +260,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public Collection<byte[]> generateBatch(Transaction transaction, ContactId c, int maxLength, int maxLatency) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -254,6 +278,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public Offer generateOffer(Transaction transaction, ContactId c, int maxMessages, int maxLatency) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -265,6 +290,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public Request generateRequest(Transaction transaction, ContactId c, int maxMessages) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -277,6 +303,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public Collection<byte[]> generateRequestedBatch(Transaction transaction, ContactId c, int maxLength, int maxLatency) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -420,14 +447,9 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { return db.getTransportKeys(txn, t); } - public Map<TransportId, Integer> getTransportLatencies( - Transaction transaction) throws DbException { - T txn = unbox(transaction); - return db.getTransportLatencies(txn); - } - public void incrementStreamCounter(Transaction transaction, ContactId c, TransportId t, long rotationPeriod) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -448,6 +470,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void mergeGroupMetadata(Transaction transaction, GroupId g, Metadata meta) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsGroup(txn, g)) throw new NoSuchGroupException(); @@ -456,6 +479,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void mergeMessageMetadata(Transaction transaction, MessageId m, Metadata meta) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsMessage(txn, m)) throw new NoSuchMessageException(); @@ -464,6 +488,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void mergeSettings(Transaction transaction, Settings s, String namespace) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); Settings old = db.getSettings(txn, namespace); Settings merged = new Settings(); @@ -477,6 +502,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void receiveAck(Transaction transaction, ContactId c, Ack a) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -492,6 +518,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void receiveMessage(Transaction transaction, ContactId c, Message m) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -507,6 +534,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void receiveOffer(Transaction transaction, ContactId c, Offer o) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -529,6 +557,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void receiveRequest(Transaction transaction, ContactId c, Request r) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -545,6 +574,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void removeContact(Transaction transaction, ContactId c) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -554,6 +584,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void removeGroup(Transaction transaction, Group g) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); GroupId id = g.getId(); if (!db.containsGroup(txn, id)) @@ -566,6 +597,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void removeLocalAuthor(Transaction transaction, AuthorId a) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsLocalAuthor(txn, a)) throw new NoSuchLocalAuthorException(); @@ -575,15 +607,16 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void removeTransport(Transaction transaction, TransportId t) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsTransport(txn, t)) throw new NoSuchTransportException(); db.removeTransport(txn, t); - transaction.attach(new TransportRemovedEvent(t)); } public void setContactActive(Transaction transaction, ContactId c, boolean active) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -593,6 +626,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void setMessageShared(Transaction transaction, Message m, boolean shared) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsMessage(txn, m.getId())) throw new NoSuchMessageException(); @@ -602,6 +636,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void setMessageValid(Transaction transaction, Message m, ClientId c, boolean valid) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsMessage(txn, m.getId())) throw new NoSuchMessageException(); @@ -612,6 +647,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void setReorderingWindow(Transaction transaction, ContactId c, TransportId t, long rotationPeriod, long base, byte[] bitmap) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -622,6 +658,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void setVisibleToContact(Transaction transaction, ContactId c, GroupId g, boolean visible) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); @@ -647,6 +684,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { public void updateTransportKeys(Transaction transaction, Map<ContactId, TransportKeys> keys) throws DbException { + if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); Map<ContactId, TransportKeys> filtered = new HashMap<ContactId, TransportKeys>(); diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java index 7fc836348386c6aa042532889700060295bb69cc..536161562462bc9ce06144418701eb11d4b78510 100644 --- a/briar-core/src/org/briarproject/db/JdbcDatabase.java +++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java @@ -1542,30 +1542,6 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public Map<TransportId, Integer> getTransportLatencies(Connection txn) - throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT transportId, maxLatency FROM transports"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); - Map<TransportId, Integer> latencies = - new HashMap<TransportId, Integer>(); - while (rs.next()) { - TransportId id = new TransportId(rs.getString(1)); - latencies.put(id, rs.getInt(2)); - } - rs.close(); - ps.close(); - return Collections.unmodifiableMap(latencies); - } catch (SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - } - public Collection<ContactId> getVisibility(Connection txn, GroupId g) throws DbException { PreparedStatement ps = null; diff --git a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java index d2b2d872e8ebd38954e273ae2a8579438638ba72..8d319ca4ad11a4ef6e66ebc431367829a4c3795d 100644 --- a/briar-core/src/org/briarproject/forum/ForumManagerImpl.java +++ b/briar-core/src/org/briarproject/forum/ForumManagerImpl.java @@ -83,7 +83,7 @@ class ForumManagerImpl implements ForumManager { public Forum getForum(GroupId g) throws DbException { try { Group group; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { group = db.getGroup(txn, g); txn.setComplete(); @@ -100,7 +100,7 @@ class ForumManagerImpl implements ForumManager { public Collection<Forum> getForums() throws DbException { try { Collection<Group> groups; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { groups = db.getGroups(txn, CLIENT_ID); txn.setComplete(); @@ -132,7 +132,7 @@ class ForumManagerImpl implements ForumManager { Set<AuthorId> localAuthorIds = new HashSet<AuthorId>(); Set<AuthorId> contactAuthorIds = new HashSet<AuthorId>(); Map<MessageId, BdfDictionary> metadata; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { // Load the IDs of the user's identities for (LocalAuthor a : db.getLocalAuthors(txn)) diff --git a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java index b0e8fd486f810180ea15631ba8d2eb57135db72b..c30834e8f6b0a570644533b7bbd0e3b47b5a8fda 100644 --- a/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/forum/ForumSharingManagerImpl.java @@ -131,7 +131,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, @Override public void addForum(Forum f) throws DbException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.addGroup(txn, f.getGroup()); txn.setComplete(); @@ -144,7 +144,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, public void removeForum(Forum f) throws DbException { try { // Update the list shared with each contact - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { for (Contact c : db.getContacts(txn)) removeFromList(txn, getContactGroup(c).getId(), f); @@ -162,7 +162,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, public Collection<Forum> getAvailableForums() throws DbException { try { Set<Forum> available = new HashSet<Forum>(); - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { // Get any forums we subscribe to Set<Group> subscribed = new HashSet<Group>(db.getGroups(txn, @@ -196,7 +196,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, public Collection<Contact> getSharedBy(GroupId g) throws DbException { try { List<Contact> subscribers = new ArrayList<Contact>(); - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { for (Contact c : db.getContacts(txn)) { if (listContains(txn, getContactGroup(c).getId(), g, false)) @@ -216,7 +216,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, public Collection<ContactId> getSharedWith(GroupId g) throws DbException { try { List<ContactId> shared = new ArrayList<ContactId>(); - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { for (Contact c : db.getContacts(txn)) { if (listContains(txn, getContactGroup(c).getId(), g, true)) @@ -236,7 +236,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, public void setSharedWith(GroupId g, Collection<ContactId> shared) throws DbException { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { // Retrieve the forum Forum f = parseForum(db.getGroup(txn, g)); @@ -268,7 +268,7 @@ class ForumSharingManagerImpl implements ForumSharingManager, AddContactHook, @Override public void setSharedWithAll(GroupId g) throws DbException { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { // Retrieve the forum Forum f = parseForum(db.getGroup(txn, g)); diff --git a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java index 997456d2941dad65c40509e8507dc0eb9a5ca06e..b3d7a1f4d8213f8427963457ff8a3d80b8c91a0f 100644 --- a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java +++ b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java @@ -37,7 +37,7 @@ class IdentityManagerImpl implements IdentityManager { @Override public void addLocalAuthor(LocalAuthor localAuthor) throws DbException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.addLocalAuthor(txn, localAuthor); for (AddIdentityHook hook : addHooks) @@ -51,7 +51,7 @@ class IdentityManagerImpl implements IdentityManager { @Override public LocalAuthor getLocalAuthor(AuthorId a) throws DbException { LocalAuthor author; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { author = db.getLocalAuthor(txn, a); txn.setComplete(); @@ -64,7 +64,7 @@ class IdentityManagerImpl implements IdentityManager { @Override public Collection<LocalAuthor> getLocalAuthors() throws DbException { Collection<LocalAuthor> authors; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { authors = db.getLocalAuthors(txn); txn.setComplete(); @@ -76,7 +76,7 @@ class IdentityManagerImpl implements IdentityManager { @Override public void removeLocalAuthor(AuthorId a) throws DbException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { LocalAuthor localAuthor = db.getLocalAuthor(txn, a); for (RemoveIdentityHook hook : removeHooks) diff --git a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java index aba60f16b147645e738cda56f258a17d73766c8c..f153a3a37714ca1ae8c7935fa12c2d9d950138ea 100644 --- a/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java +++ b/briar-core/src/org/briarproject/lifecycle/LifecycleManagerImpl.java @@ -6,7 +6,6 @@ import org.briarproject.api.event.EventBus; import org.briarproject.api.event.ShutdownEvent; import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.Service; -import org.briarproject.api.system.Clock; import java.io.IOException; import java.util.Collection; @@ -30,7 +29,6 @@ class LifecycleManagerImpl implements LifecycleManager { private static final Logger LOG = Logger.getLogger(LifecycleManagerImpl.class.getName()); - private final Clock clock; private final DatabaseComponent db; private final EventBus eventBus; private final Collection<Service> services; @@ -41,8 +39,7 @@ class LifecycleManagerImpl implements LifecycleManager { private final CountDownLatch shutdownLatch = new CountDownLatch(1); @Inject - LifecycleManagerImpl(Clock clock, DatabaseComponent db, EventBus eventBus) { - this.clock = clock; + LifecycleManagerImpl(DatabaseComponent db, EventBus eventBus) { this.db = db; this.eventBus = eventBus; services = new CopyOnWriteArrayList<Service>(); @@ -68,9 +65,9 @@ class LifecycleManagerImpl implements LifecycleManager { } try { LOG.info("Starting services"); - long now = clock.currentTimeMillis(); + long start = System.currentTimeMillis(); boolean reopened = db.open(); - long duration = clock.currentTimeMillis() - now; + long duration = System.currentTimeMillis() - start; if (LOG.isLoggable(INFO)) { if (reopened) LOG.info("Reopening database took " + duration + " ms"); @@ -78,9 +75,9 @@ class LifecycleManagerImpl implements LifecycleManager { } dbLatch.countDown(); for (Service s : services) { - now = clock.currentTimeMillis(); + start = System.currentTimeMillis(); boolean started = s.start(); - duration = clock.currentTimeMillis() - now; + duration = System.currentTimeMillis() - start; if (!started) { if (LOG.isLoggable(WARNING)) { String name = s.getClass().getName(); diff --git a/briar-core/src/org/briarproject/lifecycle/LifecycleModule.java b/briar-core/src/org/briarproject/lifecycle/LifecycleModule.java index 7b98244eb405d4e30dc32a4fe1de56e01251d8a6..7ad4cb6b0cb27f48c5e8a6fa6253ed0ee3176c07 100644 --- a/briar-core/src/org/briarproject/lifecycle/LifecycleModule.java +++ b/briar-core/src/org/briarproject/lifecycle/LifecycleModule.java @@ -1,6 +1,10 @@ package org.briarproject.lifecycle; -import static java.util.concurrent.TimeUnit.SECONDS; +import org.briarproject.api.db.DatabaseComponent; +import org.briarproject.api.event.EventBus; +import org.briarproject.api.lifecycle.IoExecutor; +import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.lifecycle.ShutdownManager; import java.util.concurrent.BlockingQueue; import java.util.concurrent.Executor; @@ -12,16 +16,11 @@ import java.util.concurrent.ThreadPoolExecutor; import javax.inject.Inject; import javax.inject.Singleton; -import org.briarproject.api.db.DatabaseComponent; -import org.briarproject.api.event.EventBus; -import org.briarproject.api.lifecycle.IoExecutor; -import org.briarproject.api.lifecycle.LifecycleManager; -import org.briarproject.api.lifecycle.ShutdownManager; -import org.briarproject.api.system.Clock; - import dagger.Module; import dagger.Provides; +import static java.util.concurrent.TimeUnit.SECONDS; + @Module public class LifecycleModule { @@ -51,9 +50,9 @@ public class LifecycleModule { @Provides @Singleton - LifecycleManager provideLifeCycleManager(Clock clock, DatabaseComponent db, + LifecycleManager provideLifecycleManager(DatabaseComponent db, EventBus eventBus) { - return new LifecycleManagerImpl(clock, db, eventBus); + return new LifecycleManagerImpl(db, eventBus); } @Provides @@ -63,5 +62,4 @@ public class LifecycleModule { lifecycleManager.registerForShutdown(ioExecutor); return ioExecutor; } - } diff --git a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java index c1a0eb797cad84b3130b76785e1d397bb682dc32..e7e64552f5c3a6d42f6b8ec2123c2edf03ebfe1b 100644 --- a/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java +++ b/briar-core/src/org/briarproject/messaging/MessagingManagerImpl.java @@ -106,7 +106,7 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook, @Override public GroupId getConversationId(ContactId c) throws DbException { Contact contact; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { contact = db.getContact(txn, c); txn.setComplete(); @@ -121,7 +121,7 @@ class MessagingManagerImpl implements MessagingManager, AddContactHook, throws DbException { Map<MessageId, BdfDictionary> metadata; Collection<MessageStatus> statuses; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { GroupId g = getContactGroup(db.getContact(txn, c)).getId(); metadata = clientHelper.getMessageMetadataAsDictionary(txn, g); diff --git a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java index 0b6fe073d310186b53c0fac4208846407e85d707..2eb502cf1e929aa30f9dbed84d11a1ee6d069328 100644 --- a/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/ConnectionManagerImpl.java @@ -2,6 +2,7 @@ package org.briarproject.plugins; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DbException; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.ConnectionRegistry; @@ -90,8 +91,8 @@ class ConnectionManagerImpl implements ConnectionManager { TransportConnectionReader r) throws IOException { InputStream streamReader = streamReaderFactory.createStreamReader( r.getInputStream(), ctx); - return syncSessionFactory.createIncomingSession( - ctx.getContactId(), ctx.getTransportId(), streamReader); + return syncSessionFactory.createIncomingSession(ctx.getContactId(), + streamReader); } private SyncSession createSimplexOutgoingSession(StreamContext ctx, @@ -99,8 +100,7 @@ class ConnectionManagerImpl implements ConnectionManager { OutputStream streamWriter = streamWriterFactory.createStreamWriter( w.getOutputStream(), ctx); return syncSessionFactory.createSimplexOutgoingSession( - ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), - streamWriter); + ctx.getContactId(), w.getMaxLatency(), streamWriter); } private SyncSession createDuplexOutgoingSession(StreamContext ctx, @@ -108,8 +108,8 @@ class ConnectionManagerImpl implements ConnectionManager { OutputStream streamWriter = streamWriterFactory.createStreamWriter( w.getOutputStream(), ctx); return syncSessionFactory.createDuplexOutgoingSession( - ctx.getContactId(), ctx.getTransportId(), w.getMaxLatency(), - w.getMaxIdleTime(), streamWriter); + ctx.getContactId(), w.getMaxLatency(), w.getMaxIdleTime(), + streamWriter); } private class ManageIncomingSimplexConnection implements Runnable { @@ -133,10 +133,14 @@ class ConnectionManagerImpl implements ConnectionManager { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); disposeReader(true, false); return; + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + disposeReader(true, false); + return; } if (ctx == null) { LOG.info("Unrecognised tag"); - disposeReader(true, false); + disposeReader(false, false); return; } ContactId contactId = ctx.getContactId(); @@ -177,11 +181,17 @@ class ConnectionManagerImpl implements ConnectionManager { public void run() { // Allocate a stream context - StreamContext ctx = keyManager.getStreamContext(contactId, - transportId); + StreamContext ctx; + try { + ctx = keyManager.getStreamContext(contactId, transportId); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + disposeWriter(true); + return; + } if (ctx == null) { LOG.warning("Could not allocate stream context"); - disposeWriter(true); + disposeWriter(false); return; } connectionRegistry.registerConnection(contactId, transportId); @@ -233,10 +243,14 @@ class ConnectionManagerImpl implements ConnectionManager { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); disposeReader(true, false); return; + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + disposeReader(true, false); + return; } if (ctx == null) { LOG.info("Unrecognised tag"); - disposeReader(true, false); + disposeReader(false, false); return; } contactId = ctx.getContactId(); @@ -262,11 +276,17 @@ class ConnectionManagerImpl implements ConnectionManager { private void runOutgoingSession() { // Allocate a stream context - StreamContext ctx = keyManager.getStreamContext(contactId, - transportId); + StreamContext ctx; + try { + ctx = keyManager.getStreamContext(contactId, transportId); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + disposeWriter(true); + return; + } if (ctx == null) { LOG.warning("Could not allocate stream context"); - disposeWriter(true); + disposeWriter(false); return; } try { @@ -321,11 +341,17 @@ class ConnectionManagerImpl implements ConnectionManager { public void run() { // Allocate a stream context - StreamContext ctx = keyManager.getStreamContext(contactId, - transportId); + StreamContext ctx; + try { + ctx = keyManager.getStreamContext(contactId, transportId); + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + disposeWriter(true); + return; + } if (ctx == null) { LOG.warning("Could not allocate stream context"); - disposeWriter(true); + disposeWriter(false); return; } connectionRegistry.registerConnection(contactId, transportId); @@ -358,6 +384,10 @@ class ConnectionManagerImpl implements ConnectionManager { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); disposeReader(true, true); return; + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + disposeReader(true, true); + return; } // Unrecognised tags are suspicious in this case if (ctx == null) { diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java index bd110d0cf652715543b0b4670adfa7e7fc65f1ba..367b1b66c5be99be31d6e20c930f5702bab09893 100644 --- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java @@ -2,9 +2,7 @@ package org.briarproject.plugins; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; -import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; -import org.briarproject.api.db.Transaction; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.TransportDisabledEvent; import org.briarproject.api.event.TransportEnabledEvent; @@ -13,23 +11,21 @@ import org.briarproject.api.lifecycle.Service; import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.Plugin; import org.briarproject.api.plugins.PluginCallback; +import org.briarproject.api.plugins.PluginConfig; import org.briarproject.api.plugins.PluginManager; 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.DuplexPluginCallback; -import org.briarproject.api.plugins.duplex.DuplexPluginConfig; import org.briarproject.api.plugins.duplex.DuplexPluginFactory; import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.simplex.SimplexPlugin; import org.briarproject.api.plugins.simplex.SimplexPluginCallback; -import org.briarproject.api.plugins.simplex.SimplexPluginConfig; import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.properties.TransportProperties; import org.briarproject.api.properties.TransportPropertyManager; import org.briarproject.api.settings.Settings; import org.briarproject.api.settings.SettingsManager; -import org.briarproject.api.system.Clock; import org.briarproject.api.ui.UiCallback; import java.io.IOException; @@ -56,10 +52,7 @@ class PluginManagerImpl implements PluginManager, Service { private final Executor ioExecutor; private final EventBus eventBus; - private final SimplexPluginConfig simplexPluginConfig; - private final DuplexPluginConfig duplexPluginConfig; - private final Clock clock; - private final DatabaseComponent db; + private final PluginConfig pluginConfig; private final Poller poller; private final ConnectionManager connectionManager; private final SettingsManager settingsManager; @@ -71,19 +64,14 @@ class PluginManagerImpl implements PluginManager, Service { @Inject PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus, - SimplexPluginConfig simplexPluginConfig, - DuplexPluginConfig duplexPluginConfig, Clock clock, - DatabaseComponent db, Poller poller, + PluginConfig pluginConfig, Poller poller, ConnectionManager connectionManager, SettingsManager settingsManager, TransportPropertyManager transportPropertyManager, UiCallback uiCallback) { this.ioExecutor = ioExecutor; this.eventBus = eventBus; - this.simplexPluginConfig = simplexPluginConfig; - this.duplexPluginConfig = duplexPluginConfig; - this.clock = clock; - this.db = db; + this.pluginConfig = pluginConfig; this.poller = poller; this.connectionManager = connectionManager; this.settingsManager = settingsManager; @@ -99,14 +87,14 @@ class PluginManagerImpl implements PluginManager, Service { // Instantiate and start the simplex plugins LOG.info("Starting simplex plugins"); Collection<SimplexPluginFactory> sFactories = - simplexPluginConfig.getFactories(); + pluginConfig.getSimplexFactories(); final CountDownLatch sLatch = new CountDownLatch(sFactories.size()); for (SimplexPluginFactory factory : sFactories) ioExecutor.execute(new SimplexPluginStarter(factory, sLatch)); // Instantiate and start the duplex plugins LOG.info("Starting duplex plugins"); Collection<DuplexPluginFactory> dFactories = - duplexPluginConfig.getFactories(); + pluginConfig.getDuplexFactories(); final CountDownLatch dLatch = new CountDownLatch(dFactories.size()); for (DuplexPluginFactory factory : dFactories) ioExecutor.execute(new DuplexPluginStarter(factory, dLatch)); @@ -185,26 +173,9 @@ class PluginManagerImpl implements PluginManager, Service { return; } try { - long start = clock.currentTimeMillis(); - Transaction txn = db.startTransaction(); - try { - db.addTransport(txn, id, plugin.getMaxLatency()); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } - long duration = clock.currentTimeMillis() - start; - if (LOG.isLoggable(INFO)) - LOG.info("Adding transport took " + duration + " ms"); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - return; - } - try { - long start = clock.currentTimeMillis(); + long start = System.currentTimeMillis(); boolean started = plugin.start(); - long duration = clock.currentTimeMillis() - start; + long duration = System.currentTimeMillis() - start; if (started) { plugins.put(id, plugin); simplexPlugins.add(plugin); @@ -254,26 +225,9 @@ class PluginManagerImpl implements PluginManager, Service { return; } try { - long start = clock.currentTimeMillis(); - Transaction txn = db.startTransaction(); - try { - db.addTransport(txn, id, plugin.getMaxLatency()); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } - long duration = clock.currentTimeMillis() - start; - if (LOG.isLoggable(INFO)) - LOG.info("Adding transport took " + duration + " ms"); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - return; - } - try { - long start = clock.currentTimeMillis(); + long start = System.currentTimeMillis(); boolean started = plugin.start(); - long duration = clock.currentTimeMillis() - start; + long duration = System.currentTimeMillis() - start; if (started) { plugins.put(id, plugin); duplexPlugins.add(plugin); @@ -311,9 +265,9 @@ class PluginManagerImpl implements PluginManager, Service { public void run() { try { - long start = clock.currentTimeMillis(); + long start = System.currentTimeMillis(); plugin.stop(); - long duration = clock.currentTimeMillis() - start; + long duration = System.currentTimeMillis() - start; if (LOG.isLoggable(INFO)) { String name = plugin.getClass().getSimpleName(); LOG.info("Stopping " + name + " took " + duration + " ms"); diff --git a/briar-core/src/org/briarproject/plugins/PluginsModule.java b/briar-core/src/org/briarproject/plugins/PluginsModule.java index 6f3357b8b5ac88229644c4a6eae3e38c7f283477..d106d8920f549b308a30006094e01818ec8e1313 100644 --- a/briar-core/src/org/briarproject/plugins/PluginsModule.java +++ b/briar-core/src/org/briarproject/plugins/PluginsModule.java @@ -1,8 +1,5 @@ package org.briarproject.plugins; -import javax.inject.Inject; -import javax.inject.Singleton; - import org.briarproject.api.event.EventBus; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.lifecycle.LifecycleManager; @@ -19,10 +16,12 @@ import org.briarproject.api.transport.StreamWriterFactory; import java.security.SecureRandom; import java.util.concurrent.Executor; +import javax.inject.Inject; +import javax.inject.Singleton; + import dagger.Module; import dagger.Provides; - @Module public class PluginsModule { @@ -45,8 +44,8 @@ public class PluginsModule { @Provides ConnectionManager provideConnectionManager( - @IoExecutor Executor ioExecutor, - KeyManager keyManager, StreamReaderFactory streamReaderFactory, + @IoExecutor Executor ioExecutor, KeyManager keyManager, + StreamReaderFactory streamReaderFactory, StreamWriterFactory streamWriterFactory, SyncSessionFactory syncSessionFactory, ConnectionRegistry connectionRegistry) { @@ -61,7 +60,6 @@ public class PluginsModule { return new ConnectionRegistryImpl(eventBus); } - @Provides @Singleton PluginManager getPluginManager(LifecycleManager lifecycleManager, @@ -69,5 +67,4 @@ public class PluginsModule { lifecycleManager.register(pluginManager); return pluginManager; } - } diff --git a/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java b/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java index 39ea14b3eab4bcc3c477bf7b1a0222fb42403244..ed6219797c7dd5d33629eee3bb25f79955a708bd 100644 --- a/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java +++ b/briar-core/src/org/briarproject/plugins/file/FileTransportReader.java @@ -1,13 +1,13 @@ package org.briarproject.plugins.file; -import static java.util.logging.Level.WARNING; +import org.briarproject.api.plugins.TransportConnectionReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.logging.Logger; -import org.briarproject.api.plugins.TransportConnectionReader; +import static java.util.logging.Level.WARNING; class FileTransportReader implements TransportConnectionReader { @@ -24,10 +24,6 @@ class FileTransportReader implements TransportConnectionReader { this.plugin = plugin; } - public long getMaxLatency() { - return plugin.getMaxLatency(); - } - public InputStream getInputStream() { return in; } diff --git a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java index 929f63a6b849b80454e24c33f7783cdd765b0c5f..9b354427a240b81f05bb54aadade681ccdf3727b 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/LanTcpPluginFactory.java @@ -30,6 +30,10 @@ public class LanTcpPluginFactory implements DuplexPluginFactory { return LanTcpPlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); diff --git a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java index 213cb88ce5d1cf81c5075089d691d8d23bf90e33..c400975bf3d44bb21ba87d97b174a7e292b728ac 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java +++ b/briar-core/src/org/briarproject/plugins/tcp/TcpTransportConnection.java @@ -1,16 +1,16 @@ package org.briarproject.plugins.tcp; +import org.briarproject.api.plugins.Plugin; +import org.briarproject.api.plugins.TransportConnectionReader; +import org.briarproject.api.plugins.TransportConnectionWriter; +import org.briarproject.api.plugins.duplex.DuplexTransportConnection; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.concurrent.atomic.AtomicBoolean; -import org.briarproject.api.plugins.Plugin; -import org.briarproject.api.plugins.TransportConnectionReader; -import org.briarproject.api.plugins.TransportConnectionWriter; -import org.briarproject.api.plugins.duplex.DuplexTransportConnection; - class TcpTransportConnection implements DuplexTransportConnection { private final Plugin plugin; @@ -38,10 +38,6 @@ class TcpTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public long getMaxLatency() { - return plugin.getMaxLatency(); - } - public InputStream getInputStream() throws IOException { return socket.getInputStream(); } diff --git a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java index 659b79f1c0536b80105ea855caf6a63e6a3b48a1..44fdf5edfdf1ffe9b7b4c60c04678f6002dd6d4f 100644 --- a/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java +++ b/briar-core/src/org/briarproject/plugins/tcp/WanTcpPluginFactory.java @@ -33,6 +33,10 @@ public class WanTcpPluginFactory implements DuplexPluginFactory { return WanTcpPlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); diff --git a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java index 2c90166526ae97810aca79d0e1d8d6cddb1e4e1e..9910ff42fe9facb2d1a0a5eebebff2cc89b1f6da 100644 --- a/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java +++ b/briar-core/src/org/briarproject/properties/TransportPropertyManagerImpl.java @@ -84,7 +84,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, @Override public void addRemoteProperties(ContactId c, DeviceId dev, Map<TransportId, TransportProperties> props) throws DbException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { Group g = getContactGroup(db.getContact(txn, c)); for (Entry<TransportId, TransportProperties> e : props.entrySet()) { @@ -101,7 +101,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, public Map<TransportId, TransportProperties> getLocalProperties() throws DbException { Map<TransportId, TransportProperties> local; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { local = getLocalProperties(txn); txn.setComplete(); @@ -116,7 +116,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, throws DbException { try { TransportProperties p = null; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { // Find the latest local update LatestUpdate latest = findLatest(txn, localGroup.getId(), t, @@ -146,7 +146,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, try { Map<ContactId, TransportProperties> remote = new HashMap<ContactId, TransportProperties>(); - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { for (Contact c : db.getContacts(txn)) { Group g = getContactGroup(c); @@ -173,7 +173,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, public void mergeLocalProperties(TransportId t, TransportProperties p) throws DbException { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { // Create the local group if necessary db.addGroup(txn, localGroup); diff --git a/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java b/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java index 4ff0ff2217cd9c0ec5a5e16bba6e2f121e9fca25..3df277318cb41650fc69ff5af2f15ee80e44cb2d 100644 --- a/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java +++ b/briar-core/src/org/briarproject/settings/SettingsManagerImpl.java @@ -21,7 +21,7 @@ class SettingsManagerImpl implements SettingsManager { @Override public Settings getSettings(String namespace) throws DbException { Settings s; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { s = db.getSettings(txn, namespace); txn.setComplete(); @@ -33,7 +33,7 @@ class SettingsManagerImpl implements SettingsManager { @Override public void mergeSettings(Settings s, String namespace) throws DbException { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.mergeSettings(txn, s, namespace); txn.setComplete(); diff --git a/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java b/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java index 8976eb7d16be1f951098999468f57a810740341c..7c87c3151419ed36f9d7a0d95bc93d9663a79479 100644 --- a/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/sync/DuplexOutgoingSession.java @@ -1,6 +1,5 @@ package org.briarproject.sync; -import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; @@ -15,7 +14,6 @@ import org.briarproject.api.event.MessageSharedEvent; import org.briarproject.api.event.MessageToAckEvent; import org.briarproject.api.event.MessageToRequestEvent; import org.briarproject.api.event.ShutdownEvent; -import org.briarproject.api.event.TransportRemovedEvent; import org.briarproject.api.sync.Ack; import org.briarproject.api.sync.Offer; import org.briarproject.api.sync.PacketWriter; @@ -59,7 +57,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener { private final EventBus eventBus; private final Clock clock; private final ContactId contactId; - private final TransportId transportId; private final int maxLatency, maxIdleTime; private final PacketWriter packetWriter; private final BlockingQueue<ThrowingRunnable<IOException>> writerTasks; @@ -67,15 +64,13 @@ class DuplexOutgoingSession implements SyncSession, EventListener { private volatile boolean interrupted = false; DuplexOutgoingSession(DatabaseComponent db, Executor dbExecutor, - EventBus eventBus, Clock clock, ContactId contactId, - TransportId transportId, int maxLatency, int maxIdleTime, - PacketWriter packetWriter) { + EventBus eventBus, Clock clock, ContactId contactId, int maxLatency, + int maxIdleTime, PacketWriter packetWriter) { this.db = db; this.dbExecutor = dbExecutor; this.eventBus = eventBus; this.clock = clock; this.contactId = contactId; - this.transportId = transportId; this.maxLatency = maxLatency; this.maxIdleTime = maxIdleTime; this.packetWriter = packetWriter; @@ -167,9 +162,6 @@ class DuplexOutgoingSession implements SyncSession, EventListener { dbExecutor.execute(new GenerateRequest()); } else if (e instanceof ShutdownEvent) { interrupt(); - } else if (e instanceof TransportRemovedEvent) { - TransportRemovedEvent t = (TransportRemovedEvent) e; - if (t.getTransportId().equals(transportId)) interrupt(); } } @@ -180,7 +172,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener { if (interrupted) return; try { Ack a; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS); txn.setComplete(); @@ -221,7 +213,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener { if (interrupted) return; try { Collection<byte[]> b; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { b = db.generateRequestedBatch(txn, contactId, MAX_PACKET_PAYLOAD_LENGTH, maxLatency); @@ -263,7 +255,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener { if (interrupted) return; try { Offer o; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { o = db.generateOffer(txn, contactId, MAX_MESSAGE_IDS, maxLatency); @@ -305,7 +297,7 @@ class DuplexOutgoingSession implements SyncSession, EventListener { if (interrupted) return; try { Request r; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { r = db.generateRequest(txn, contactId, MAX_MESSAGE_IDS); txn.setComplete(); diff --git a/briar-core/src/org/briarproject/sync/IncomingSession.java b/briar-core/src/org/briarproject/sync/IncomingSession.java index 5e5f4c6df220bcfb23ef55b6417d07eb8f79ed65..2a06d29cb0e18a70aa4a230b68223b0fb5b984e9 100644 --- a/briar-core/src/org/briarproject/sync/IncomingSession.java +++ b/briar-core/src/org/briarproject/sync/IncomingSession.java @@ -1,7 +1,6 @@ package org.briarproject.sync; import org.briarproject.api.FormatException; -import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; @@ -11,7 +10,6 @@ import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.ShutdownEvent; -import org.briarproject.api.event.TransportRemovedEvent; import org.briarproject.api.sync.Ack; import org.briarproject.api.sync.Message; import org.briarproject.api.sync.Offer; @@ -37,19 +35,17 @@ class IncomingSession implements SyncSession, EventListener { private final Executor dbExecutor; private final EventBus eventBus; private final ContactId contactId; - private final TransportId transportId; private final PacketReader packetReader; private volatile boolean interrupted = false; IncomingSession(DatabaseComponent db, Executor dbExecutor, - EventBus eventBus, ContactId contactId, TransportId transportId, + EventBus eventBus, ContactId contactId, PacketReader packetReader) { this.db = db; this.dbExecutor = dbExecutor; this.eventBus = eventBus; this.contactId = contactId; - this.transportId = transportId; this.packetReader = packetReader; } @@ -90,9 +86,6 @@ class IncomingSession implements SyncSession, EventListener { if (c.getContactId().equals(contactId)) interrupt(); } else if (e instanceof ShutdownEvent) { interrupt(); - } else if (e instanceof TransportRemovedEvent) { - TransportRemovedEvent t = (TransportRemovedEvent) e; - if (t.getTransportId().equals(transportId)) interrupt(); } } @@ -106,7 +99,7 @@ class IncomingSession implements SyncSession, EventListener { public void run() { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.receiveAck(txn, contactId, ack); txn.setComplete(); @@ -130,7 +123,7 @@ class IncomingSession implements SyncSession, EventListener { public void run() { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.receiveMessage(txn, contactId, message); txn.setComplete(); @@ -154,7 +147,7 @@ class IncomingSession implements SyncSession, EventListener { public void run() { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.receiveOffer(txn, contactId, offer); txn.setComplete(); @@ -178,7 +171,7 @@ class IncomingSession implements SyncSession, EventListener { public void run() { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { db.receiveRequest(txn, contactId, request); txn.setComplete(); diff --git a/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java b/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java index 31ca6268485c4f18b2de9f1c469e1a579287120d..5623c275e70d923e6be402fb3337c4dd7e2cc120 100644 --- a/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java +++ b/briar-core/src/org/briarproject/sync/SimplexOutgoingSession.java @@ -1,6 +1,5 @@ package org.briarproject.sync; -import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DbException; @@ -10,7 +9,6 @@ import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.EventListener; import org.briarproject.api.event.ShutdownEvent; -import org.briarproject.api.event.TransportRemovedEvent; import org.briarproject.api.sync.Ack; import org.briarproject.api.sync.PacketWriter; import org.briarproject.api.sync.SyncSession; @@ -48,7 +46,6 @@ class SimplexOutgoingSession implements SyncSession, EventListener { private final Executor dbExecutor; private final EventBus eventBus; private final ContactId contactId; - private final TransportId transportId; private final int maxLatency; private final PacketWriter packetWriter; private final AtomicInteger outstandingQueries; @@ -57,13 +54,12 @@ class SimplexOutgoingSession implements SyncSession, EventListener { private volatile boolean interrupted = false; SimplexOutgoingSession(DatabaseComponent db, Executor dbExecutor, - EventBus eventBus, ContactId contactId, TransportId transportId, + EventBus eventBus, ContactId contactId, int maxLatency, PacketWriter packetWriter) { this.db = db; this.dbExecutor = dbExecutor; this.eventBus = eventBus; this.contactId = contactId; - this.transportId = transportId; this.maxLatency = maxLatency; this.packetWriter = packetWriter; outstandingQueries = new AtomicInteger(2); // One per type of packet @@ -108,9 +104,6 @@ class SimplexOutgoingSession implements SyncSession, EventListener { if (c.getContactId().equals(contactId)) interrupt(); } else if (e instanceof ShutdownEvent) { interrupt(); - } else if (e instanceof TransportRemovedEvent) { - TransportRemovedEvent t = (TransportRemovedEvent) e; - if (t.getTransportId().equals(transportId)) interrupt(); } } @@ -121,7 +114,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener { if (interrupted) return; try { Ack a; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { a = db.generateAck(txn, contactId, MAX_MESSAGE_IDS); txn.setComplete(); @@ -163,7 +156,7 @@ class SimplexOutgoingSession implements SyncSession, EventListener { if (interrupted) return; try { Collection<byte[]> b; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { b = db.generateBatch(txn, contactId, MAX_PACKET_PAYLOAD_LENGTH, maxLatency); diff --git a/briar-core/src/org/briarproject/sync/SyncSessionFactoryImpl.java b/briar-core/src/org/briarproject/sync/SyncSessionFactoryImpl.java index 5a4021b1d41ba409a1bc2394edbcad0dc0043f24..6fac0012f6acfcad59e8790844d9a6fa06523d4c 100644 --- a/briar-core/src/org/briarproject/sync/SyncSessionFactoryImpl.java +++ b/briar-core/src/org/briarproject/sync/SyncSessionFactoryImpl.java @@ -1,6 +1,5 @@ package org.briarproject.sync; -import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.DatabaseExecutor; @@ -41,24 +40,22 @@ class SyncSessionFactoryImpl implements SyncSessionFactory { this.packetWriterFactory = packetWriterFactory; } - public SyncSession createIncomingSession(ContactId c, TransportId t, - InputStream in) { + public SyncSession createIncomingSession(ContactId c, InputStream in) { PacketReader packetReader = packetReaderFactory.createPacketReader(in); - return new IncomingSession(db, dbExecutor, eventBus, c, t, - packetReader); + return new IncomingSession(db, dbExecutor, eventBus, c, packetReader); } - public SyncSession createSimplexOutgoingSession(ContactId c, TransportId t, + public SyncSession createSimplexOutgoingSession(ContactId c, int maxLatency, OutputStream out) { PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out); - return new SimplexOutgoingSession(db, dbExecutor, eventBus, c, t, + return new SimplexOutgoingSession(db, dbExecutor, eventBus, c, maxLatency, packetWriter); } - public SyncSession createDuplexOutgoingSession(ContactId c, TransportId t, - int maxLatency, int maxIdleTime, OutputStream out) { + public SyncSession createDuplexOutgoingSession(ContactId c, int maxLatency, + int maxIdleTime, OutputStream out) { PacketWriter packetWriter = packetWriterFactory.createPacketWriter(out); - return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c, t, + return new DuplexOutgoingSession(db, dbExecutor, eventBus, clock, c, maxLatency, maxIdleTime, packetWriter); } } diff --git a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java index 4837a1b57a813175fefbd9a24b559d1ab3616efb..89c35459af995d1758670f8747de534a4a21373b 100644 --- a/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java +++ b/briar-core/src/org/briarproject/sync/ValidationManagerImpl.java @@ -83,7 +83,7 @@ class ValidationManagerImpl implements ValidationManager, Service, public void run() { try { Queue<MessageId> unvalidated = new LinkedList<MessageId>(); - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { unvalidated.addAll(db.getMessagesToValidate(txn, c)); txn.setComplete(); @@ -106,7 +106,7 @@ class ValidationManagerImpl implements ValidationManager, Service, try { Message m = null; Group g = null; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { MessageId id = unvalidated.poll(); byte[] raw = db.getRawMessage(txn, id); @@ -160,7 +160,7 @@ class ValidationManagerImpl implements ValidationManager, Service, dbExecutor.execute(new Runnable() { public void run() { try { - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { if (meta == null) { db.setMessageValid(txn, m, c, false); @@ -198,7 +198,7 @@ class ValidationManagerImpl implements ValidationManager, Service, public void run() { try { Group g; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(true); try { g = db.getGroup(txn, m.getGroupId()); txn.setComplete(); diff --git a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java index 3cbfef824f96f241b75389fab118ab25114c9731..32a6ee3aada1dd7cb4f8b2a03b1382dc7b622765 100644 --- a/briar-core/src/org/briarproject/transport/KeyManagerImpl.java +++ b/briar-core/src/org/briarproject/transport/KeyManagerImpl.java @@ -13,15 +13,16 @@ import org.briarproject.api.event.ContactRemovedEvent; import org.briarproject.api.event.ContactStatusChangedEvent; import org.briarproject.api.event.Event; import org.briarproject.api.event.EventListener; -import org.briarproject.api.event.TransportAddedEvent; -import org.briarproject.api.event.TransportRemovedEvent; import org.briarproject.api.lifecycle.Service; +import org.briarproject.api.plugins.PluginConfig; +import org.briarproject.api.plugins.duplex.DuplexPluginFactory; +import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.system.Clock; import org.briarproject.api.system.Timer; import org.briarproject.api.transport.KeyManager; import org.briarproject.api.transport.StreamContext; -import java.util.Collection; +import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; @@ -30,6 +31,7 @@ import java.util.logging.Logger; import javax.inject.Inject; +import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; class KeyManagerImpl implements KeyManager, Service, EventListener { @@ -40,6 +42,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { private final DatabaseComponent db; private final CryptoComponent crypto; private final ExecutorService dbExecutor; + private final PluginConfig pluginConfig; private final Timer timer; private final Clock clock; private final Map<ContactId, Boolean> activeContacts; @@ -47,11 +50,12 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { @Inject KeyManagerImpl(DatabaseComponent db, CryptoComponent crypto, - @DatabaseExecutor ExecutorService dbExecutor, Timer timer, - Clock clock) { + @DatabaseExecutor ExecutorService dbExecutor, + PluginConfig pluginConfig, Timer timer, Clock clock) { this.db = db; this.crypto = crypto; this.dbExecutor = dbExecutor; + this.pluginConfig = pluginConfig; this.timer = timer; this.clock = clock; // Use a ConcurrentHashMap as a thread-safe set @@ -61,21 +65,29 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { @Override public boolean start() { + Map<TransportId, Integer> transports = + new HashMap<TransportId, Integer>(); + for (SimplexPluginFactory f : pluginConfig.getSimplexFactories()) + transports.put(f.getId(), f.getMaxLatency()); + for (DuplexPluginFactory f : pluginConfig.getDuplexFactories()) + transports.put(f.getId(), f.getMaxLatency()); try { - Collection<Contact> contacts; - Map<TransportId, Integer> latencies; - Transaction txn = db.startTransaction(); + Transaction txn = db.startTransaction(false); try { - contacts = db.getContacts(txn); - latencies = db.getTransportLatencies(txn); + for (Contact c : db.getContacts(txn)) + if (c.isActive()) activeContacts.put(c.getId(), true); + for (Entry<TransportId, Integer> e : transports.entrySet()) + db.addTransport(txn, e.getKey(), e.getValue()); + for (Entry<TransportId, Integer> e : transports.entrySet()) { + TransportKeyManager m = new TransportKeyManager(db, crypto, + timer, clock, e.getKey(), e.getValue()); + managers.put(e.getKey(), m); + m.start(txn); + } txn.setComplete(); } finally { db.endTransaction(txn); } - for (Contact c : contacts) - if (c.isActive()) activeContacts.put(c.getId(), true); - for (Entry<TransportId, Integer> e : latencies.entrySet()) - addTransport(e.getKey(), e.getValue()); } catch (DbException e) { if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); return false; @@ -94,43 +106,49 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { m.addContact(txn, c, master, timestamp, alice); } - public StreamContext getStreamContext(ContactId c, TransportId t) { + public StreamContext getStreamContext(ContactId c, TransportId t) + throws DbException { // Don't allow outgoing streams to inactive contacts if (!activeContacts.containsKey(c)) return null; TransportKeyManager m = managers.get(t); - return m == null ? null : m.getStreamContext(c); + if (m == null) { + if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t); + return null; + } + StreamContext ctx = null; + Transaction txn = db.startTransaction(false); + try { + ctx = m.getStreamContext(txn, c); + txn.setComplete(); + } finally { + db.endTransaction(txn); + } + return ctx; } - public StreamContext getStreamContext(TransportId t, byte[] tag) { + public StreamContext getStreamContext(TransportId t, byte[] tag) + throws DbException { TransportKeyManager m = managers.get(t); - if (m == null) return null; - StreamContext ctx = m.getStreamContext(tag); - if (ctx == null) return null; - // Activate the contact if not already active - if (!activeContacts.containsKey(ctx.getContactId())) { - try { - Transaction txn = db.startTransaction(); - try { - db.setContactActive(txn, ctx.getContactId(), true); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return null; - } + if (m == null) { + if (LOG.isLoggable(INFO)) LOG.info("No key manager for " + t); + return null; + } + StreamContext ctx = null; + Transaction txn = db.startTransaction(false); + try { + ctx = m.getStreamContext(txn, tag); + // Activate the contact if not already active + if (ctx != null && !activeContacts.containsKey(ctx.getContactId())) + db.setContactActive(txn, ctx.getContactId(), true); + txn.setComplete(); + } finally { + db.endTransaction(txn); } return ctx; } public void eventOccurred(Event e) { - if (e instanceof TransportAddedEvent) { - TransportAddedEvent t = (TransportAddedEvent) e; - addTransport(t.getTransportId(), t.getMaxLatency()); - } else if (e instanceof TransportRemovedEvent) { - removeTransport(((TransportRemovedEvent) e).getTransportId()); - } else if (e instanceof ContactRemovedEvent) { + if (e instanceof ContactRemovedEvent) { removeContact(((ContactRemovedEvent) e).getContactId()); } else if (e instanceof ContactStatusChangedEvent) { ContactStatusChangedEvent c = (ContactStatusChangedEvent) e; @@ -139,21 +157,6 @@ class KeyManagerImpl implements KeyManager, Service, EventListener { } } - private void addTransport(final TransportId t, final int maxLatency) { - dbExecutor.execute(new Runnable() { - public void run() { - TransportKeyManager m = new TransportKeyManager(db, crypto, - timer, clock, t, maxLatency); - // Don't add transport twice if event is received during startup - if (managers.putIfAbsent(t, m) == null) m.start(); - } - }); - } - - private void removeTransport(TransportId t) { - managers.remove(t); - } - private void removeContact(final ContactId c) { activeContacts.remove(c); dbExecutor.execute(new Runnable() { diff --git a/briar-core/src/org/briarproject/transport/TransportKeyManager.java b/briar-core/src/org/briarproject/transport/TransportKeyManager.java index b8bcdfb3f99693971e0a5c37e2c991f9091d3111..0c9b95bf4679e5d6bb09f95a8b733b83dc1b605c 100644 --- a/briar-core/src/org/briarproject/transport/TransportKeyManager.java +++ b/briar-core/src/org/briarproject/transport/TransportKeyManager.java @@ -60,46 +60,20 @@ class TransportKeyManager { keys = new HashMap<ContactId, MutableTransportKeys>(); } - void start() { + void start(Transaction txn) throws DbException { long now = clock.currentTimeMillis(); lock.lock(); try { // Load the transport keys from the DB - Map<ContactId, TransportKeys> loaded; - try { - Transaction txn = db.startTransaction(); - try { - loaded = db.getTransportKeys(txn, transportId); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return; - } + Map<ContactId, TransportKeys> loaded = + db.getTransportKeys(txn, transportId); // Rotate the keys to the current rotation period - Map<ContactId, TransportKeys> rotated = - new HashMap<ContactId, TransportKeys>(); - Map<ContactId, TransportKeys> current = - new HashMap<ContactId, TransportKeys>(); - long rotationPeriod = now / rotationPeriodLength; - for (Entry<ContactId, TransportKeys> e : loaded.entrySet()) { - ContactId c = e.getKey(); - TransportKeys k = e.getValue(); - TransportKeys k1 = crypto.rotateTransportKeys(k, - rotationPeriod); - if (k1.getRotationPeriod() > k.getRotationPeriod()) - rotated.put(c, k1); - current.put(c, k1); - } + RotationResult rotationResult = rotateKeys(loaded, now); // Initialise mutable state for all contacts - for (Entry<ContactId, TransportKeys> e : current.entrySet()) - addKeys(e.getKey(), new MutableTransportKeys(e.getValue())); + addKeys(rotationResult.current); // Write any rotated keys back to the DB - updateTransportKeys(rotated); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + if (!rotationResult.rotated.isEmpty()) + db.updateTransportKeys(txn, rotationResult.rotated); } finally { lock.unlock(); } @@ -107,6 +81,27 @@ class TransportKeyManager { scheduleKeyRotation(now); } + private RotationResult rotateKeys(Map<ContactId, TransportKeys> keys, + long now) { + RotationResult rotationResult = new RotationResult(); + long rotationPeriod = now / rotationPeriodLength; + for (Entry<ContactId, TransportKeys> e : keys.entrySet()) { + ContactId c = e.getKey(); + TransportKeys k = e.getValue(); + TransportKeys k1 = crypto.rotateTransportKeys(k, rotationPeriod); + if (k1.getRotationPeriod() > k.getRotationPeriod()) + rotationResult.rotated.put(c, k1); + rotationResult.current.put(c, k1); + } + return rotationResult; + } + + // Locking: lock + private void addKeys(Map<ContactId, TransportKeys> m) { + for (Entry<ContactId, TransportKeys> e : m.entrySet()) + addKeys(e.getKey(), new MutableTransportKeys(e.getValue())); + } + // Locking: lock private void addKeys(ContactId c, MutableTransportKeys m) { encodeTags(c, m.getPreviousIncomingKeys()); @@ -126,23 +121,21 @@ class TransportKeyManager { } } - private void updateTransportKeys(Map<ContactId, TransportKeys> rotated) - throws DbException { - if (!rotated.isEmpty()) { - Transaction txn = db.startTransaction(); - try { - db.updateTransportKeys(txn, rotated); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } - } - } - private void scheduleKeyRotation(long now) { TimerTask task = new TimerTask() { public void run() { - rotateKeys(); + try { + Transaction txn = db.startTransaction(false); + try { + rotateKeys(txn); + txn.setComplete(); + } finally { + db.endTransaction(txn); + } + } catch (DbException e) { + if (LOG.isLoggable(WARNING)) + LOG.log(WARNING, e.toString(), e); + } } }; long delay = rotationPeriodLength - now % rotationPeriodLength; @@ -185,7 +178,8 @@ class TransportKeyManager { } } - StreamContext getStreamContext(ContactId c) { + StreamContext getStreamContext(Transaction txn, ContactId c) + throws DbException { lock.lock(); try { // Look up the outgoing keys for the contact @@ -198,24 +192,16 @@ class TransportKeyManager { outKeys.getStreamCounter()); // Increment the stream counter and write it back to the DB outKeys.incrementStreamCounter(); - Transaction txn = db.startTransaction(); - try { - db.incrementStreamCounter(txn, c, transportId, - outKeys.getRotationPeriod()); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } + db.incrementStreamCounter(txn, c, transportId, + outKeys.getRotationPeriod()); return ctx; - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return null; } finally { lock.unlock(); } } - StreamContext getStreamContext(byte[] tag) { + StreamContext getStreamContext(Transaction txn, byte[] tag) + throws DbException { lock.lock(); try { // Look up the incoming keys for the tag @@ -244,53 +230,33 @@ class TransportKeyManager { inContexts.remove(new Bytes(removeTag)); } // Write the window back to the DB - Transaction txn = db.startTransaction(); - try { - db.setReorderingWindow(txn, tagCtx.contactId, transportId, - inKeys.getRotationPeriod(), window.getBase(), - window.getBitmap()); - txn.setComplete(); - } finally { - db.endTransaction(txn); - } + db.setReorderingWindow(txn, tagCtx.contactId, transportId, + inKeys.getRotationPeriod(), window.getBase(), + window.getBitmap()); return ctx; - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); - return null; } finally { lock.unlock(); } } - private void rotateKeys() { + private void rotateKeys(Transaction txn) throws DbException { long now = clock.currentTimeMillis(); lock.lock(); try { // Rotate the keys to the current rotation period - Map<ContactId, TransportKeys> rotated = - new HashMap<ContactId, TransportKeys>(); - Map<ContactId, TransportKeys> current = + Map<ContactId, TransportKeys> snapshot = new HashMap<ContactId, TransportKeys>(); - long rotationPeriod = now / rotationPeriodLength; - for (Entry<ContactId, MutableTransportKeys> e : keys.entrySet()) { - ContactId c = e.getKey(); - TransportKeys k = e.getValue().snapshot(); - TransportKeys k1 = crypto.rotateTransportKeys(k, - rotationPeriod); - if (k1.getRotationPeriod() > k.getRotationPeriod()) - rotated.put(c, k1); - current.put(c, k1); - } + for (Entry<ContactId, MutableTransportKeys> e : keys.entrySet()) + snapshot.put(e.getKey(), e.getValue().snapshot()); + RotationResult rotationResult = rotateKeys(snapshot, now); // Rebuild the mutable state for all contacts inContexts.clear(); outContexts.clear(); keys.clear(); - for (Entry<ContactId, TransportKeys> e : current.entrySet()) - addKeys(e.getKey(), new MutableTransportKeys(e.getValue())); + addKeys(rotationResult.current); // Write any rotated keys back to the DB - updateTransportKeys(rotated); - } catch (DbException e) { - if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e); + if (!rotationResult.rotated.isEmpty()) + db.updateTransportKeys(txn, rotationResult.rotated); } finally { lock.unlock(); } @@ -311,4 +277,14 @@ class TransportKeyManager { this.streamNumber = streamNumber; } } + + private static class RotationResult { + + private final Map<ContactId, TransportKeys> current, rotated; + + private RotationResult() { + current = new HashMap<ContactId, TransportKeys>(); + rotated = new HashMap<ContactId, TransportKeys>(); + } + } } diff --git a/briar-desktop/src/org/briarproject/lifecycle/DesktopLifecycleModule.java b/briar-desktop/src/org/briarproject/lifecycle/DesktopLifecycleModule.java index 4986668b1e5f25af228994f5c0f14824c391bfaa..79525935a0123371418ae744006f41563c3b2394 100644 --- a/briar-desktop/src/org/briarproject/lifecycle/DesktopLifecycleModule.java +++ b/briar-desktop/src/org/briarproject/lifecycle/DesktopLifecycleModule.java @@ -1,10 +1,6 @@ package org.briarproject.lifecycle; -import org.briarproject.api.db.DatabaseComponent; -import org.briarproject.api.event.EventBus; -import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.lifecycle.ShutdownManager; -import org.briarproject.api.system.Clock; import org.briarproject.util.OsUtils; import javax.inject.Singleton; @@ -15,22 +11,10 @@ import dagger.Provides; @Module public class DesktopLifecycleModule extends LifecycleModule { - @Provides - @Singleton - LifecycleManager provideLifecycleManager(Clock clock, DatabaseComponent db, - EventBus eventBus) { - return new LifecycleManagerImpl(clock, db, eventBus); - } - @Provides @Singleton ShutdownManager provideDesktopShutdownManager() { - if (OsUtils.isWindows()) { - return new WindowsShutdownManagerImpl(); - } - else { - return new ShutdownManagerImpl(); - } + if (OsUtils.isWindows()) return new WindowsShutdownManagerImpl(); + else return new ShutdownManagerImpl(); } - } diff --git a/briar-desktop/src/org/briarproject/plugins/DesktopPluginsModule.java b/briar-desktop/src/org/briarproject/plugins/DesktopPluginsModule.java index 6d727a6d89786c273f7ee9fd58c1abf1837bb65d..912a0a7d7a1d4950f972acef29779b5e4b6f7258 100644 --- a/briar-desktop/src/org/briarproject/plugins/DesktopPluginsModule.java +++ b/briar-desktop/src/org/briarproject/plugins/DesktopPluginsModule.java @@ -3,9 +3,8 @@ package org.briarproject.plugins; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.lifecycle.ShutdownManager; import org.briarproject.api.plugins.BackoffFactory; -import org.briarproject.api.plugins.duplex.DuplexPluginConfig; +import org.briarproject.api.plugins.PluginConfig; import org.briarproject.api.plugins.duplex.DuplexPluginFactory; -import org.briarproject.api.plugins.simplex.SimplexPluginConfig; import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.reliability.ReliabilityLayerFactory; import org.briarproject.plugins.bluetooth.BluetoothPluginFactory; @@ -27,21 +26,7 @@ import dagger.Provides; public class DesktopPluginsModule extends PluginsModule { @Provides - SimplexPluginConfig getSimplexPluginConfig( - @IoExecutor Executor ioExecutor) { - SimplexPluginFactory removable = - new RemovableDrivePluginFactory(ioExecutor); - final Collection<SimplexPluginFactory> factories = - Collections.singletonList(removable); - return new SimplexPluginConfig() { - public Collection<SimplexPluginFactory> getFactories() { - return factories; - } - }; - } - - @Provides - DuplexPluginConfig getDuplexPluginConfig(@IoExecutor Executor ioExecutor, + PluginConfig getPluginConfig(@IoExecutor Executor ioExecutor, SecureRandom random, BackoffFactory backoffFactory, ReliabilityLayerFactory reliabilityFactory, ShutdownManager shutdownManager) { @@ -53,11 +38,22 @@ public class DesktopPluginsModule extends PluginsModule { backoffFactory); DuplexPluginFactory wan = new WanTcpPluginFactory(ioExecutor, backoffFactory, shutdownManager); - final Collection<DuplexPluginFactory> factories = + SimplexPluginFactory removable = + new RemovableDrivePluginFactory(ioExecutor); + final Collection<SimplexPluginFactory> simplex = + Collections.singletonList(removable); + final Collection<DuplexPluginFactory> duplex = Arrays.asList(bluetooth, modem, lan, wan); - return new DuplexPluginConfig() { - public Collection<DuplexPluginFactory> getFactories() { - return factories; + return new PluginConfig() { + + @Override + public Collection<DuplexPluginFactory> getDuplexFactories() { + return duplex; + } + + @Override + public Collection<SimplexPluginFactory> getSimplexFactories() { + return simplex; } }; } diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java index 2d7f156e22d861f777808cc98ba0fbbb69224d13..d4165bc410fbbe3ba5f6a1ff71e55a388bf8945d 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothPluginFactory.java @@ -32,6 +32,10 @@ public class BluetoothPluginFactory implements DuplexPluginFactory { return BluetoothPlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL, MAX_POLLING_INTERVAL, BACKOFF_BASE); diff --git a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java index 8f852f1ef820c87244e36f2f8b15df4f96a33e03..6139b8c14bba8b749537ed1e6533526cfaee6113 100644 --- a/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java +++ b/briar-desktop/src/org/briarproject/plugins/bluetooth/BluetoothTransportConnection.java @@ -1,5 +1,10 @@ package org.briarproject.plugins.bluetooth; +import org.briarproject.api.plugins.Plugin; +import org.briarproject.api.plugins.TransportConnectionReader; +import org.briarproject.api.plugins.TransportConnectionWriter; +import org.briarproject.api.plugins.duplex.DuplexTransportConnection; + import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -7,11 +12,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import javax.microedition.io.StreamConnection; -import org.briarproject.api.plugins.Plugin; -import org.briarproject.api.plugins.TransportConnectionReader; -import org.briarproject.api.plugins.TransportConnectionWriter; -import org.briarproject.api.plugins.duplex.DuplexTransportConnection; - class BluetoothTransportConnection implements DuplexTransportConnection { private final Plugin plugin; @@ -39,10 +39,6 @@ class BluetoothTransportConnection implements DuplexTransportConnection { private class Reader implements TransportConnectionReader { - public long getMaxLatency() { - return plugin.getMaxLatency(); - } - public InputStream getInputStream() throws IOException { return stream.openInputStream(); } diff --git a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java index f4ed1e348121584b22dcbc8f6ac21f693045608a..e2db0717d77aafdeade20519f45dbe55e8afb840 100644 --- a/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/file/RemovableDrivePluginFactory.java @@ -24,6 +24,10 @@ public class RemovableDrivePluginFactory implements SimplexPluginFactory { return RemovableDrivePlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public SimplexPlugin createPlugin(SimplexPluginCallback callback) { RemovableDriveFinder finder; RemovableDriveMonitor monitor; diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java index 954529a5e8221fa1341f7b0a7b198409e33efa19..ffa06c2a477689045735b9c1aa5cd28ebd04ae07 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPlugin.java @@ -194,10 +194,6 @@ class ModemPlugin implements DuplexPlugin, Modem.Callback { private class Reader implements TransportConnectionReader { - public long getMaxLatency() { - return ModemPlugin.this.getMaxLatency(); - } - public InputStream getInputStream() throws IOException { return modem.getInputStream(); } diff --git a/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java b/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java index 2e9561c077fa55e332c7fd4d9d24de706aed6ba0..690b3c7d78f6f603a400bd690a1c92464b263215 100644 --- a/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java +++ b/briar-desktop/src/org/briarproject/plugins/modem/ModemPluginFactory.java @@ -1,7 +1,5 @@ package org.briarproject.plugins.modem; -import java.util.concurrent.Executor; - import org.briarproject.api.TransportId; import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPluginCallback; @@ -9,6 +7,8 @@ import org.briarproject.api.plugins.duplex.DuplexPluginFactory; import org.briarproject.api.reliability.ReliabilityLayerFactory; import org.briarproject.util.StringUtils; +import java.util.concurrent.Executor; + public class ModemPluginFactory implements DuplexPluginFactory { private static final int MAX_LATENCY = 30 * 1000; // 30 seconds @@ -26,6 +26,10 @@ public class ModemPluginFactory implements DuplexPluginFactory { return ModemPlugin.ID; } + public int getMaxLatency() { + return MAX_LATENCY; + } + public DuplexPlugin createPlugin(DuplexPluginCallback callback) { // This plugin is not enabled by default String enabled = callback.getSettings().get("enabled"); diff --git a/briar-tests/src/org/briarproject/TestPluginsModule.java b/briar-tests/src/org/briarproject/TestPluginsModule.java new file mode 100644 index 0000000000000000000000000000000000000000..b7cf4209ee34199b051b1bc2e61c95d308291c43 --- /dev/null +++ b/briar-tests/src/org/briarproject/TestPluginsModule.java @@ -0,0 +1,55 @@ +package org.briarproject; + +import org.briarproject.api.TransportId; +import org.briarproject.api.plugins.PluginConfig; +import org.briarproject.api.plugins.duplex.DuplexPluginFactory; +import org.briarproject.api.plugins.simplex.SimplexPlugin; +import org.briarproject.api.plugins.simplex.SimplexPluginCallback; +import org.briarproject.api.plugins.simplex.SimplexPluginFactory; + +import java.util.Collection; +import java.util.Collections; + +import dagger.Module; +import dagger.Provides; + +@Module +public class TestPluginsModule { + + public static final TransportId TRANSPORT_ID = new TransportId("id"); + public static final int MAX_LATENCY = 2 * 60 * 1000; // 2 minutes + + private final SimplexPluginFactory simplex = new SimplexPluginFactory() { + + @Override + public TransportId getId() { + return TRANSPORT_ID; + } + + @Override + public int getMaxLatency() { + return MAX_LATENCY; + } + + @Override + public SimplexPlugin createPlugin(SimplexPluginCallback callback) { + return null; + } + }; + + @Provides + PluginConfig providePluginConfig() { + return new PluginConfig() { + + @Override + public Collection<DuplexPluginFactory> getDuplexFactories() { + return Collections.emptyList(); + } + + @Override + public Collection<SimplexPluginFactory> getSimplexFactories() { + return Collections.singletonList(simplex); + } + }; + } +} diff --git a/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java b/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java index 3cbed06cb9c4ab6835d62355ca739d1cf54bfdff..cf816fd88e4614430de2bc34a99a56a08b6918b0 100644 --- a/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java +++ b/briar-tests/src/org/briarproject/clients/MessageQueueManagerImplTest.java @@ -56,7 +56,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase { context.mock(QueueMessageFactory.class); final ValidationManager validationManager = context.mock(ValidationManager.class); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); final byte[] body = new byte[123]; final Metadata groupMetadata = new Metadata(); final Metadata messageMetadata = new Metadata(); @@ -249,7 +249,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase { new AtomicReference<IncomingMessageHook>(); final IncomingQueueMessageHook incomingQueueMessageHook = context.mock(IncomingQueueMessageHook.class); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); final Metadata groupMetadata = new Metadata(); final byte[] queueState = new byte[123]; groupMetadata.put(QUEUE_STATE_KEY, queueState); @@ -300,7 +300,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase { new AtomicReference<IncomingMessageHook>(); final IncomingQueueMessageHook incomingQueueMessageHook = context.mock(IncomingQueueMessageHook.class); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); final Metadata groupMetadata = new Metadata(); final byte[] queueState = new byte[123]; groupMetadata.put(QUEUE_STATE_KEY, queueState); @@ -355,7 +355,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase { new AtomicReference<IncomingMessageHook>(); final IncomingQueueMessageHook incomingQueueMessageHook = context.mock(IncomingQueueMessageHook.class); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); final Metadata groupMetadata = new Metadata(); final byte[] queueState = new byte[123]; groupMetadata.put(QUEUE_STATE_KEY, queueState); @@ -412,7 +412,7 @@ public class MessageQueueManagerImplTest extends BriarTestCase { new AtomicReference<IncomingMessageHook>(); final IncomingQueueMessageHook incomingQueueMessageHook = context.mock(IncomingQueueMessageHook.class); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); final Metadata groupMetadata = new Metadata(); final byte[] queueState = new byte[123]; groupMetadata.put(QUEUE_STATE_KEY, queueState); diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java index 4049a4091db098696bf672b5b4a6fdffbb343f79..02531d08d1165f34c1aaeea85ece32a9fd43cbeb 100644 --- a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java +++ b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java @@ -192,7 +192,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { shutdown); assertFalse(db.open()); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.addLocalAuthor(transaction, localAuthor); assertEquals(contactId, @@ -233,7 +233,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.addLocalMessage(transaction, message, clientId, metadata, true); fail(); @@ -276,7 +276,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.addLocalMessage(transaction, message, clientId, metadata, true); transaction.setComplete(); @@ -306,7 +306,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.addTransportKeys(transaction, contactId, createTransportKeys()); fail(); @@ -316,7 +316,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.generateAck(transaction, contactId, 123); fail(); @@ -326,7 +326,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.generateBatch(transaction, contactId, 123, 456); fail(); @@ -336,7 +336,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.generateOffer(transaction, contactId, 123, 456); fail(); @@ -346,7 +346,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.generateRequest(transaction, contactId, 123); fail(); @@ -356,7 +356,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getContact(transaction, contactId); fail(); @@ -366,7 +366,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getMessageStatus(transaction, contactId, groupId); fail(); @@ -376,7 +376,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getMessageStatus(transaction, contactId, messageId); fail(); @@ -386,7 +386,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.incrementStreamCounter(transaction, contactId, transportId, 0); fail(); @@ -396,7 +396,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.isVisibleToContact(transaction, contactId, groupId); fail(); @@ -406,7 +406,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { Ack a = new Ack(Collections.singletonList(messageId)); db.receiveAck(transaction, contactId, a); @@ -417,7 +417,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.receiveMessage(transaction, contactId, message); fail(); @@ -427,7 +427,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { Offer o = new Offer(Collections.singletonList(messageId)); db.receiveOffer(transaction, contactId, o); @@ -438,7 +438,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { Request r = new Request(Collections.singletonList(messageId)); db.receiveRequest(transaction, contactId, r); @@ -449,7 +449,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.removeContact(transaction, contactId); fail(); @@ -459,7 +459,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.setContactActive(transaction, contactId, true); fail(); @@ -469,7 +469,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.setReorderingWindow(transaction, contactId, transportId, 0, 0, new byte[REORDERING_WINDOW_SIZE / 8]); @@ -480,7 +480,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.setVisibleToContact(transaction, contactId, groupId, true); fail(); @@ -512,7 +512,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.addContact(transaction, author, localAuthorId, true); fail(); @@ -522,7 +522,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getLocalAuthor(transaction, localAuthorId); fail(); @@ -532,7 +532,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.removeLocalAuthor(transaction, localAuthorId); fail(); @@ -568,7 +568,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.getGroup(transaction, groupId); fail(); @@ -578,7 +578,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getGroupMetadata(transaction, groupId); fail(); @@ -588,7 +588,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getMessageStatus(transaction, contactId, groupId); fail(); @@ -598,7 +598,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.isVisibleToContact(transaction, contactId, groupId); fail(); @@ -608,7 +608,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.mergeGroupMetadata(transaction, groupId, metadata); fail(); @@ -618,7 +618,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.removeGroup(transaction, group); fail(); @@ -628,7 +628,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.setVisibleToContact(transaction, contactId, groupId, true); fail(); @@ -663,7 +663,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.deleteMessage(transaction, messageId); fail(); @@ -673,7 +673,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.deleteMessageMetadata(transaction, messageId); fail(); @@ -683,7 +683,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getRawMessage(transaction, messageId); fail(); @@ -693,7 +693,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getMessageMetadata(transaction, messageId); fail(); @@ -703,7 +703,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getMessageStatus(transaction, contactId, messageId); fail(); @@ -713,7 +713,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.mergeMessageMetadata(transaction, messageId, metadata); fail(); @@ -723,7 +723,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.setMessageShared(transaction, message, true); fail(); @@ -733,7 +733,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.setMessageValid(transaction, message, clientId, true); fail(); @@ -787,7 +787,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.addLocalAuthor(transaction, localAuthor); assertEquals(contactId, @@ -797,7 +797,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.getTransportKeys(transaction, transportId); fail(); @@ -807,7 +807,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.incrementStreamCounter(transaction, contactId, transportId, 0); fail(); @@ -817,7 +817,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.removeTransport(transaction, transportId); fail(); @@ -827,7 +827,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } - transaction = db.startTransaction(); + transaction = db.startTransaction(false); try { db.setReorderingWindow(transaction, contactId, transportId, 0, 0, new byte[REORDERING_WINDOW_SIZE / 8]); @@ -863,7 +863,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { Ack a = db.generateAck(transaction, contactId, 123); assertEquals(messagesToAck, a.getMessageIds()); @@ -907,7 +907,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { assertEquals(messages, db.generateBatch(transaction, contactId, size * 2, maxLatency)); @@ -944,7 +944,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { Offer o = db.generateOffer(transaction, contactId, 123, maxLatency); assertEquals(ids, o.getMessageIds()); @@ -978,7 +978,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { Request r = db.generateRequest(transaction, contactId, 123); assertEquals(ids, r.getMessageIds()); @@ -1023,7 +1023,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { assertEquals(messages, db.generateRequestedBatch(transaction, contactId, size * 2, maxLatency)); @@ -1056,7 +1056,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { Ack a = new Ack(Collections.singletonList(messageId)); db.receiveAck(transaction, contactId, a); @@ -1099,7 +1099,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.receiveMessage(transaction, contactId, message); transaction.setComplete(); @@ -1135,7 +1135,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.receiveMessage(transaction, contactId, message); transaction.setComplete(); @@ -1165,7 +1165,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.receiveMessage(transaction, contactId, message); transaction.setComplete(); @@ -1217,7 +1217,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { Offer o = new Offer(Arrays.asList(messageId, messageId1, messageId2, messageId3)); @@ -1252,7 +1252,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { Request r = new Request(Collections.singletonList(messageId)); db.receiveRequest(transaction, contactId, r); @@ -1293,7 +1293,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.setVisibleToContact(transaction, contactId, groupId, true); transaction.setComplete(); @@ -1326,7 +1326,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.setVisibleToContact(transaction, contactId, groupId, true); transaction.setComplete(); @@ -1368,7 +1368,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { db.updateTransportKeys(transaction, keys); assertEquals(keys, db.getTransportKeys(transaction, transportId)); @@ -1434,7 +1434,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); - Transaction transaction = db.startTransaction(); + Transaction transaction = db.startTransaction(false); try { // First merge should broadcast an event db.mergeSettings(transaction, update, "namespace"); diff --git a/briar-tests/src/org/briarproject/db/TransactionIsolationTest.java b/briar-tests/src/org/briarproject/db/TransactionIsolationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b01f5770a9413b9a2f0508a1b6e57aa05a37ff03 --- /dev/null +++ b/briar-tests/src/org/briarproject/db/TransactionIsolationTest.java @@ -0,0 +1,277 @@ +package org.briarproject.db; + +import org.briarproject.BriarTestCase; +import org.briarproject.TestUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import java.io.File; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class TransactionIsolationTest extends BriarTestCase { + + private static final String DROP_TABLE = "DROP TABLE foo IF EXISTS"; + private static final String CREATE_TABLE = "CREATE TABLE foo" + + " (key INT NOT NULL," + + " counter INT NOT NULL)"; + private static final String INSERT_ROW = + "INSERT INTO foo (key, counter) VALUES (1, 123)"; + private static final String GET_COUNTER = + "SELECT counter FROM foo WHERE key = 1"; + private static final String SET_COUNTER = + "UPDATE foo SET counter = ? WHERE key = 1"; + + private final File testDir = TestUtils.getTestDirectory(); + private final File db = new File(testDir, "db"); + private final String withMvcc = "jdbc:h2:" + db.getAbsolutePath() + + ";MV_STORE=TRUE;MVCC=TRUE"; + private final String withoutMvcc = "jdbc:h2:" + db.getAbsolutePath() + + ";MV_STORE=FALSE;MVCC=FALSE;LOCK_MODE=1"; + + @Before + public void setUp() throws Exception { + assertTrue(testDir.mkdirs()); + Class.forName("org.h2.Driver"); + } + + @After + public void tearDown() throws Exception { + TestUtils.deleteTestDirectory(testDir); + } + + @Test + public void testDoesNotReadUncommittedWritesWithMvcc() throws Exception { + Connection connection = openConnection(true); + try { + createTableAndInsertRow(connection); + } finally { + connection.close(); + } + // Start the first transaction + Connection txn1 = openConnection(true); + try { + txn1.setAutoCommit(false); + // The first transaction should read the initial value + assertEquals(123, getCounter(txn1)); + // The first transaction updates the value but doesn't commit it + assertEquals(1, setCounter(txn1, 234)); + // Start the second transaction + Connection txn2 = openConnection(true); + try { + txn2.setAutoCommit(false); + // The second transaction should still read the initial value + assertEquals(123, getCounter(txn2)); + // Commit the second transaction + txn2.commit(); + } finally { + txn2.close(); + } + // Commit the first transaction + txn1.commit(); + } finally { + txn1.close(); + } + } + + @Test + public void testLastWriterWinsWithMvcc() throws Exception { + Connection connection = openConnection(true); + try { + createTableAndInsertRow(connection); + } finally { + connection.close(); + } + // Start the first transaction + Connection txn1 = openConnection(true); + try { + txn1.setAutoCommit(false); + // The first transaction should read the initial value + assertEquals(123, getCounter(txn1)); + // The first transaction updates the value but doesn't commit it + assertEquals(1, setCounter(txn1, 234)); + // Start the second transaction + Connection txn2 = openConnection(true); + try { + txn2.setAutoCommit(false); + // The second transaction should still read the initial value + assertEquals(123, getCounter(txn2)); + // Commit the first transaction + txn1.commit(); + // The second transaction updates the value + assertEquals(1, setCounter(txn2, 345)); + // Commit the second transaction + txn2.commit(); + } finally { + txn2.close(); + } + } finally { + txn1.close(); + } + // The second transaction was the last writer, so it should win + connection = openConnection(true); + try { + assertEquals(345, getCounter(connection)); + } finally { + connection.close(); + } + } + + @Test + public void testLockTimeoutOnRowWithMvcc() throws Exception { + Connection connection = openConnection(true); + try { + createTableAndInsertRow(connection); + } finally { + connection.close(); + } + // Start the first transaction + Connection txn1 = openConnection(true); + try { + txn1.setAutoCommit(false); + // The first transaction should read the initial value + assertEquals(123, getCounter(txn1)); + // Start the second transaction + Connection txn2 = openConnection(true); + try { + txn2.setAutoCommit(false); + // The second transaction should read the initial value + assertEquals(123, getCounter(txn2)); + // The first transaction updates the value but doesn't commit it + assertEquals(1, setCounter(txn1, 234)); + // The second transaction tries to update the value + try { + setCounter(txn2, 345); + fail(); + } catch (SQLException expected) { + // Expected: the row is locked by the first transaction + } + // Abort the transactions + txn1.rollback(); + txn2.rollback(); + } finally { + txn2.close(); + } + } finally { + txn1.close(); + } + } + + @Test + public void testReadLockTimeoutOnTableWithoutMvcc() throws Exception { + Connection connection = openConnection(false); + try { + createTableAndInsertRow(connection); + } finally { + connection.close(); + } + // Start the first transaction + Connection txn1 = openConnection(false); + try { + txn1.setAutoCommit(false); + // The first transaction should read the initial value + assertEquals(123, getCounter(txn1)); + // Start the second transaction + Connection txn2 = openConnection(false); + try { + txn2.setAutoCommit(false); + // The second transaction should read the initial value + assertEquals(123, getCounter(txn2)); + // The first transaction tries to update the value + try { + setCounter(txn1, 345); + fail(); + } catch (SQLException expected) { + // Expected: the table is locked by the second transaction + } + // Abort the transactions + txn1.rollback(); + txn2.rollback(); + } finally { + txn2.close(); + } + } finally { + txn1.close(); + } + } + + @Test + public void testWriteLockTimeoutOnTableWithoutMvcc() throws Exception { + Connection connection = openConnection(false); + try { + createTableAndInsertRow(connection); + } finally { + connection.close(); + } + // Start the first transaction + Connection txn1 = openConnection(false); + try { + txn1.setAutoCommit(false); + // The first transaction should read the initial value + assertEquals(123, getCounter(txn1)); + // The first transaction updates the value but doesn't commit yet + assertEquals(1, setCounter(txn1, 345)); + // Start the second transaction + Connection txn2 = openConnection(false); + try { + txn2.setAutoCommit(false); + // The second transaction tries to read the value + try { + getCounter(txn2); + fail(); + } catch (SQLException expected) { + // Expected: the table is locked by the first transaction + } + // Abort the transactions + txn1.rollback(); + txn2.rollback(); + } finally { + txn2.close(); + } + } finally { + txn1.close(); + } + } + + private Connection openConnection(boolean mvcc) throws SQLException { + return DriverManager.getConnection(mvcc ? withMvcc : withoutMvcc); + } + + private void createTableAndInsertRow(Connection c) throws SQLException { + Statement s = c.createStatement(); + s.executeUpdate(DROP_TABLE); + s.executeUpdate(CREATE_TABLE); + s.executeUpdate(INSERT_ROW); + s.close(); + } + + private int getCounter(Connection c) throws SQLException { + Statement s = c.createStatement(); + ResultSet rs = s.executeQuery(GET_COUNTER); + assertTrue(rs.next()); + int counter = rs.getInt(1); + assertFalse(rs.next()); + rs.close(); + s.close(); + return counter; + } + + private int setCounter(Connection c, int counter) + throws SQLException { + PreparedStatement ps = c.prepareStatement(SET_COUNTER); + ps.setInt(1, counter); + int rowsAffected = ps.executeUpdate(); + ps.close(); + return rowsAffected; + } +} diff --git a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java index 52b5b5448a30a545c4e8db25c68206aeb91ca9b7..2d2ea5ce2ce61e9547d46b7fa15e1f0bdb08e8b7 100644 --- a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java +++ b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java @@ -2,23 +2,18 @@ package org.briarproject.plugins; import org.briarproject.BriarTestCase; import org.briarproject.api.TransportId; -import org.briarproject.api.db.DatabaseComponent; -import org.briarproject.api.db.Transaction; import org.briarproject.api.event.EventBus; import org.briarproject.api.plugins.ConnectionManager; +import org.briarproject.api.plugins.PluginConfig; import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPluginCallback; -import org.briarproject.api.plugins.duplex.DuplexPluginConfig; import org.briarproject.api.plugins.duplex.DuplexPluginFactory; import org.briarproject.api.plugins.simplex.SimplexPlugin; import org.briarproject.api.plugins.simplex.SimplexPluginCallback; -import org.briarproject.api.plugins.simplex.SimplexPluginConfig; import org.briarproject.api.plugins.simplex.SimplexPluginFactory; import org.briarproject.api.properties.TransportPropertyManager; import org.briarproject.api.settings.SettingsManager; -import org.briarproject.api.system.Clock; import org.briarproject.api.ui.UiCallback; -import org.briarproject.system.SystemClock; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.lib.concurrent.Synchroniser; @@ -34,17 +29,12 @@ public class PluginManagerImplTest extends BriarTestCase { @Test public void testStartAndStop() throws Exception { - Clock clock = new SystemClock(); Mockery context = new Mockery() {{ setThreadingPolicy(new Synchroniser()); }}; final Executor ioExecutor = Executors.newSingleThreadExecutor(); final EventBus eventBus = context.mock(EventBus.class); - final SimplexPluginConfig simplexPluginConfig = - context.mock(SimplexPluginConfig.class); - final DuplexPluginConfig duplexPluginConfig = - context.mock(DuplexPluginConfig.class); - final DatabaseComponent db = context.mock(DatabaseComponent.class); + final PluginConfig pluginConfig = context.mock(PluginConfig.class); final Poller poller = context.mock(Poller.class); final ConnectionManager connectionManager = context.mock(ConnectionManager.class); @@ -53,33 +43,30 @@ public class PluginManagerImplTest extends BriarTestCase { final TransportPropertyManager transportPropertyManager = context.mock(TransportPropertyManager.class); final UiCallback uiCallback = context.mock(UiCallback.class); + // Two simplex plugin factories: both create plugins, one fails to start final SimplexPluginFactory simplexFactory = context.mock(SimplexPluginFactory.class); final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class); final TransportId simplexId = new TransportId("simplex"); - final int simplexLatency = 12345; - final Transaction simplexTxn = new Transaction(null); final SimplexPluginFactory simplexFailFactory = context.mock(SimplexPluginFactory.class, "simplexFailFactory"); final SimplexPlugin simplexFailPlugin = context.mock(SimplexPlugin.class, "simplexFailPlugin"); final TransportId simplexFailId = new TransportId("simplex1"); - final int simplexFailLatency = 23456; - final Transaction simplexFailTxn = new Transaction(null); + // Two duplex plugin factories: one creates a plugin, the other fails final DuplexPluginFactory duplexFactory = context.mock(DuplexPluginFactory.class); final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class); final TransportId duplexId = new TransportId("duplex"); - final int duplexLatency = 34567; - final Transaction duplexTxn = new Transaction(null); final DuplexPluginFactory duplexFailFactory = context.mock(DuplexPluginFactory.class, "duplexFailFactory"); final TransportId duplexFailId = new TransportId("duplex1"); + context.checking(new Expectations() {{ // First simplex plugin - oneOf(simplexPluginConfig).getFactories(); + oneOf(pluginConfig).getSimplexFactories(); will(returnValue(Arrays.asList(simplexFactory, simplexFailFactory))); oneOf(simplexFactory).getId(); @@ -87,12 +74,6 @@ public class PluginManagerImplTest extends BriarTestCase { oneOf(simplexFactory).createPlugin(with(any( SimplexPluginCallback.class))); will(returnValue(simplexPlugin)); // Created - oneOf(simplexPlugin).getMaxLatency(); - will(returnValue(simplexLatency)); - oneOf(db).startTransaction(); - will(returnValue(simplexTxn)); - oneOf(db).addTransport(simplexTxn, simplexId, simplexLatency); - oneOf(db).endTransaction(simplexTxn); oneOf(simplexPlugin).start(); will(returnValue(true)); // Started oneOf(simplexPlugin).shouldPoll(); @@ -104,29 +85,16 @@ public class PluginManagerImplTest extends BriarTestCase { oneOf(simplexFailFactory).createPlugin(with(any( SimplexPluginCallback.class))); will(returnValue(simplexFailPlugin)); // Created - oneOf(simplexFailPlugin).getMaxLatency(); - will(returnValue(simplexFailLatency)); - oneOf(db).startTransaction(); - will(returnValue(simplexFailTxn)); - oneOf(db).addTransport(simplexFailTxn, simplexFailId, - simplexFailLatency); - oneOf(db).endTransaction(simplexFailTxn); oneOf(simplexFailPlugin).start(); will(returnValue(false)); // Failed to start // First duplex plugin - oneOf(duplexPluginConfig).getFactories(); + oneOf(pluginConfig).getDuplexFactories(); will(returnValue(Arrays.asList(duplexFactory, duplexFailFactory))); oneOf(duplexFactory).getId(); will(returnValue(duplexId)); oneOf(duplexFactory).createPlugin(with(any( DuplexPluginCallback.class))); will(returnValue(duplexPlugin)); // Created - oneOf(duplexPlugin).getMaxLatency(); - will(returnValue(duplexLatency)); - oneOf(db).startTransaction(); - will(returnValue(duplexTxn)); - oneOf(db).addTransport(duplexTxn, duplexId, duplexLatency); - oneOf(db).endTransaction(duplexTxn); oneOf(duplexPlugin).start(); will(returnValue(true)); // Started oneOf(duplexPlugin).shouldPoll(); @@ -143,14 +111,15 @@ public class PluginManagerImplTest extends BriarTestCase { oneOf(simplexPlugin).stop(); oneOf(duplexPlugin).stop(); }}); + PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus, - simplexPluginConfig, duplexPluginConfig, clock, db, poller, - connectionManager, settingsManager, transportPropertyManager, - uiCallback); + pluginConfig, poller, connectionManager, settingsManager, + transportPropertyManager, uiCallback); // Two plugins should be started and stopped assertTrue(p.start()); assertTrue(p.stop()); + context.assertIsSatisfied(); } } diff --git a/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java b/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java index a62b7add1271d904c284c2af23d5313448a9a824..57e6eb2fe54c29f6184506ae34cd03249c4df35f 100644 --- a/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java +++ b/briar-tests/src/org/briarproject/sync/SimplexOutgoingSessionTest.java @@ -3,7 +3,6 @@ package org.briarproject.sync; import org.briarproject.BriarTestCase; import org.briarproject.ImmediateExecutor; import org.briarproject.TestUtils; -import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DatabaseComponent; import org.briarproject.api.db.Transaction; @@ -28,7 +27,6 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { private final Executor dbExecutor; private final EventBus eventBus; private final ContactId contactId; - private final TransportId transportId; private final MessageId messageId; private final int maxLatency; private final PacketWriter packetWriter; @@ -40,7 +38,6 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { eventBus = context.mock(EventBus.class); packetWriter = context.mock(PacketWriter.class); contactId = new ContactId(234); - transportId = new TransportId("id"); messageId = new MessageId(TestUtils.getRandomId()); maxLatency = Integer.MAX_VALUE; } @@ -48,21 +45,21 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { @Test public void testNothingToSend() throws Exception { final SimplexOutgoingSession session = new SimplexOutgoingSession(db, - dbExecutor, eventBus, contactId, transportId, maxLatency, - packetWriter); - final Transaction noAckTxn = new Transaction(null); - final Transaction noMsgTxn = new Transaction(null); + dbExecutor, eventBus, contactId, maxLatency, packetWriter); + final Transaction noAckTxn = new Transaction(null, false); + final Transaction noMsgTxn = new Transaction(null, false); + context.checking(new Expectations() {{ // Add listener oneOf(eventBus).addListener(session); // No acks to send - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(noAckTxn)); oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS); will(returnValue(null)); oneOf(db).endTransaction(noAckTxn); // No messages to send - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(noMsgTxn)); oneOf(db).generateBatch(with(noMsgTxn), with(contactId), with(any(int.class)), with(maxLatency)); @@ -73,7 +70,9 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { // Remove listener oneOf(eventBus).removeListener(session); }}); + session.run(); + context.assertIsSatisfied(); } @@ -82,24 +81,24 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { final Ack ack = new Ack(Collections.singletonList(messageId)); final byte[] raw = new byte[1234]; final SimplexOutgoingSession session = new SimplexOutgoingSession(db, - dbExecutor, eventBus, contactId, transportId, maxLatency, - packetWriter); - final Transaction ackTxn = new Transaction(null); - final Transaction noAckTxn = new Transaction(null); - final Transaction msgTxn = new Transaction(null); - final Transaction noMsgTxn = new Transaction(null); + dbExecutor, eventBus, contactId, maxLatency, packetWriter); + final Transaction ackTxn = new Transaction(null, false); + final Transaction noAckTxn = new Transaction(null, false); + final Transaction msgTxn = new Transaction(null, false); + final Transaction noMsgTxn = new Transaction(null, false); + context.checking(new Expectations() {{ // Add listener oneOf(eventBus).addListener(session); // One ack to send - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(ackTxn)); oneOf(db).generateAck(ackTxn, contactId, MAX_MESSAGE_IDS); will(returnValue(ack)); oneOf(db).endTransaction(ackTxn); oneOf(packetWriter).writeAck(ack); // One message to send - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(msgTxn)); oneOf(db).generateBatch(with(msgTxn), with(contactId), with(any(int.class)), with(maxLatency)); @@ -107,13 +106,13 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { oneOf(db).endTransaction(msgTxn); oneOf(packetWriter).writeMessage(raw); // No more acks - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(noAckTxn)); oneOf(db).generateAck(noAckTxn, contactId, MAX_MESSAGE_IDS); will(returnValue(null)); oneOf(db).endTransaction(noAckTxn); // No more messages - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(noMsgTxn)); oneOf(db).generateBatch(with(noMsgTxn), with(contactId), with(any(int.class)), with(maxLatency)); @@ -124,7 +123,9 @@ public class SimplexOutgoingSessionTest extends BriarTestCase { // Remove listener oneOf(eventBus).removeListener(session); }}); + session.run(); + context.assertIsSatisfied(); } } diff --git a/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java b/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java index d883a1ef20f746256b698972bd0a450cbf837ca3..561bb26ce4d6f6cfcdc8fc29eb37bc2240dd544a 100644 --- a/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java +++ b/briar-tests/src/org/briarproject/sync/ValidationManagerImplTest.java @@ -58,20 +58,20 @@ public class ValidationManagerImplTest extends BriarTestCase { final MessageValidator validator = context.mock(MessageValidator.class); final IncomingMessageHook hook = context.mock(IncomingMessageHook.class); - final Transaction txn = new Transaction(null); - final Transaction txn1 = new Transaction(null); - final Transaction txn2 = new Transaction(null); - final Transaction txn3 = new Transaction(null); - final Transaction txn4 = new Transaction(null); + final Transaction txn = new Transaction(null, false); + final Transaction txn1 = new Transaction(null, false); + final Transaction txn2 = new Transaction(null, false); + final Transaction txn3 = new Transaction(null, false); + final Transaction txn4 = new Transaction(null, false); context.checking(new Expectations() {{ // Get messages to validate - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn)); oneOf(db).getMessagesToValidate(txn, clientId); will(returnValue(Arrays.asList(messageId, messageId1))); oneOf(db).endTransaction(txn); // Load the first raw message and group - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn1)); oneOf(db).getRawMessage(txn1, messageId); will(returnValue(raw)); @@ -82,7 +82,7 @@ public class ValidationManagerImplTest extends BriarTestCase { oneOf(validator).validateMessage(message, group); will(returnValue(metadata)); // Store the validation result for the first message - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(txn2)); oneOf(db).mergeMessageMetadata(txn2, messageId, metadata); oneOf(db).setMessageValid(txn2, message, clientId, true); @@ -91,7 +91,7 @@ public class ValidationManagerImplTest extends BriarTestCase { oneOf(hook).incomingMessage(txn2, message, metadata); oneOf(db).endTransaction(txn2); // Load the second raw message and group - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn3)); oneOf(db).getRawMessage(txn3, messageId1); will(returnValue(raw)); @@ -102,7 +102,7 @@ public class ValidationManagerImplTest extends BriarTestCase { oneOf(validator).validateMessage(message1, group); will(returnValue(null)); // Store the validation result for the second message - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(txn4)); oneOf(db).setMessageValid(txn4, message1, clientId, false); oneOf(db).endTransaction(txn4); @@ -127,25 +127,25 @@ public class ValidationManagerImplTest extends BriarTestCase { final MessageValidator validator = context.mock(MessageValidator.class); final IncomingMessageHook hook = context.mock(IncomingMessageHook.class); - final Transaction txn = new Transaction(null); - final Transaction txn1 = new Transaction(null); - final Transaction txn2 = new Transaction(null); - final Transaction txn3 = new Transaction(null); + final Transaction txn = new Transaction(null, true); + final Transaction txn1 = new Transaction(null, true); + final Transaction txn2 = new Transaction(null, true); + final Transaction txn3 = new Transaction(null, false); context.checking(new Expectations() {{ // Get messages to validate - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn)); oneOf(db).getMessagesToValidate(txn, clientId); will(returnValue(Arrays.asList(messageId, messageId1))); oneOf(db).endTransaction(txn); // Load the first raw message - *gasp* it's gone! - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn1)); oneOf(db).getRawMessage(txn1, messageId); will(throwException(new NoSuchMessageException())); oneOf(db).endTransaction(txn1); // Load the second raw message and group - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn2)); oneOf(db).getRawMessage(txn2, messageId1); will(returnValue(raw)); @@ -156,7 +156,7 @@ public class ValidationManagerImplTest extends BriarTestCase { oneOf(validator).validateMessage(message1, group); will(returnValue(null)); // Store the validation result for the second message - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(txn3)); oneOf(db).setMessageValid(txn3, message1, clientId, false); oneOf(db).endTransaction(txn3); @@ -181,19 +181,19 @@ public class ValidationManagerImplTest extends BriarTestCase { final MessageValidator validator = context.mock(MessageValidator.class); final IncomingMessageHook hook = context.mock(IncomingMessageHook.class); - final Transaction txn = new Transaction(null); - final Transaction txn1 = new Transaction(null); - final Transaction txn2 = new Transaction(null); - final Transaction txn3 = new Transaction(null); + final Transaction txn = new Transaction(null, true); + final Transaction txn1 = new Transaction(null, true); + final Transaction txn2 = new Transaction(null, true); + final Transaction txn3 = new Transaction(null, false); context.checking(new Expectations() {{ // Get messages to validate - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn)); oneOf(db).getMessagesToValidate(txn, clientId); will(returnValue(Arrays.asList(messageId, messageId1))); oneOf(db).endTransaction(txn); // Load the first raw message - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn1)); oneOf(db).getRawMessage(txn1, messageId); will(returnValue(raw)); @@ -202,7 +202,7 @@ public class ValidationManagerImplTest extends BriarTestCase { will(throwException(new NoSuchGroupException())); oneOf(db).endTransaction(txn1); // Load the second raw message and group - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn2)); oneOf(db).getRawMessage(txn2, messageId1); will(returnValue(raw)); @@ -213,7 +213,7 @@ public class ValidationManagerImplTest extends BriarTestCase { oneOf(validator).validateMessage(message1, group); will(returnValue(null)); // Store the validation result for the second message - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(txn3)); oneOf(db).setMessageValid(txn3, message1, clientId, false); oneOf(db).endTransaction(txn3); @@ -237,11 +237,11 @@ public class ValidationManagerImplTest extends BriarTestCase { final MessageValidator validator = context.mock(MessageValidator.class); final IncomingMessageHook hook = context.mock(IncomingMessageHook.class); - final Transaction txn = new Transaction(null); - final Transaction txn1 = new Transaction(null); + final Transaction txn = new Transaction(null, true); + final Transaction txn1 = new Transaction(null, false); context.checking(new Expectations() {{ // Load the group - oneOf(db).startTransaction(); + oneOf(db).startTransaction(true); will(returnValue(txn)); oneOf(db).getGroup(txn, groupId); will(returnValue(group)); @@ -250,7 +250,7 @@ public class ValidationManagerImplTest extends BriarTestCase { oneOf(validator).validateMessage(message, group); will(returnValue(metadata)); // Store the validation result - oneOf(db).startTransaction(); + oneOf(db).startTransaction(false); will(returnValue(txn1)); oneOf(db).mergeMessageMetadata(txn1, messageId, metadata); oneOf(db).setMessageValid(txn1, message, clientId, true); diff --git a/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java b/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java index 148262b27557af93fd8a541db9d881002d8a5e46..7fdfbcf7b3a1aeb30fc0a77b076cc1575487c393 100644 --- a/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java +++ b/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java @@ -37,6 +37,7 @@ import static org.briarproject.util.ByteUtils.MAX_32_BIT_UNSIGNED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; public class TransportKeyManagerTest extends BriarTestCase { @@ -57,7 +58,7 @@ public class TransportKeyManagerTest extends BriarTestCase { final CryptoComponent crypto = context.mock(CryptoComponent.class); final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); - final Transaction txn = new Transaction(null); + final Map<ContactId, TransportKeys> loaded = new LinkedHashMap<ContactId, TransportKeys>(); final TransportKeys shouldRotate = createTransportKeys(900, 0); @@ -65,17 +66,15 @@ public class TransportKeyManagerTest extends BriarTestCase { loaded.put(contactId, shouldRotate); loaded.put(contactId1, shouldNotRotate); final TransportKeys rotated = createTransportKeys(1000, 0); - final Transaction txn1 = new Transaction(null); + final Transaction txn = new Transaction(null, false); + context.checking(new Expectations() {{ // Get the current time (1 ms after start of rotation period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1000 + 1)); // Load the transport keys - oneOf(db).startTransaction(); - will(returnValue(txn)); oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); - oneOf(db).endTransaction(txn); // Rotate the transport keys oneOf(crypto).rotateTransportKeys(shouldRotate, 1000); will(returnValue(rotated)); @@ -88,11 +87,8 @@ public class TransportKeyManagerTest extends BriarTestCase { will(new EncodeTagAction()); } // Save the keys that were rotated - oneOf(db).startTransaction(); - will(returnValue(txn1)); - oneOf(db).updateTransportKeys(txn1, + oneOf(db).updateTransportKeys(txn, Collections.singletonMap(contactId, rotated)); - oneOf(db).endTransaction(txn1); // Schedule key rotation at the start of the next rotation period oneOf(timer).schedule(with(any(TimerTask.class)), with(rotationPeriodLength - 1)); @@ -100,7 +96,7 @@ public class TransportKeyManagerTest extends BriarTestCase { TransportKeyManager transportKeyManager = new TransportKeyManager(db, crypto, timer, clock, transportId, maxLatency); - transportKeyManager.start(); + transportKeyManager.start(txn); context.assertIsSatisfied(); } @@ -112,10 +108,12 @@ public class TransportKeyManagerTest extends BriarTestCase { final CryptoComponent crypto = context.mock(CryptoComponent.class); final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); + final boolean alice = true; final TransportKeys transportKeys = createTransportKeys(999, 0); final TransportKeys rotated = createTransportKeys(1000, 0); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); + context.checking(new Expectations() {{ oneOf(crypto).deriveTransportKeys(transportId, masterKey, 999, alice); @@ -155,9 +153,11 @@ public class TransportKeyManagerTest extends BriarTestCase { final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); + final Transaction txn = new Transaction(null, false); + TransportKeyManager transportKeyManager = new TransportKeyManager(db, crypto, timer, clock, transportId, maxLatency); - assertNull(transportKeyManager.getStreamContext(contactId)); + assertNull(transportKeyManager.getStreamContext(txn, contactId)); context.assertIsSatisfied(); } @@ -170,11 +170,13 @@ public class TransportKeyManagerTest extends BriarTestCase { final CryptoComponent crypto = context.mock(CryptoComponent.class); final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); + final boolean alice = true; // The stream counter has been exhausted final TransportKeys transportKeys = createTransportKeys(1000, MAX_32_BIT_UNSIGNED + 1); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); + context.checking(new Expectations() {{ oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, alice); @@ -201,7 +203,7 @@ public class TransportKeyManagerTest extends BriarTestCase { long timestamp = rotationPeriodLength * 1000; transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice); - assertNull(transportKeyManager.getStreamContext(contactId)); + assertNull(transportKeyManager.getStreamContext(txn, contactId)); context.assertIsSatisfied(); } @@ -213,12 +215,13 @@ public class TransportKeyManagerTest extends BriarTestCase { final CryptoComponent crypto = context.mock(CryptoComponent.class); final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); + final boolean alice = true; // The stream counter can be used one more time before being exhausted final TransportKeys transportKeys = createTransportKeys(1000, MAX_32_BIT_UNSIGNED); - final Transaction txn = new Transaction(null); - final Transaction txn1 = new Transaction(null); + final Transaction txn = new Transaction(null, false); + context.checking(new Expectations() {{ oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, alice); @@ -238,11 +241,7 @@ public class TransportKeyManagerTest extends BriarTestCase { // Save the keys oneOf(db).addTransportKeys(txn, contactId, transportKeys); // Increment the stream counter - oneOf(db).startTransaction(); - will(returnValue(txn1)); - oneOf(db).incrementStreamCounter(txn1, contactId, transportId, - 1000); - oneOf(db).endTransaction(txn1); + oneOf(db).incrementStreamCounter(txn, contactId, transportId, 1000); }}); TransportKeyManager transportKeyManager = new TransportKeyManager(db, @@ -252,7 +251,8 @@ public class TransportKeyManagerTest extends BriarTestCase { transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice); // The first request should return a stream context - StreamContext ctx = transportKeyManager.getStreamContext(contactId); + StreamContext ctx = transportKeyManager.getStreamContext(txn, + contactId); assertNotNull(ctx); assertEquals(contactId, ctx.getContactId()); assertEquals(transportId, ctx.getTransportId()); @@ -260,7 +260,7 @@ public class TransportKeyManagerTest extends BriarTestCase { assertEquals(headerKey, ctx.getHeaderKey()); assertEquals(MAX_32_BIT_UNSIGNED, ctx.getStreamNumber()); // The second request should return null, the counter is exhausted - assertNull(transportKeyManager.getStreamContext(contactId)); + assertNull(transportKeyManager.getStreamContext(txn, contactId)); context.assertIsSatisfied(); } @@ -273,9 +273,11 @@ public class TransportKeyManagerTest extends BriarTestCase { final CryptoComponent crypto = context.mock(CryptoComponent.class); final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); + final boolean alice = true; final TransportKeys transportKeys = createTransportKeys(1000, 0); - final Transaction txn = new Transaction(null); + final Transaction txn = new Transaction(null, false); + context.checking(new Expectations() {{ oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, alice); @@ -302,7 +304,8 @@ public class TransportKeyManagerTest extends BriarTestCase { long timestamp = rotationPeriodLength * 1000; transportKeyManager.addContact(txn, contactId, masterKey, timestamp, alice); - assertNull(transportKeyManager.getStreamContext(new byte[TAG_LENGTH])); + assertNull(transportKeyManager.getStreamContext(txn, + new byte[TAG_LENGTH])); context.assertIsSatisfied(); } @@ -314,12 +317,13 @@ public class TransportKeyManagerTest extends BriarTestCase { final CryptoComponent crypto = context.mock(CryptoComponent.class); final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); + final boolean alice = true; final TransportKeys transportKeys = createTransportKeys(1000, 0); - final Transaction txn = new Transaction(null); - final Transaction txn1 = new Transaction(null); // Keep a copy of the tags final List<byte[]> tags = new ArrayList<byte[]>(); + final Transaction txn = new Transaction(null, false); + context.checking(new Expectations() {{ oneOf(crypto).deriveTransportKeys(transportId, masterKey, 1000, alice); @@ -343,11 +347,8 @@ public class TransportKeyManagerTest extends BriarTestCase { with(tagKey), with((long) REORDERING_WINDOW_SIZE)); will(new EncodeTagAction(tags)); // Save the reordering window (previous rotation period, base 1) - oneOf(db).startTransaction(); - will(returnValue(txn1)); - oneOf(db).setReorderingWindow(txn1, contactId, transportId, 999, + oneOf(db).setReorderingWindow(txn, contactId, transportId, 999, 1, new byte[REORDERING_WINDOW_SIZE / 8]); - oneOf(db).endTransaction(txn1); }}); TransportKeyManager transportKeyManager = new TransportKeyManager(db, @@ -360,7 +361,7 @@ public class TransportKeyManagerTest extends BriarTestCase { assertEquals(REORDERING_WINDOW_SIZE * 3, tags.size()); byte[] tag = tags.get(0); // The first request should return a stream context - StreamContext ctx = transportKeyManager.getStreamContext(tag); + StreamContext ctx = transportKeyManager.getStreamContext(txn, tag); assertNotNull(ctx); assertEquals(contactId, ctx.getContactId()); assertEquals(transportId, ctx.getTransportId()); @@ -370,7 +371,7 @@ public class TransportKeyManagerTest extends BriarTestCase { // Another tag should have been encoded assertEquals(REORDERING_WINDOW_SIZE * 3 + 1, tags.size()); // The second request should return null, the tag has already been used - assertNull(transportKeyManager.getStreamContext(tag)); + assertNull(transportKeyManager.getStreamContext(txn, tag)); context.assertIsSatisfied(); } @@ -382,22 +383,21 @@ public class TransportKeyManagerTest extends BriarTestCase { final CryptoComponent crypto = context.mock(CryptoComponent.class); final Timer timer = context.mock(Timer.class); final Clock clock = context.mock(Clock.class); - final Transaction txn = new Transaction(null); + final TransportKeys transportKeys = createTransportKeys(1000, 0); final Map<ContactId, TransportKeys> loaded = Collections.singletonMap(contactId, transportKeys); final TransportKeys rotated = createTransportKeys(1001, 0); - final Transaction txn1 = new Transaction(null); + final Transaction txn = new Transaction(null, false); + final Transaction txn1 = new Transaction(null, false); + context.checking(new Expectations() {{ // Get the current time (the start of rotation period 1000) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1000)); // Load the transport keys - oneOf(db).startTransaction(); - will(returnValue(txn)); oneOf(db).getTransportKeys(txn, transportId); will(returnValue(loaded)); - oneOf(db).endTransaction(txn); // Rotate the transport keys (the keys are unaffected) oneOf(crypto).rotateTransportKeys(transportKeys, 1000); will(returnValue(transportKeys)); @@ -411,6 +411,9 @@ public class TransportKeyManagerTest extends BriarTestCase { oneOf(timer).schedule(with(any(TimerTask.class)), with(rotationPeriodLength)); will(new RunTimerTaskAction()); + // Start a transaction for key rotation + oneOf(db).startTransaction(false); + will(returnValue(txn1)); // Get the current time (the start of rotation period 1001) oneOf(clock).currentTimeMillis(); will(returnValue(rotationPeriodLength * 1001)); @@ -425,19 +428,19 @@ public class TransportKeyManagerTest extends BriarTestCase { will(new EncodeTagAction()); } // Save the keys that were rotated - oneOf(db).startTransaction(); - will(returnValue(txn1)); oneOf(db).updateTransportKeys(txn1, Collections.singletonMap(contactId, rotated)); - oneOf(db).endTransaction(txn1); // Schedule key rotation at the start of the next rotation period oneOf(timer).schedule(with(any(TimerTask.class)), with(rotationPeriodLength)); + // Commit the key rotation transaction + oneOf(db).endTransaction(txn1); }}); TransportKeyManager transportKeyManager = new TransportKeyManager(db, crypto, timer, clock, transportId, maxLatency); - transportKeyManager.start(); + transportKeyManager.start(txn); + assertTrue(txn1.isComplete()); context.assertIsSatisfied(); }