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