mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 10:49:06 +01:00
Merge branch '272-transaction-isolation' into 'master'
Transaction isolation. #272 When client transactions were implemented the DB's read-write lock was removed, exposing H2's transaction isolation semantics. The default isolation level is "read committed", which allows concurrent transactions to overwrite each other's updates. This was the cause of #272. Changing H2's isolation level to "serialisable" would have caused other problems. The solution is to reintroduce the DB's read-write lock. The lock is acquired when starting a transaction and released when committing or rolling back a transaction. (We already use try/finally blocks to ensure every transaction is committed or rolled back.) Read-only transactions can share the lock. To avoid deadlock, transactions must not be started while holding other locks. This patch adapts the key manager to the new locking rules. The rest of the code was already compliant. Transports are now added to the DB during the startup phase, which allows TransportAddedEvent and TransportRemovedEvent to be deleted. Fixes #269, fixes #272. See merge request !124
This commit is contained in:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
13
briar-api/src/org/briarproject/api/plugins/PluginConfig.java
Normal file
13
briar-api/src/org/briarproject/api/plugins/PluginConfig.java
Normal file
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package org.briarproject.api.plugins.duplex;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface DuplexPluginConfig {
|
||||
|
||||
Collection<DuplexPluginFactory> getFactories();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
package org.briarproject.api.plugins.simplex;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface SimplexPluginConfig {
|
||||
|
||||
Collection<SimplexPluginFactory> getFactories();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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 =
|
||||
Map<ContactId, TransportKeys> snapshot =
|
||||
new HashMap<ContactId, TransportKeys>();
|
||||
Map<ContactId, TransportKeys> current =
|
||||
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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
55
briar-tests/src/org/briarproject/TestPluginsModule.java
Normal file
55
briar-tests/src/org/briarproject/TestPluginsModule.java
Normal file
@@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user