mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 21:59:54 +01:00
Merge branch 'poller-refactoring' into 'master'
Poller refactoring, replace Timer with ScheduledExecutorService * Replace Timer with ScheduledExecutorService (closes #258) * Move automatic connection logic from PluginManager to Poller * Reschedule polling when connections are opened or closed, making the poller more responsive to reductions in the polling interval See merge request !180
This commit is contained in:
@@ -42,6 +42,7 @@ import org.briarproject.introduction.MessageSender;
|
|||||||
import org.briarproject.lifecycle.LifecycleModule;
|
import org.briarproject.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.properties.PropertiesModule;
|
import org.briarproject.properties.PropertiesModule;
|
||||||
import org.briarproject.sync.SyncModule;
|
import org.briarproject.sync.SyncModule;
|
||||||
|
import org.briarproject.system.SystemModule;
|
||||||
import org.briarproject.transport.TransportModule;
|
import org.briarproject.transport.TransportModule;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -944,6 +945,7 @@ public class IntroductionIntegrationTest extends BriarTestCase {
|
|||||||
this.accept = accept;
|
this.accept = accept;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof MessageValidatedEvent) {
|
if (e instanceof MessageValidatedEvent) {
|
||||||
MessageValidatedEvent event = (MessageValidatedEvent) e;
|
MessageValidatedEvent event = (MessageValidatedEvent) e;
|
||||||
@@ -1010,6 +1012,7 @@ public class IntroductionIntegrationTest extends BriarTestCase {
|
|||||||
public volatile boolean response2Received = false;
|
public volatile boolean response2Received = false;
|
||||||
public volatile boolean aborted = false;
|
public volatile boolean aborted = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof MessageValidatedEvent) {
|
if (e instanceof MessageValidatedEvent) {
|
||||||
MessageValidatedEvent event = (MessageValidatedEvent) e;
|
MessageValidatedEvent event = (MessageValidatedEvent) e;
|
||||||
@@ -1050,7 +1053,7 @@ public class IntroductionIntegrationTest extends BriarTestCase {
|
|||||||
component.inject(new ContactModule.EagerSingletons());
|
component.inject(new ContactModule.EagerSingletons());
|
||||||
component.inject(new TransportModule.EagerSingletons());
|
component.inject(new TransportModule.EagerSingletons());
|
||||||
component.inject(new SyncModule.EagerSingletons());
|
component.inject(new SyncModule.EagerSingletons());
|
||||||
|
component.inject(new SystemModule.EagerSingletons());
|
||||||
component.inject(new PropertiesModule.EagerSingletons());
|
component.inject(new PropertiesModule.EagerSingletons());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.briarproject.introduction.MessageSender;
|
|||||||
import org.briarproject.lifecycle.LifecycleModule;
|
import org.briarproject.lifecycle.LifecycleModule;
|
||||||
import org.briarproject.properties.PropertiesModule;
|
import org.briarproject.properties.PropertiesModule;
|
||||||
import org.briarproject.sync.SyncModule;
|
import org.briarproject.sync.SyncModule;
|
||||||
|
import org.briarproject.system.SystemModule;
|
||||||
import org.briarproject.transport.TransportModule;
|
import org.briarproject.transport.TransportModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -29,9 +30,9 @@ import dagger.Component;
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
TestSystemModule.class,
|
|
||||||
TestDatabaseModule.class,
|
TestDatabaseModule.class,
|
||||||
TestPluginsModule.class,
|
TestPluginsModule.class,
|
||||||
|
TestSeedProviderModule.class,
|
||||||
LifecycleModule.class,
|
LifecycleModule.class,
|
||||||
IntroductionModule.class,
|
IntroductionModule.class,
|
||||||
DatabaseModule.class,
|
DatabaseModule.class,
|
||||||
@@ -42,6 +43,7 @@ import dagger.Component;
|
|||||||
TransportModule.class,
|
TransportModule.class,
|
||||||
ClientsModule.class,
|
ClientsModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
|
SystemModule.class,
|
||||||
DataModule.class,
|
DataModule.class,
|
||||||
PropertiesModule.class
|
PropertiesModule.class
|
||||||
})
|
})
|
||||||
@@ -61,6 +63,8 @@ public interface IntroductionIntegrationTestComponent {
|
|||||||
|
|
||||||
void inject(SyncModule.EagerSingletons init);
|
void inject(SyncModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(TransportModule.EagerSingletons init);
|
void inject(TransportModule.EagerSingletons init);
|
||||||
|
|
||||||
LifecycleManager getLifecycleManager();
|
LifecycleManager getLifecycleManager();
|
||||||
@@ -84,5 +88,4 @@ public interface IntroductionIntegrationTestComponent {
|
|||||||
MessageSender getMessageSender();
|
MessageSender getMessageSender();
|
||||||
|
|
||||||
IntroductionGroupFactory getIntroductionGroupFactory();
|
IntroductionGroupFactory getIntroductionGroupFactory();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.briarproject.api.messaging.PrivateMessage;
|
|||||||
import org.briarproject.api.messaging.PrivateMessageFactory;
|
import org.briarproject.api.messaging.PrivateMessageFactory;
|
||||||
import org.briarproject.api.sync.GroupId;
|
import org.briarproject.api.sync.GroupId;
|
||||||
import org.briarproject.api.sync.MessageId;
|
import org.briarproject.api.sync.MessageId;
|
||||||
|
import org.briarproject.system.SystemModule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -39,6 +40,7 @@ public class MessageSizeIntegrationTest extends BriarTestCase {
|
|||||||
MessageSizeIntegrationTestComponent component =
|
MessageSizeIntegrationTestComponent component =
|
||||||
DaggerMessageSizeIntegrationTestComponent.builder().build();
|
DaggerMessageSizeIntegrationTestComponent.builder().build();
|
||||||
component.inject(this);
|
component.inject(this);
|
||||||
|
component.inject(new SystemModule.EagerSingletons());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import org.briarproject.forum.ForumModule;
|
|||||||
import org.briarproject.identity.IdentityModule;
|
import org.briarproject.identity.IdentityModule;
|
||||||
import org.briarproject.messaging.MessagingModule;
|
import org.briarproject.messaging.MessagingModule;
|
||||||
import org.briarproject.sync.SyncModule;
|
import org.briarproject.sync.SyncModule;
|
||||||
|
import org.briarproject.system.SystemModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
@@ -18,7 +19,7 @@ import dagger.Component;
|
|||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
TestDatabaseModule.class,
|
TestDatabaseModule.class,
|
||||||
TestLifecycleModule.class,
|
TestLifecycleModule.class,
|
||||||
TestSystemModule.class,
|
TestSeedProviderModule.class,
|
||||||
ClientsModule.class,
|
ClientsModule.class,
|
||||||
CryptoModule.class,
|
CryptoModule.class,
|
||||||
DataModule.class,
|
DataModule.class,
|
||||||
@@ -27,8 +28,12 @@ import dagger.Component;
|
|||||||
ForumModule.class,
|
ForumModule.class,
|
||||||
IdentityModule.class,
|
IdentityModule.class,
|
||||||
MessagingModule.class,
|
MessagingModule.class,
|
||||||
SyncModule.class
|
SyncModule.class,
|
||||||
|
SystemModule.class
|
||||||
})
|
})
|
||||||
public interface MessageSizeIntegrationTestComponent {
|
public interface MessageSizeIntegrationTestComponent {
|
||||||
|
|
||||||
void inject(MessageSizeIntegrationTest testCase);
|
void inject(MessageSizeIntegrationTest testCase);
|
||||||
|
|
||||||
|
void inject(SystemModule.EagerSingletons init);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.briarproject.api.transport.KeyManager;
|
|||||||
import org.briarproject.api.transport.StreamContext;
|
import org.briarproject.api.transport.StreamContext;
|
||||||
import org.briarproject.api.transport.StreamReaderFactory;
|
import org.briarproject.api.transport.StreamReaderFactory;
|
||||||
import org.briarproject.api.transport.StreamWriterFactory;
|
import org.briarproject.api.transport.StreamWriterFactory;
|
||||||
|
import org.briarproject.system.SystemModule;
|
||||||
import org.junit.After;
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -57,8 +58,10 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
|||||||
assertTrue(testDir.mkdirs());
|
assertTrue(testDir.mkdirs());
|
||||||
alice = DaggerSimplexMessagingIntegrationTestComponent.builder()
|
alice = DaggerSimplexMessagingIntegrationTestComponent.builder()
|
||||||
.testDatabaseModule(new TestDatabaseModule(aliceDir)).build();
|
.testDatabaseModule(new TestDatabaseModule(aliceDir)).build();
|
||||||
|
alice.inject(new SystemModule.EagerSingletons());
|
||||||
bob = DaggerSimplexMessagingIntegrationTestComponent.builder()
|
bob = DaggerSimplexMessagingIntegrationTestComponent.builder()
|
||||||
.testDatabaseModule(new TestDatabaseModule(bobDir)).build();
|
.testDatabaseModule(new TestDatabaseModule(bobDir)).build();
|
||||||
|
bob.inject(new SystemModule.EagerSingletons());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -183,6 +186,7 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase {
|
|||||||
|
|
||||||
private volatile boolean messageAdded = false;
|
private volatile boolean messageAdded = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof MessageAddedEvent) messageAdded = true;
|
if (e instanceof MessageAddedEvent) messageAdded = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import org.briarproject.lifecycle.LifecycleModule;
|
|||||||
import org.briarproject.messaging.MessagingModule;
|
import org.briarproject.messaging.MessagingModule;
|
||||||
import org.briarproject.plugins.PluginsModule;
|
import org.briarproject.plugins.PluginsModule;
|
||||||
import org.briarproject.sync.SyncModule;
|
import org.briarproject.sync.SyncModule;
|
||||||
|
import org.briarproject.system.SystemModule;
|
||||||
import org.briarproject.transport.TransportModule;
|
import org.briarproject.transport.TransportModule;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -31,7 +32,7 @@ import dagger.Component;
|
|||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
TestDatabaseModule.class,
|
TestDatabaseModule.class,
|
||||||
TestPluginsModule.class,
|
TestPluginsModule.class,
|
||||||
TestSystemModule.class,
|
TestSeedProviderModule.class,
|
||||||
ClientsModule.class,
|
ClientsModule.class,
|
||||||
ContactModule.class,
|
ContactModule.class,
|
||||||
CryptoModule.class,
|
CryptoModule.class,
|
||||||
@@ -43,11 +44,12 @@ import dagger.Component;
|
|||||||
MessagingModule.class,
|
MessagingModule.class,
|
||||||
PluginsModule.class,
|
PluginsModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
|
SystemModule.class,
|
||||||
TransportModule.class
|
TransportModule.class
|
||||||
})
|
})
|
||||||
public interface SimplexMessagingIntegrationTestComponent {
|
public interface SimplexMessagingIntegrationTestComponent {
|
||||||
|
|
||||||
void inject(SimplexMessagingIntegrationTest testCase);
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|
||||||
LifecycleManager getLifecycleManager();
|
LifecycleManager getLifecycleManager();
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import dagger.Component;
|
|||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
@Component(modules = {
|
@Component(modules = {
|
||||||
TestSystemModule.class,
|
TestSeedProviderModule.class,
|
||||||
CryptoModule.class,
|
CryptoModule.class,
|
||||||
SyncModule.class,
|
SyncModule.class,
|
||||||
TransportModule.class
|
TransportModule.class
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import dagger.Provides;
|
|||||||
public class AndroidSystemModule {
|
public class AndroidSystemModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@Singleton
|
||||||
public SeedProvider provideSeedProvider(Application app) {
|
public SeedProvider provideSeedProvider(Application app) {
|
||||||
return new AndroidSeedProvider(app);
|
return new AndroidSeedProvider(app);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,24 +2,39 @@ package org.briarproject.api.plugins;
|
|||||||
|
|
||||||
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.simplex.SimplexPlugin;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for starting transport plugins at startup, stopping them at
|
* Responsible for starting transport plugins at startup and stopping them at
|
||||||
* shutdown, and providing access to plugins for exchanging invitations.
|
* shutdown.
|
||||||
*/
|
*/
|
||||||
public interface PluginManager {
|
public interface PluginManager {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the plugin for the given transport, or null if no such plugin
|
* Returns the plugin for the given transport, or null if no such plugin
|
||||||
* is running.
|
* has been created.
|
||||||
*/
|
*/
|
||||||
Plugin getPlugin(TransportId t);
|
Plugin getPlugin(TransportId t);
|
||||||
|
|
||||||
/** Returns any running duplex plugins that support invitations. */
|
/**
|
||||||
|
* Returns any simplex plugins that have been created.
|
||||||
|
*/
|
||||||
|
Collection<SimplexPlugin> getSimplexPlugins();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns any duplex plugins that have been created.
|
||||||
|
*/
|
||||||
|
Collection<DuplexPlugin> getDuplexPlugins();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns any duplex plugins that support invitations.
|
||||||
|
*/
|
||||||
Collection<DuplexPlugin> getInvitationPlugins();
|
Collection<DuplexPlugin> getInvitationPlugins();
|
||||||
|
|
||||||
/** Returns any running duplex plugins that support key agreement. */
|
/**
|
||||||
|
* Returns any duplex plugins that support key agreement.
|
||||||
|
*/
|
||||||
Collection<DuplexPlugin> getKeyAgreementPlugins();
|
Collection<DuplexPlugin> getKeyAgreementPlugins();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
package org.briarproject.api.system;
|
|
||||||
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A wrapper around a {@link java.util.Timer} that allows it to be replaced for
|
|
||||||
* testing.
|
|
||||||
*/
|
|
||||||
public interface Timer {
|
|
||||||
|
|
||||||
/** @see {@link java.util.Timer#cancel()} */
|
|
||||||
void cancel();
|
|
||||||
|
|
||||||
/** @see {@link java.util.Timer#purge()} */
|
|
||||||
int purge();
|
|
||||||
|
|
||||||
/** @see {@link java.util.Timer#schedule(TimerTask, long)} */
|
|
||||||
void schedule(TimerTask task, long delay);
|
|
||||||
|
|
||||||
/** @see {@link java.util.Timer#schedule(TimerTask, long, long)} */
|
|
||||||
void schedule(TimerTask task, long delay, long period);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see {@link java.util.Timer#scheduleAtFixedRate(TimerTask, long, long)}
|
|
||||||
*/
|
|
||||||
void scheduleAtFixedRate(TimerTask task, long delay, long period);
|
|
||||||
}
|
|
||||||
@@ -10,6 +10,7 @@ import org.briarproject.messaging.MessagingModule;
|
|||||||
import org.briarproject.plugins.PluginsModule;
|
import org.briarproject.plugins.PluginsModule;
|
||||||
import org.briarproject.properties.PropertiesModule;
|
import org.briarproject.properties.PropertiesModule;
|
||||||
import org.briarproject.sync.SyncModule;
|
import org.briarproject.sync.SyncModule;
|
||||||
|
import org.briarproject.system.SystemModule;
|
||||||
import org.briarproject.transport.TransportModule;
|
import org.briarproject.transport.TransportModule;
|
||||||
|
|
||||||
public interface CoreEagerSingletons {
|
public interface CoreEagerSingletons {
|
||||||
@@ -34,5 +35,7 @@ public interface CoreEagerSingletons {
|
|||||||
|
|
||||||
void inject(SyncModule.EagerSingletons init);
|
void inject(SyncModule.EagerSingletons init);
|
||||||
|
|
||||||
|
void inject(SystemModule.EagerSingletons init);
|
||||||
|
|
||||||
void inject(TransportModule.EagerSingletons init);
|
void inject(TransportModule.EagerSingletons init);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ public class CoreModule {
|
|||||||
c.inject(new PluginsModule.EagerSingletons());
|
c.inject(new PluginsModule.EagerSingletons());
|
||||||
c.inject(new PropertiesModule.EagerSingletons());
|
c.inject(new PropertiesModule.EagerSingletons());
|
||||||
c.inject(new SyncModule.EagerSingletons());
|
c.inject(new SyncModule.EagerSingletons());
|
||||||
|
c.inject(new SystemModule.EagerSingletons());
|
||||||
c.inject(new TransportModule.EagerSingletons());
|
c.inject(new TransportModule.EagerSingletons());
|
||||||
c.inject(new IntroductionModule.EagerSingletons());
|
c.inject(new IntroductionModule.EagerSingletons());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,24 +50,27 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
executors = new CopyOnWriteArrayList<ExecutorService>();
|
executors = new CopyOnWriteArrayList<ExecutorService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void registerService(Service s) {
|
public void registerService(Service s) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Registering service " + s.getClass().getName());
|
LOG.info("Registering service " + s.getClass().getName());
|
||||||
services.add(s);
|
services.add(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void registerClient(Client c) {
|
public void registerClient(Client c) {
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info("Registering client " + c.getClass().getName());
|
LOG.info("Registering client " + c.getClass().getName());
|
||||||
clients.add(c);
|
clients.add(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void registerForShutdown(ExecutorService e) {
|
public void registerForShutdown(ExecutorService e) {
|
||||||
if (LOG.isLoggable(INFO))
|
LOG.info("Registering executor");
|
||||||
LOG.info("Registering executor " + e.getClass().getName());
|
|
||||||
executors.add(e);
|
executors.add(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public StartResult startServices() {
|
public StartResult startServices() {
|
||||||
if (!startStopSemaphore.tryAcquire()) {
|
if (!startStopSemaphore.tryAcquire()) {
|
||||||
LOG.info("Already starting or stopping");
|
LOG.info("Already starting or stopping");
|
||||||
@@ -91,7 +94,7 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
c.createLocalState(txn);
|
c.createLocalState(txn);
|
||||||
duration = System.currentTimeMillis() - start;
|
duration = System.currentTimeMillis() - start;
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Starting " + c.getClass().getName()
|
LOG.info("Starting client " + c.getClass().getName()
|
||||||
+ " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,7 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
s.startService();
|
s.startService();
|
||||||
duration = System.currentTimeMillis() - start;
|
duration = System.currentTimeMillis() - start;
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
LOG.info("Starting " + s.getClass().getName()
|
LOG.info("Starting service " + s.getClass().getName()
|
||||||
+ " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,6 +124,7 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void stopServices() {
|
public void stopServices() {
|
||||||
try {
|
try {
|
||||||
startStopSemaphore.acquire();
|
startStopSemaphore.acquire();
|
||||||
@@ -132,15 +136,22 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
LOG.info("Stopping services");
|
LOG.info("Stopping services");
|
||||||
eventBus.broadcast(new ShutdownEvent());
|
eventBus.broadcast(new ShutdownEvent());
|
||||||
for (Service s : services) {
|
for (Service s : services) {
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
s.stopService();
|
s.stopService();
|
||||||
if (LOG.isLoggable(INFO))
|
long duration = System.currentTimeMillis() - start;
|
||||||
LOG.info("Service stopped: " + s.getClass().getName());
|
if (LOG.isLoggable(INFO)) {
|
||||||
|
LOG.info("Stopping service " + s.getClass().getName()
|
||||||
|
+ " took " + duration + " ms");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (ExecutorService e : executors) e.shutdownNow();
|
for (ExecutorService e : executors) e.shutdownNow();
|
||||||
if (LOG.isLoggable(INFO))
|
if (LOG.isLoggable(INFO))
|
||||||
LOG.info(executors.size() + " executors shut down");
|
LOG.info(executors.size() + " executors shut down");
|
||||||
|
long start = System.currentTimeMillis();
|
||||||
db.close();
|
db.close();
|
||||||
LOG.info("Database closed");
|
long duration = System.currentTimeMillis() - start;
|
||||||
|
if (LOG.isLoggable(INFO))
|
||||||
|
LOG.info("Closing database took " + duration + " ms");
|
||||||
shutdownLatch.countDown();
|
shutdownLatch.countDown();
|
||||||
} 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);
|
||||||
@@ -151,14 +162,17 @@ class LifecycleManagerImpl implements LifecycleManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void waitForDatabase() throws InterruptedException {
|
public void waitForDatabase() throws InterruptedException {
|
||||||
dbLatch.await();
|
dbLatch.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void waitForStartup() throws InterruptedException {
|
public void waitForStartup() throws InterruptedException {
|
||||||
startupLatch.await();
|
startupLatch.await();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void waitForShutdown() throws InterruptedException {
|
public void waitForShutdown() throws InterruptedException {
|
||||||
shutdownLatch.await();
|
shutdownLatch.await();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,13 @@ 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.db.DbException;
|
||||||
import org.briarproject.api.event.ConnectionClosedEvent;
|
|
||||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
|
||||||
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.TransportDisabledEvent;
|
import org.briarproject.api.event.TransportDisabledEvent;
|
||||||
import org.briarproject.api.event.TransportEnabledEvent;
|
import org.briarproject.api.event.TransportEnabledEvent;
|
||||||
import org.briarproject.api.lifecycle.IoExecutor;
|
import org.briarproject.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.api.lifecycle.Service;
|
import org.briarproject.api.lifecycle.Service;
|
||||||
import org.briarproject.api.lifecycle.ServiceException;
|
import org.briarproject.api.lifecycle.ServiceException;
|
||||||
import org.briarproject.api.plugins.ConnectionManager;
|
import org.briarproject.api.plugins.ConnectionManager;
|
||||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
|
||||||
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.PluginConfig;
|
||||||
@@ -51,7 +46,7 @@ import javax.inject.Inject;
|
|||||||
import static java.util.logging.Level.INFO;
|
import static java.util.logging.Level.INFO;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
|
|
||||||
class PluginManagerImpl implements PluginManager, Service, EventListener {
|
class PluginManagerImpl implements PluginManager, Service {
|
||||||
|
|
||||||
private static final Logger LOG =
|
private static final Logger LOG =
|
||||||
Logger.getLogger(PluginManagerImpl.class.getName());
|
Logger.getLogger(PluginManagerImpl.class.getName());
|
||||||
@@ -59,9 +54,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
|||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final EventBus eventBus;
|
private final EventBus eventBus;
|
||||||
private final PluginConfig pluginConfig;
|
private final PluginConfig pluginConfig;
|
||||||
private final Poller poller;
|
|
||||||
private final ConnectionManager connectionManager;
|
private final ConnectionManager connectionManager;
|
||||||
private final ConnectionRegistry connectionRegistry;
|
|
||||||
private final SettingsManager settingsManager;
|
private final SettingsManager settingsManager;
|
||||||
private final TransportPropertyManager transportPropertyManager;
|
private final TransportPropertyManager transportPropertyManager;
|
||||||
private final UiCallback uiCallback;
|
private final UiCallback uiCallback;
|
||||||
@@ -71,18 +64,14 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
|||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
|
PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus,
|
||||||
PluginConfig pluginConfig, Poller poller,
|
PluginConfig pluginConfig, ConnectionManager connectionManager,
|
||||||
ConnectionManager connectionManager,
|
|
||||||
ConnectionRegistry connectionRegistry,
|
|
||||||
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.pluginConfig = pluginConfig;
|
this.pluginConfig = pluginConfig;
|
||||||
this.poller = poller;
|
|
||||||
this.connectionManager = connectionManager;
|
this.connectionManager = connectionManager;
|
||||||
this.connectionRegistry = connectionRegistry;
|
|
||||||
this.settingsManager = settingsManager;
|
this.settingsManager = settingsManager;
|
||||||
this.transportPropertyManager = transportPropertyManager;
|
this.transportPropertyManager = transportPropertyManager;
|
||||||
this.uiCallback = uiCallback;
|
this.uiCallback = uiCallback;
|
||||||
@@ -93,39 +82,53 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startService() throws ServiceException {
|
public void startService() throws ServiceException {
|
||||||
|
Collection<SimplexPluginFactory> simplexFactories =
|
||||||
|
pluginConfig.getSimplexFactories();
|
||||||
|
Collection<DuplexPluginFactory> duplexFactories =
|
||||||
|
pluginConfig.getDuplexFactories();
|
||||||
|
int numPlugins = simplexFactories.size() + duplexFactories.size();
|
||||||
|
CountDownLatch latch = new CountDownLatch(numPlugins);
|
||||||
// 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 =
|
for (SimplexPluginFactory f : simplexFactories) {
|
||||||
pluginConfig.getSimplexFactories();
|
TransportId t = f.getId();
|
||||||
final CountDownLatch sLatch = new CountDownLatch(sFactories.size());
|
SimplexPlugin s = f.createPlugin(new SimplexCallback(t));
|
||||||
for (SimplexPluginFactory factory : sFactories)
|
if (s == null) {
|
||||||
ioExecutor.execute(new SimplexPluginStarter(factory, sLatch));
|
if (LOG.isLoggable(WARNING))
|
||||||
|
LOG.warning("Could not create plugin for " + t);
|
||||||
|
latch.countDown();
|
||||||
|
} else {
|
||||||
|
plugins.put(t, s);
|
||||||
|
simplexPlugins.add(s);
|
||||||
|
ioExecutor.execute(new PluginStarter(s, latch));
|
||||||
|
}
|
||||||
|
}
|
||||||
// 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 =
|
for (DuplexPluginFactory f : duplexFactories) {
|
||||||
pluginConfig.getDuplexFactories();
|
TransportId t = f.getId();
|
||||||
final CountDownLatch dLatch = new CountDownLatch(dFactories.size());
|
DuplexPlugin d = f.createPlugin(new DuplexCallback(t));
|
||||||
for (DuplexPluginFactory factory : dFactories)
|
if (d == null) {
|
||||||
ioExecutor.execute(new DuplexPluginStarter(factory, dLatch));
|
if (LOG.isLoggable(WARNING))
|
||||||
// Wait for the plugins to start
|
LOG.warning("Could not create plugin for " + t);
|
||||||
|
latch.countDown();
|
||||||
|
} else {
|
||||||
|
plugins.put(t, d);
|
||||||
|
duplexPlugins.add(d);
|
||||||
|
ioExecutor.execute(new PluginStarter(d, latch));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Wait for all the plugins to start
|
||||||
try {
|
try {
|
||||||
sLatch.await();
|
latch.await();
|
||||||
dLatch.await();
|
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
throw new ServiceException(e);
|
throw new ServiceException(e);
|
||||||
}
|
}
|
||||||
// Listen for events
|
|
||||||
eventBus.addListener(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void stopService() throws ServiceException {
|
public void stopService() throws ServiceException {
|
||||||
// Stop listening for events
|
CountDownLatch latch = new CountDownLatch(plugins.size());
|
||||||
eventBus.removeListener(this);
|
|
||||||
// Stop the poller
|
|
||||||
LOG.info("Stopping poller");
|
|
||||||
poller.stop();
|
|
||||||
final CountDownLatch latch = new CountDownLatch(plugins.size());
|
|
||||||
// Stop the simplex plugins
|
// Stop the simplex plugins
|
||||||
LOG.info("Stopping simplex plugins");
|
LOG.info("Stopping simplex plugins");
|
||||||
for (SimplexPlugin plugin : simplexPlugins)
|
for (SimplexPlugin plugin : simplexPlugins)
|
||||||
@@ -147,6 +150,16 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
|||||||
return plugins.get(t);
|
return plugins.get(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<SimplexPlugin> getSimplexPlugins() {
|
||||||
|
return Collections.unmodifiableList(simplexPlugins);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<DuplexPlugin> getDuplexPlugins() {
|
||||||
|
return Collections.unmodifiableList(duplexPlugins);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<DuplexPlugin> getInvitationPlugins() {
|
public Collection<DuplexPlugin> getInvitationPlugins() {
|
||||||
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>();
|
||||||
@@ -163,158 +176,32 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
|||||||
return Collections.unmodifiableList(supported);
|
return Collections.unmodifiableList(supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private class PluginStarter implements Runnable {
|
||||||
public void eventOccurred(Event e) {
|
|
||||||
if (e instanceof ContactStatusChangedEvent) {
|
|
||||||
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
|
||||||
if (c.isActive()) {
|
|
||||||
// Connect to the newly activated contact
|
|
||||||
connectToContact(c.getContactId());
|
|
||||||
}
|
|
||||||
} else if (e instanceof ConnectionClosedEvent) {
|
|
||||||
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
|
||||||
if (!c.isIncoming()) {
|
|
||||||
// Connect to the disconnected contact
|
|
||||||
connectToContact(c.getContactId(), c.getTransportId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectToContact(ContactId c) {
|
private final Plugin plugin;
|
||||||
for (SimplexPlugin s : simplexPlugins)
|
|
||||||
if (s.shouldPoll()) connectToContact(c, s);
|
|
||||||
for (DuplexPlugin d : duplexPlugins)
|
|
||||||
if (d.shouldPoll()) connectToContact(c, d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectToContact(ContactId c, TransportId t) {
|
|
||||||
Plugin p = plugins.get(t);
|
|
||||||
if (p instanceof SimplexPlugin && p.shouldPoll())
|
|
||||||
connectToContact(c, (SimplexPlugin) p);
|
|
||||||
else if (p instanceof DuplexPlugin && p.shouldPoll())
|
|
||||||
connectToContact(c, (DuplexPlugin) p);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectToContact(final ContactId c, final SimplexPlugin p) {
|
|
||||||
ioExecutor.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
TransportId t = p.getId();
|
|
||||||
if (!connectionRegistry.isConnected(c, t)) {
|
|
||||||
TransportConnectionWriter w = p.createWriter(c);
|
|
||||||
if (w != null)
|
|
||||||
connectionManager.manageOutgoingConnection(c, t, w);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void connectToContact(final ContactId c, final DuplexPlugin p) {
|
|
||||||
ioExecutor.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
TransportId t = p.getId();
|
|
||||||
if (!connectionRegistry.isConnected(c, t)) {
|
|
||||||
DuplexTransportConnection d = p.createConnection(c);
|
|
||||||
if (d != null)
|
|
||||||
connectionManager.manageOutgoingConnection(c, t, d);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SimplexPluginStarter implements Runnable {
|
|
||||||
|
|
||||||
private final SimplexPluginFactory factory;
|
|
||||||
private final CountDownLatch latch;
|
private final CountDownLatch latch;
|
||||||
|
|
||||||
private SimplexPluginStarter(SimplexPluginFactory factory,
|
private PluginStarter(Plugin plugin, CountDownLatch latch) {
|
||||||
CountDownLatch latch) {
|
this.plugin = plugin;
|
||||||
this.factory = factory;
|
|
||||||
this.latch = latch;
|
this.latch = latch;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
TransportId id = factory.getId();
|
|
||||||
SimplexCallback callback = new SimplexCallback(id);
|
|
||||||
SimplexPlugin plugin = factory.createPlugin(callback);
|
|
||||||
if (plugin == null) {
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
String name = factory.getClass().getSimpleName();
|
|
||||||
LOG.info(name + " did not create a plugin");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
boolean started = plugin.start();
|
boolean started = plugin.start();
|
||||||
long duration = System.currentTimeMillis() - start;
|
long duration = System.currentTimeMillis() - start;
|
||||||
if (started) {
|
if (started) {
|
||||||
plugins.put(id, plugin);
|
|
||||||
simplexPlugins.add(plugin);
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
String name = plugin.getClass().getSimpleName();
|
LOG.info("Starting plugin " + plugin.getId()
|
||||||
LOG.info("Starting " + name + " took " +
|
+ " took " + duration + " ms");
|
||||||
duration + " ms");
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (LOG.isLoggable(WARNING)) {
|
if (LOG.isLoggable(WARNING)) {
|
||||||
String name = plugin.getClass().getSimpleName();
|
LOG.warning("Plugin" + plugin.getId()
|
||||||
LOG.warning(name + " did not start");
|
+ " did not start");
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException e) {
|
|
||||||
if (LOG.isLoggable(WARNING))
|
|
||||||
LOG.log(WARNING, e.toString(), e);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
latch.countDown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class DuplexPluginStarter implements Runnable {
|
|
||||||
|
|
||||||
private final DuplexPluginFactory factory;
|
|
||||||
private final CountDownLatch latch;
|
|
||||||
|
|
||||||
private DuplexPluginStarter(DuplexPluginFactory factory,
|
|
||||||
CountDownLatch latch) {
|
|
||||||
this.factory = factory;
|
|
||||||
this.latch = latch;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
try {
|
|
||||||
TransportId id = factory.getId();
|
|
||||||
DuplexCallback callback = new DuplexCallback(id);
|
|
||||||
DuplexPlugin plugin = factory.createPlugin(callback);
|
|
||||||
if (plugin == null) {
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
String name = factory.getClass().getSimpleName();
|
|
||||||
LOG.info(name + " did not create a plugin");
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
boolean started = plugin.start();
|
|
||||||
long duration = System.currentTimeMillis() - start;
|
|
||||||
if (started) {
|
|
||||||
plugins.put(id, plugin);
|
|
||||||
duplexPlugins.add(plugin);
|
|
||||||
if (LOG.isLoggable(INFO)) {
|
|
||||||
String name = plugin.getClass().getSimpleName();
|
|
||||||
LOG.info("Starting " + name + " took " +
|
|
||||||
duration + " ms");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (LOG.isLoggable(WARNING)) {
|
|
||||||
String name = plugin.getClass().getSimpleName();
|
|
||||||
LOG.warning(name + " did not start");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
@@ -344,8 +231,8 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
|||||||
plugin.stop();
|
plugin.stop();
|
||||||
long duration = System.currentTimeMillis() - start;
|
long duration = System.currentTimeMillis() - start;
|
||||||
if (LOG.isLoggable(INFO)) {
|
if (LOG.isLoggable(INFO)) {
|
||||||
String name = plugin.getClass().getSimpleName();
|
LOG.info("Stopping plugin " + plugin.getId()
|
||||||
LOG.info("Stopping " + name + " took " + duration + " ms");
|
+ " took " + duration + " ms");
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||||
@@ -431,8 +318,6 @@ class PluginManagerImpl implements PluginManager, Service, EventListener {
|
|||||||
@Override
|
@Override
|
||||||
public void transportEnabled() {
|
public void transportEnabled() {
|
||||||
eventBus.broadcast(new TransportEnabledEvent(id));
|
eventBus.broadcast(new TransportEnabledEvent(id));
|
||||||
Plugin p = plugins.get(id);
|
|
||||||
if (p != null) poller.pollNow(p);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -7,14 +7,11 @@ import org.briarproject.api.plugins.BackoffFactory;
|
|||||||
import org.briarproject.api.plugins.ConnectionManager;
|
import org.briarproject.api.plugins.ConnectionManager;
|
||||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||||
import org.briarproject.api.plugins.PluginManager;
|
import org.briarproject.api.plugins.PluginManager;
|
||||||
import org.briarproject.api.sync.SyncSessionFactory;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
import org.briarproject.api.transport.KeyManager;
|
|
||||||
import org.briarproject.api.transport.StreamReaderFactory;
|
|
||||||
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 java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -28,6 +25,8 @@ public class PluginsModule {
|
|||||||
public static class EagerSingletons {
|
public static class EagerSingletons {
|
||||||
@Inject
|
@Inject
|
||||||
PluginManager pluginManager;
|
PluginManager pluginManager;
|
||||||
|
@Inject
|
||||||
|
Poller poller;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -36,33 +35,35 @@ public class PluginsModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@Singleton
|
||||||
Poller providePoller(@IoExecutor Executor ioExecutor,
|
Poller providePoller(@IoExecutor Executor ioExecutor,
|
||||||
ConnectionRegistry connectionRegistry, SecureRandom random,
|
ScheduledExecutorService scheduler,
|
||||||
Timer timer) {
|
ConnectionManager connectionManager,
|
||||||
return new PollerImpl(ioExecutor, connectionRegistry, random, timer);
|
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
||||||
|
SecureRandom random, Clock clock, EventBus eventBus) {
|
||||||
|
Poller poller = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, random, clock);
|
||||||
|
eventBus.addListener(poller);
|
||||||
|
return poller;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
|
@Singleton
|
||||||
ConnectionManager provideConnectionManager(
|
ConnectionManager provideConnectionManager(
|
||||||
@IoExecutor Executor ioExecutor, KeyManager keyManager,
|
ConnectionManagerImpl connectionManager) {
|
||||||
StreamReaderFactory streamReaderFactory,
|
return connectionManager;
|
||||||
StreamWriterFactory streamWriterFactory,
|
|
||||||
SyncSessionFactory syncSessionFactory,
|
|
||||||
ConnectionRegistry connectionRegistry) {
|
|
||||||
return new ConnectionManagerImpl(ioExecutor, keyManager,
|
|
||||||
streamReaderFactory, streamWriterFactory, syncSessionFactory,
|
|
||||||
connectionRegistry);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
ConnectionRegistry provideConnectionRegistry(EventBus eventBus) {
|
ConnectionRegistry provideConnectionRegistry(
|
||||||
return new ConnectionRegistryImpl(eventBus);
|
ConnectionRegistryImpl connectionRegistry) {
|
||||||
|
return connectionRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
PluginManager getPluginManager(LifecycleManager lifecycleManager,
|
PluginManager providePluginManager(LifecycleManager lifecycleManager,
|
||||||
PluginManagerImpl pluginManager) {
|
PluginManagerImpl pluginManager) {
|
||||||
lifecycleManager.registerService(pluginManager);
|
lifecycleManager.registerService(pluginManager);
|
||||||
return pluginManager;
|
return pluginManager;
|
||||||
|
|||||||
@@ -1,12 +1,203 @@
|
|||||||
package org.briarproject.plugins;
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.event.ConnectionClosedEvent;
|
||||||
|
import org.briarproject.api.event.ConnectionOpenedEvent;
|
||||||
|
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||||
|
import org.briarproject.api.event.Event;
|
||||||
|
import org.briarproject.api.event.EventListener;
|
||||||
|
import org.briarproject.api.event.TransportEnabledEvent;
|
||||||
|
import org.briarproject.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.api.plugins.ConnectionManager;
|
||||||
|
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||||
import org.briarproject.api.plugins.Plugin;
|
import org.briarproject.api.plugins.Plugin;
|
||||||
|
import org.briarproject.api.plugins.PluginManager;
|
||||||
|
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||||
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
|
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||||
|
import org.briarproject.api.system.Clock;
|
||||||
|
|
||||||
interface Poller {
|
import java.security.SecureRandom;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.locks.Lock;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
/** Tells the poller to poll the given plugin immediately. */
|
import javax.inject.Inject;
|
||||||
void pollNow(Plugin p);
|
|
||||||
|
|
||||||
/** Stops the poller. */
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
void stop();
|
import static java.util.logging.Level.INFO;
|
||||||
|
|
||||||
|
class Poller implements EventListener {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(Poller.class.getName());
|
||||||
|
|
||||||
|
private final Executor ioExecutor;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
|
private final ConnectionManager connectionManager;
|
||||||
|
private final ConnectionRegistry connectionRegistry;
|
||||||
|
private final PluginManager pluginManager;
|
||||||
|
private final SecureRandom random;
|
||||||
|
private final Clock clock;
|
||||||
|
private final Lock lock;
|
||||||
|
private final Map<TransportId, PollTask> tasks; // Locking: lock
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
Poller(@IoExecutor Executor ioExecutor, ScheduledExecutorService scheduler,
|
||||||
|
ConnectionManager connectionManager,
|
||||||
|
ConnectionRegistry connectionRegistry, PluginManager pluginManager,
|
||||||
|
SecureRandom random, Clock clock) {
|
||||||
|
this.ioExecutor = ioExecutor;
|
||||||
|
this.scheduler = scheduler;
|
||||||
|
this.connectionManager = connectionManager;
|
||||||
|
this.connectionRegistry = connectionRegistry;
|
||||||
|
this.pluginManager = pluginManager;
|
||||||
|
this.random = random;
|
||||||
|
this.clock = clock;
|
||||||
|
lock = new ReentrantLock();
|
||||||
|
tasks = new HashMap<TransportId, PollTask>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void eventOccurred(Event e) {
|
||||||
|
if (e instanceof ContactStatusChangedEvent) {
|
||||||
|
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||||
|
if (c.isActive()) {
|
||||||
|
// Connect to the newly activated contact
|
||||||
|
connectToContact(c.getContactId());
|
||||||
|
}
|
||||||
|
} else if (e instanceof ConnectionClosedEvent) {
|
||||||
|
ConnectionClosedEvent c = (ConnectionClosedEvent) e;
|
||||||
|
// Reschedule polling, the polling interval may have decreased
|
||||||
|
reschedule(c.getTransportId());
|
||||||
|
if (!c.isIncoming()) {
|
||||||
|
// Connect to the disconnected contact
|
||||||
|
connectToContact(c.getContactId(), c.getTransportId());
|
||||||
|
}
|
||||||
|
} else if (e instanceof ConnectionOpenedEvent) {
|
||||||
|
ConnectionOpenedEvent c = (ConnectionOpenedEvent) e;
|
||||||
|
// Reschedule polling, the polling interval may have decreased
|
||||||
|
reschedule(c.getTransportId());
|
||||||
|
} else if (e instanceof TransportEnabledEvent) {
|
||||||
|
TransportEnabledEvent t = (TransportEnabledEvent) e;
|
||||||
|
// Poll the newly enabled transport
|
||||||
|
pollNow(t.getTransportId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToContact(ContactId c) {
|
||||||
|
for (SimplexPlugin s : pluginManager.getSimplexPlugins())
|
||||||
|
if (s.shouldPoll()) connectToContact(c, s);
|
||||||
|
for (DuplexPlugin d : pluginManager.getDuplexPlugins())
|
||||||
|
if (d.shouldPoll()) connectToContact(c, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToContact(ContactId c, TransportId t) {
|
||||||
|
Plugin p = pluginManager.getPlugin(t);
|
||||||
|
if (p instanceof SimplexPlugin && p.shouldPoll())
|
||||||
|
connectToContact(c, (SimplexPlugin) p);
|
||||||
|
else if (p instanceof DuplexPlugin && p.shouldPoll())
|
||||||
|
connectToContact(c, (DuplexPlugin) p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToContact(final ContactId c, final SimplexPlugin p) {
|
||||||
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
TransportId t = p.getId();
|
||||||
|
if (!connectionRegistry.isConnected(c, t)) {
|
||||||
|
TransportConnectionWriter w = p.createWriter(c);
|
||||||
|
if (w != null)
|
||||||
|
connectionManager.manageOutgoingConnection(c, t, w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void connectToContact(final ContactId c, final DuplexPlugin p) {
|
||||||
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
TransportId t = p.getId();
|
||||||
|
if (!connectionRegistry.isConnected(c, t)) {
|
||||||
|
DuplexTransportConnection d = p.createConnection(c);
|
||||||
|
if (d != null)
|
||||||
|
connectionManager.manageOutgoingConnection(c, t, d);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reschedule(TransportId t) {
|
||||||
|
Plugin p = pluginManager.getPlugin(t);
|
||||||
|
if (p.shouldPoll()) schedule(p, p.getPollingInterval(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pollNow(TransportId t) {
|
||||||
|
Plugin p = pluginManager.getPlugin(t);
|
||||||
|
// Randomise next polling interval
|
||||||
|
if (p.shouldPoll()) schedule(p, 0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void schedule(Plugin p, int delay, boolean randomiseNext) {
|
||||||
|
// Replace any later scheduled task for this plugin
|
||||||
|
long due = clock.currentTimeMillis() + delay;
|
||||||
|
TransportId t = p.getId();
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
PollTask scheduled = tasks.get(t);
|
||||||
|
if (scheduled == null || due < scheduled.due) {
|
||||||
|
PollTask task = new PollTask(p, due, randomiseNext);
|
||||||
|
tasks.put(t, task);
|
||||||
|
scheduler.schedule(task, delay, MILLISECONDS);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void poll(final Plugin p) {
|
||||||
|
ioExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
TransportId t = p.getId();
|
||||||
|
if (LOG.isLoggable(INFO)) LOG.info("Polling plugin " + t);
|
||||||
|
p.poll(connectionRegistry.getConnectedContacts(t));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private class PollTask implements Runnable {
|
||||||
|
|
||||||
|
private final Plugin plugin;
|
||||||
|
private final long due;
|
||||||
|
private final boolean randomiseNext;
|
||||||
|
|
||||||
|
private PollTask(Plugin plugin, long due, boolean randomiseNext) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
this.due = due;
|
||||||
|
this.randomiseNext = randomiseNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
lock.lock();
|
||||||
|
try {
|
||||||
|
TransportId t = plugin.getId();
|
||||||
|
if (tasks.get(t) != this) return; // Replaced by another task
|
||||||
|
tasks.remove(t);
|
||||||
|
} finally {
|
||||||
|
lock.unlock();
|
||||||
|
}
|
||||||
|
int delay = plugin.getPollingInterval();
|
||||||
|
if (randomiseNext) delay = (int) (delay * random.nextDouble());
|
||||||
|
schedule(plugin, delay, false);
|
||||||
|
poll(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
package org.briarproject.plugins;
|
|
||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
|
||||||
import org.briarproject.api.lifecycle.IoExecutor;
|
|
||||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
|
||||||
import org.briarproject.api.plugins.Plugin;
|
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TimerTask;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
|
||||||
|
|
||||||
class PollerImpl implements Poller {
|
|
||||||
|
|
||||||
private static final Logger LOG =
|
|
||||||
Logger.getLogger(PollerImpl.class.getName());
|
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
|
||||||
private final ConnectionRegistry connectionRegistry;
|
|
||||||
private final SecureRandom random;
|
|
||||||
private final Timer timer;
|
|
||||||
private final Map<TransportId, PollTask> tasks;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
PollerImpl(@IoExecutor Executor ioExecutor,
|
|
||||||
ConnectionRegistry connectionRegistry, SecureRandom random,
|
|
||||||
Timer timer) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
|
||||||
this.connectionRegistry = connectionRegistry;
|
|
||||||
this.random = random;
|
|
||||||
this.timer = timer;
|
|
||||||
tasks = new ConcurrentHashMap<TransportId, PollTask>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void stop() {
|
|
||||||
timer.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void pollNow(Plugin p) {
|
|
||||||
// Randomise next polling interval
|
|
||||||
if (p.shouldPoll()) schedule(p, 0, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void schedule(Plugin p, int interval, boolean randomiseNext) {
|
|
||||||
// Replace any previously scheduled task for this plugin
|
|
||||||
PollTask task = new PollTask(p, randomiseNext);
|
|
||||||
PollTask replaced = tasks.put(p.getId(), task);
|
|
||||||
if (replaced != null) replaced.cancel();
|
|
||||||
timer.schedule(task, interval);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void poll(final Plugin p) {
|
|
||||||
ioExecutor.execute(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
if (LOG.isLoggable(INFO))
|
|
||||||
LOG.info("Polling " + p.getClass().getSimpleName());
|
|
||||||
p.poll(connectionRegistry.getConnectedContacts(p.getId()));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private class PollTask extends TimerTask {
|
|
||||||
|
|
||||||
private final Plugin plugin;
|
|
||||||
private final boolean randomiseNext;
|
|
||||||
|
|
||||||
private PollTask(Plugin plugin, boolean randomiseNext) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.randomiseNext = randomiseNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
tasks.remove(plugin.getId());
|
|
||||||
int interval = plugin.getPollingInterval();
|
|
||||||
if (randomiseNext)
|
|
||||||
interval = (int) (interval * random.nextDouble());
|
|
||||||
schedule(plugin, interval, false);
|
|
||||||
poll(plugin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,41 @@
|
|||||||
package org.briarproject.system;
|
package org.briarproject.system;
|
||||||
|
|
||||||
|
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||||
import org.briarproject.api.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.api.system.LocationUtils;
|
|
||||||
import org.briarproject.api.system.SeedProvider;
|
import java.util.concurrent.Executors;
|
||||||
import org.briarproject.api.system.Timer;
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class SystemModule {
|
public class SystemModule {
|
||||||
|
|
||||||
|
public static class EagerSingletons {
|
||||||
|
@Inject
|
||||||
|
ScheduledExecutorService scheduledExecutorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
|
|
||||||
|
public SystemModule() {
|
||||||
|
scheduler = Executors.newSingleThreadScheduledExecutor();
|
||||||
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
Clock provideClock() {
|
Clock provideClock() {
|
||||||
return new SystemClock();
|
return new SystemClock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
Timer provideTimer() {
|
@Singleton
|
||||||
return new SystemTimer();
|
ScheduledExecutorService provideScheduledExecutorService(
|
||||||
|
LifecycleManager lifecycleManager) {
|
||||||
|
lifecycleManager.registerForShutdown(scheduler);
|
||||||
|
return scheduler;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
package org.briarproject.system;
|
|
||||||
|
|
||||||
import java.util.TimerTask;
|
|
||||||
|
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
|
|
||||||
/** Default timer implementation. */
|
|
||||||
public class SystemTimer implements Timer {
|
|
||||||
|
|
||||||
private final java.util.Timer timer = new java.util.Timer(true);
|
|
||||||
|
|
||||||
public void cancel() {
|
|
||||||
timer.cancel();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int purge() {
|
|
||||||
return timer.purge();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void schedule(TimerTask task, long delay) {
|
|
||||||
timer.schedule(task, delay);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void schedule(TimerTask task, long delay, long period) {
|
|
||||||
timer.schedule(task, delay, period);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
|
|
||||||
timer.scheduleAtFixedRate(task, delay, period);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -19,7 +19,6 @@ 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.SimplexPluginFactory;
|
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.transport.KeyManager;
|
import org.briarproject.api.transport.KeyManager;
|
||||||
import org.briarproject.api.transport.StreamContext;
|
import org.briarproject.api.transport.StreamContext;
|
||||||
|
|
||||||
@@ -28,6 +27,7 @@ import java.util.Map;
|
|||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
@@ -42,21 +42,22 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final Executor dbExecutor;
|
private final Executor dbExecutor;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
private final PluginConfig pluginConfig;
|
private final PluginConfig pluginConfig;
|
||||||
private final Timer timer;
|
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final Map<ContactId, Boolean> activeContacts;
|
private final Map<ContactId, Boolean> activeContacts;
|
||||||
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
KeyManagerImpl(DatabaseComponent db, CryptoComponent crypto,
|
KeyManagerImpl(DatabaseComponent db, CryptoComponent crypto,
|
||||||
@DatabaseExecutor Executor dbExecutor, PluginConfig pluginConfig,
|
@DatabaseExecutor Executor dbExecutor,
|
||||||
Timer timer, Clock clock) {
|
ScheduledExecutorService scheduler, PluginConfig pluginConfig,
|
||||||
|
Clock clock) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.dbExecutor = dbExecutor;
|
this.dbExecutor = dbExecutor;
|
||||||
|
this.scheduler = scheduler;
|
||||||
this.pluginConfig = pluginConfig;
|
this.pluginConfig = pluginConfig;
|
||||||
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
|
||||||
activeContacts = new ConcurrentHashMap<ContactId, Boolean>();
|
activeContacts = new ConcurrentHashMap<ContactId, Boolean>();
|
||||||
@@ -80,7 +81,8 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
db.addTransport(txn, e.getKey(), e.getValue());
|
db.addTransport(txn, e.getKey(), e.getValue());
|
||||||
for (Entry<TransportId, Integer> e : transports.entrySet()) {
|
for (Entry<TransportId, Integer> e : transports.entrySet()) {
|
||||||
TransportKeyManager m = new TransportKeyManager(db, crypto,
|
TransportKeyManager m = new TransportKeyManager(db, crypto,
|
||||||
timer, clock, e.getKey(), e.getValue());
|
dbExecutor, scheduler, clock, e.getKey(),
|
||||||
|
e.getValue());
|
||||||
managers.put(e.getKey(), m);
|
managers.put(e.getKey(), m);
|
||||||
m.start(txn);
|
m.start(txn);
|
||||||
}
|
}
|
||||||
@@ -97,12 +99,14 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
public void stopService() {
|
public void stopService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
public void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
long timestamp, boolean alice) throws DbException {
|
long timestamp, boolean alice) throws DbException {
|
||||||
for (TransportKeyManager m : managers.values())
|
for (TransportKeyManager m : managers.values())
|
||||||
m.addContact(txn, c, master, timestamp, alice);
|
m.addContact(txn, c, master, timestamp, alice);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public StreamContext getStreamContext(ContactId c, TransportId t)
|
public StreamContext getStreamContext(ContactId c, TransportId t)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
// Don't allow outgoing streams to inactive contacts
|
// Don't allow outgoing streams to inactive contacts
|
||||||
@@ -123,6 +127,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public StreamContext getStreamContext(TransportId t, byte[] tag)
|
public StreamContext getStreamContext(TransportId t, byte[] tag)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
TransportKeyManager m = managers.get(t);
|
TransportKeyManager m = managers.get(t);
|
||||||
@@ -141,6 +146,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public void eventOccurred(Event e) {
|
public void eventOccurred(Event e) {
|
||||||
if (e instanceof ContactRemovedEvent) {
|
if (e instanceof ContactRemovedEvent) {
|
||||||
removeContact(((ContactRemovedEvent) e).getContactId());
|
removeContact(((ContactRemovedEvent) e).getContactId());
|
||||||
@@ -154,6 +160,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
|||||||
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() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
for (TransportKeyManager m : managers.values())
|
for (TransportKeyManager m : managers.values())
|
||||||
m.removeContact(c);
|
m.removeContact(c);
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ 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.db.Transaction;
|
||||||
import org.briarproject.api.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
import org.briarproject.api.transport.StreamContext;
|
import org.briarproject.api.transport.StreamContext;
|
||||||
import org.briarproject.api.transport.TransportKeys;
|
import org.briarproject.api.transport.TransportKeys;
|
||||||
import org.briarproject.transport.ReorderingWindow.Change;
|
import org.briarproject.transport.ReorderingWindow.Change;
|
||||||
@@ -18,10 +17,12 @@ import java.util.HashMap;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
import java.util.TimerTask;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static java.util.logging.Level.WARNING;
|
import static java.util.logging.Level.WARNING;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
@@ -34,7 +35,8 @@ class TransportKeyManager {
|
|||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
private final CryptoComponent crypto;
|
private final CryptoComponent crypto;
|
||||||
private final Timer timer;
|
private final Executor dbExecutor;
|
||||||
|
private final ScheduledExecutorService scheduler;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
private final TransportId transportId;
|
private final TransportId transportId;
|
||||||
private final long rotationPeriodLength;
|
private final long rotationPeriodLength;
|
||||||
@@ -46,11 +48,12 @@ class TransportKeyManager {
|
|||||||
private final Map<ContactId, MutableTransportKeys> keys;
|
private final Map<ContactId, MutableTransportKeys> keys;
|
||||||
|
|
||||||
TransportKeyManager(DatabaseComponent db, CryptoComponent crypto,
|
TransportKeyManager(DatabaseComponent db, CryptoComponent crypto,
|
||||||
Timer timer, Clock clock, TransportId transportId,
|
Executor dbExecutor, ScheduledExecutorService scheduler,
|
||||||
long maxLatency) {
|
Clock clock, TransportId transportId, long maxLatency) {
|
||||||
this.db = db;
|
this.db = db;
|
||||||
this.crypto = crypto;
|
this.crypto = crypto;
|
||||||
this.timer = timer;
|
this.dbExecutor = dbExecutor;
|
||||||
|
this.scheduler = scheduler;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
this.transportId = transportId;
|
this.transportId = transportId;
|
||||||
rotationPeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE;
|
rotationPeriodLength = maxLatency + MAX_CLOCK_DIFFERENCE;
|
||||||
@@ -122,7 +125,19 @@ class TransportKeyManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void scheduleKeyRotation(long now) {
|
private void scheduleKeyRotation(long now) {
|
||||||
TimerTask task = new TimerTask() {
|
Runnable task = new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
rotateKeys();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
long delay = rotationPeriodLength - now % rotationPeriodLength;
|
||||||
|
scheduler.schedule(task, delay, MILLISECONDS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rotateKeys() {
|
||||||
|
dbExecutor.execute(new Runnable() {
|
||||||
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
Transaction txn = db.startTransaction(false);
|
Transaction txn = db.startTransaction(false);
|
||||||
@@ -137,9 +152,7 @@ class TransportKeyManager {
|
|||||||
LOG.log(WARNING, e.toString(), e);
|
LOG.log(WARNING, e.toString(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
long delay = rotationPeriodLength - now % rotationPeriodLength;
|
|
||||||
timer.schedule(task, delay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void addContact(Transaction txn, ContactId c, SecretKey master,
|
void addContact(Transaction txn, ContactId c, SecretKey master,
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ import dagger.Provides;
|
|||||||
public class TransportModule {
|
public class TransportModule {
|
||||||
|
|
||||||
public static class EagerSingletons {
|
public static class EagerSingletons {
|
||||||
@Inject KeyManager keyManager;
|
@Inject
|
||||||
|
KeyManager keyManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@@ -35,7 +36,7 @@ public class TransportModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
KeyManager getKeyManager(LifecycleManager lifecycleManager,
|
KeyManager provideKeyManager(LifecycleManager lifecycleManager,
|
||||||
EventBus eventBus, KeyManagerImpl keyManager) {
|
EventBus eventBus, KeyManagerImpl keyManager) {
|
||||||
lifecycleManager.registerService(keyManager);
|
lifecycleManager.registerService(keyManager);
|
||||||
eventBus.addListener(keyManager);
|
eventBus.addListener(keyManager);
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package org.briarproject.system;
|
||||||
|
|
||||||
|
import org.briarproject.api.system.SeedProvider;
|
||||||
|
import org.briarproject.util.OsUtils;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class DesktopSeedProviderModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
SeedProvider provideSeedProvider() {
|
||||||
|
return OsUtils.isLinux() ? new LinuxSeedProvider() : null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package org.briarproject.system;
|
|
||||||
|
|
||||||
import org.briarproject.api.system.Clock;
|
|
||||||
import org.briarproject.api.system.SeedProvider;
|
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
import org.briarproject.util.OsUtils;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class DesktopSystemModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
Clock provideClock() {
|
|
||||||
return new SystemClock();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
Timer provideTimer() {
|
|
||||||
return new SystemTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
SeedProvider provideSeedProvider() {
|
|
||||||
if (OsUtils.isLinux()) {
|
|
||||||
return new LinuxSeedProvider();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
20
briar-tests/src/org/briarproject/RunAction.java
Normal file
20
briar-tests/src/org/briarproject/RunAction.java
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
package org.briarproject;
|
||||||
|
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.jmock.api.Action;
|
||||||
|
import org.jmock.api.Invocation;
|
||||||
|
|
||||||
|
public class RunAction implements Action {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object invoke(Invocation invocation) throws Throwable {
|
||||||
|
Runnable task = (Runnable) invocation.getParameter(0);
|
||||||
|
task.run();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendText("runs a runnable");
|
||||||
|
}
|
||||||
|
}
|
||||||
18
briar-tests/src/org/briarproject/TestSeedProviderModule.java
Normal file
18
briar-tests/src/org/briarproject/TestSeedProviderModule.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package org.briarproject;
|
||||||
|
|
||||||
|
import org.briarproject.api.system.SeedProvider;
|
||||||
|
|
||||||
|
import javax.inject.Singleton;
|
||||||
|
|
||||||
|
import dagger.Module;
|
||||||
|
import dagger.Provides;
|
||||||
|
|
||||||
|
@Module
|
||||||
|
public class TestSeedProviderModule {
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
SeedProvider provideSeedProvider() {
|
||||||
|
return new TestSeedProvider();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package org.briarproject;
|
|
||||||
|
|
||||||
import org.briarproject.api.system.Clock;
|
|
||||||
import org.briarproject.api.system.SeedProvider;
|
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
import org.briarproject.system.SystemClock;
|
|
||||||
import org.briarproject.system.SystemTimer;
|
|
||||||
|
|
||||||
import dagger.Module;
|
|
||||||
import dagger.Provides;
|
|
||||||
|
|
||||||
@Module
|
|
||||||
public class TestSystemModule {
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
Clock provideClock() {
|
|
||||||
return new SystemClock();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
Timer provideSystemTimer() {
|
|
||||||
return new SystemTimer();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provides
|
|
||||||
SeedProvider provideSeedProvider() {
|
|
||||||
return new TestSeedProvider();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,20 +1,13 @@
|
|||||||
package org.briarproject.plugins;
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
import org.briarproject.BriarTestCase;
|
import org.briarproject.BriarTestCase;
|
||||||
import org.briarproject.ImmediateExecutor;
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
|
||||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
|
||||||
import org.briarproject.api.event.EventBus;
|
import org.briarproject.api.event.EventBus;
|
||||||
import org.briarproject.api.event.EventListener;
|
|
||||||
import org.briarproject.api.plugins.ConnectionManager;
|
import org.briarproject.api.plugins.ConnectionManager;
|
||||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
|
||||||
import org.briarproject.api.plugins.PluginConfig;
|
import org.briarproject.api.plugins.PluginConfig;
|
||||||
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.DuplexPluginFactory;
|
import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
|
import org.briarproject.api.plugins.simplex.SimplexPluginCallback;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
|
import org.briarproject.api.plugins.simplex.SimplexPluginFactory;
|
||||||
@@ -40,11 +33,8 @@ public class PluginManagerImplTest extends BriarTestCase {
|
|||||||
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 PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
final PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
||||||
final Poller poller = context.mock(Poller.class);
|
|
||||||
final ConnectionManager connectionManager =
|
final ConnectionManager connectionManager =
|
||||||
context.mock(ConnectionManager.class);
|
context.mock(ConnectionManager.class);
|
||||||
final ConnectionRegistry connectionRegistry =
|
|
||||||
context.mock(ConnectionRegistry.class);
|
|
||||||
final SettingsManager settingsManager =
|
final SettingsManager settingsManager =
|
||||||
context.mock(SettingsManager.class);
|
context.mock(SettingsManager.class);
|
||||||
final TransportPropertyManager transportPropertyManager =
|
final TransportPropertyManager transportPropertyManager =
|
||||||
@@ -72,6 +62,12 @@ public class PluginManagerImplTest extends BriarTestCase {
|
|||||||
final TransportId duplexFailId = new TransportId("duplex1");
|
final TransportId duplexFailId = new TransportId("duplex1");
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
|
allowing(simplexPlugin).getId();
|
||||||
|
will(returnValue(simplexId));
|
||||||
|
allowing(simplexFailPlugin).getId();
|
||||||
|
will(returnValue(simplexFailId));
|
||||||
|
allowing(duplexPlugin).getId();
|
||||||
|
will(returnValue(duplexId));
|
||||||
// start()
|
// start()
|
||||||
// First simplex plugin
|
// First simplex plugin
|
||||||
oneOf(pluginConfig).getSimplexFactories();
|
oneOf(pluginConfig).getSimplexFactories();
|
||||||
@@ -108,21 +104,16 @@ public class PluginManagerImplTest extends BriarTestCase {
|
|||||||
oneOf(duplexFailFactory).createPlugin(with(any(
|
oneOf(duplexFailFactory).createPlugin(with(any(
|
||||||
DuplexPluginCallback.class)));
|
DuplexPluginCallback.class)));
|
||||||
will(returnValue(null)); // Failed to create a plugin
|
will(returnValue(null)); // Failed to create a plugin
|
||||||
// Start listening for events
|
|
||||||
oneOf(eventBus).addListener(with(any(EventListener.class)));
|
|
||||||
// stop()
|
// stop()
|
||||||
// Stop listening for events
|
|
||||||
oneOf(eventBus).removeListener(with(any(EventListener.class)));
|
|
||||||
// Stop the poller
|
|
||||||
oneOf(poller).stop();
|
|
||||||
// Stop the plugins
|
// Stop the plugins
|
||||||
oneOf(simplexPlugin).stop();
|
oneOf(simplexPlugin).stop();
|
||||||
|
oneOf(simplexFailPlugin).stop();
|
||||||
oneOf(duplexPlugin).stop();
|
oneOf(duplexPlugin).stop();
|
||||||
}});
|
}});
|
||||||
|
|
||||||
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
|
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
|
||||||
pluginConfig, poller, connectionManager, connectionRegistry,
|
pluginConfig, connectionManager, settingsManager,
|
||||||
settingsManager, transportPropertyManager, uiCallback);
|
transportPropertyManager, uiCallback);
|
||||||
|
|
||||||
// Two plugins should be started and stopped
|
// Two plugins should be started and stopped
|
||||||
p.startService();
|
p.startService();
|
||||||
@@ -130,141 +121,4 @@ public class PluginManagerImplTest extends BriarTestCase {
|
|||||||
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testConnectToNewContact() throws Exception {
|
|
||||||
Mockery context = new Mockery();
|
|
||||||
final Executor ioExecutor = new ImmediateExecutor();
|
|
||||||
final EventBus eventBus = context.mock(EventBus.class);
|
|
||||||
final PluginConfig pluginConfig = context.mock(PluginConfig.class);
|
|
||||||
final Poller poller = context.mock(Poller.class);
|
|
||||||
final ConnectionManager connectionManager =
|
|
||||||
context.mock(ConnectionManager.class);
|
|
||||||
final ConnectionRegistry connectionRegistry =
|
|
||||||
context.mock(ConnectionRegistry.class);
|
|
||||||
final SettingsManager settingsManager =
|
|
||||||
context.mock(SettingsManager.class);
|
|
||||||
final TransportPropertyManager transportPropertyManager =
|
|
||||||
context.mock(TransportPropertyManager.class);
|
|
||||||
final UiCallback uiCallback = context.mock(UiCallback.class);
|
|
||||||
final TransportConnectionWriter transportConnectionWriter =
|
|
||||||
context.mock(TransportConnectionWriter.class);
|
|
||||||
final DuplexTransportConnection duplexTransportConnection =
|
|
||||||
context.mock(DuplexTransportConnection.class);
|
|
||||||
|
|
||||||
final ContactId contactId = new ContactId(234);
|
|
||||||
|
|
||||||
// Two simplex plugins: one supports polling, the other doesn't
|
|
||||||
final SimplexPluginFactory simplexFactory =
|
|
||||||
context.mock(SimplexPluginFactory.class);
|
|
||||||
final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class);
|
|
||||||
final TransportId simplexId = new TransportId("simplex");
|
|
||||||
final SimplexPluginFactory simplexFactory1 =
|
|
||||||
context.mock(SimplexPluginFactory.class, "simplexFactory1");
|
|
||||||
final SimplexPlugin simplexPlugin1 =
|
|
||||||
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
|
||||||
final TransportId simplexId1 = new TransportId("simplex1");
|
|
||||||
|
|
||||||
// Two duplex plugins: one supports polling, the other doesn't
|
|
||||||
final DuplexPluginFactory duplexFactory =
|
|
||||||
context.mock(DuplexPluginFactory.class);
|
|
||||||
final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class);
|
|
||||||
final TransportId duplexId = new TransportId("duplex");
|
|
||||||
final DuplexPluginFactory duplexFactory1 =
|
|
||||||
context.mock(DuplexPluginFactory.class, "duplexFactory1");
|
|
||||||
final DuplexPlugin duplexPlugin1 =
|
|
||||||
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
|
||||||
final TransportId duplexId1 = new TransportId("duplex1");
|
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
|
||||||
// start()
|
|
||||||
// First simplex plugin
|
|
||||||
oneOf(pluginConfig).getSimplexFactories();
|
|
||||||
will(returnValue(Arrays.asList(simplexFactory, simplexFactory1)));
|
|
||||||
oneOf(simplexFactory).getId();
|
|
||||||
will(returnValue(simplexId));
|
|
||||||
oneOf(simplexFactory).createPlugin(with(any(
|
|
||||||
SimplexPluginCallback.class)));
|
|
||||||
will(returnValue(simplexPlugin)); // Created
|
|
||||||
oneOf(simplexPlugin).start();
|
|
||||||
will(returnValue(true)); // Started
|
|
||||||
// Second simplex plugin
|
|
||||||
oneOf(simplexFactory1).getId();
|
|
||||||
will(returnValue(simplexId1));
|
|
||||||
oneOf(simplexFactory1).createPlugin(with(any(
|
|
||||||
SimplexPluginCallback.class)));
|
|
||||||
will(returnValue(simplexPlugin1)); // Created
|
|
||||||
oneOf(simplexPlugin1).start();
|
|
||||||
will(returnValue(true)); // Started
|
|
||||||
// First duplex plugin
|
|
||||||
oneOf(pluginConfig).getDuplexFactories();
|
|
||||||
will(returnValue(Arrays.asList(duplexFactory, duplexFactory1)));
|
|
||||||
oneOf(duplexFactory).getId();
|
|
||||||
will(returnValue(duplexId));
|
|
||||||
oneOf(duplexFactory).createPlugin(with(any(
|
|
||||||
DuplexPluginCallback.class)));
|
|
||||||
will(returnValue(duplexPlugin)); // Created
|
|
||||||
oneOf(duplexPlugin).start();
|
|
||||||
will(returnValue(true)); // Started
|
|
||||||
// Second duplex plugin
|
|
||||||
oneOf(duplexFactory1).getId();
|
|
||||||
will(returnValue(duplexId1));
|
|
||||||
oneOf(duplexFactory1).createPlugin(with(any(
|
|
||||||
DuplexPluginCallback.class)));
|
|
||||||
will(returnValue(duplexPlugin1)); // Created
|
|
||||||
oneOf(duplexPlugin1).start();
|
|
||||||
will(returnValue(true)); // Started
|
|
||||||
// Start listening for events
|
|
||||||
oneOf(eventBus).addListener(with(any(EventListener.class)));
|
|
||||||
// eventOccurred()
|
|
||||||
// First simplex plugin
|
|
||||||
oneOf(simplexPlugin).shouldPoll();
|
|
||||||
will(returnValue(true));
|
|
||||||
oneOf(simplexPlugin).getId();
|
|
||||||
will(returnValue(simplexId));
|
|
||||||
oneOf(connectionRegistry).isConnected(contactId, simplexId);
|
|
||||||
will(returnValue(false));
|
|
||||||
oneOf(simplexPlugin).createWriter(contactId);
|
|
||||||
will(returnValue(transportConnectionWriter));
|
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
|
||||||
simplexId, transportConnectionWriter);
|
|
||||||
// Second simplex plugin
|
|
||||||
oneOf(simplexPlugin1).shouldPoll();
|
|
||||||
will(returnValue(false));
|
|
||||||
// First duplex plugin
|
|
||||||
oneOf(duplexPlugin).shouldPoll();
|
|
||||||
will(returnValue(true));
|
|
||||||
oneOf(duplexPlugin).getId();
|
|
||||||
will(returnValue(duplexId));
|
|
||||||
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
|
||||||
will(returnValue(false));
|
|
||||||
oneOf(duplexPlugin).createConnection(contactId);
|
|
||||||
will(returnValue(duplexTransportConnection));
|
|
||||||
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
|
||||||
duplexId, duplexTransportConnection);
|
|
||||||
// Second duplex plugin
|
|
||||||
oneOf(duplexPlugin1).shouldPoll();
|
|
||||||
will(returnValue(false));
|
|
||||||
// stop()
|
|
||||||
// Stop listening for events
|
|
||||||
oneOf(eventBus).removeListener(with(any(EventListener.class)));
|
|
||||||
// Stop the poller
|
|
||||||
oneOf(poller).stop();
|
|
||||||
// Stop the plugins
|
|
||||||
oneOf(simplexPlugin).stop();
|
|
||||||
oneOf(simplexPlugin1).stop();
|
|
||||||
oneOf(duplexPlugin).stop();
|
|
||||||
oneOf(duplexPlugin1).stop();
|
|
||||||
}});
|
|
||||||
|
|
||||||
PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus,
|
|
||||||
pluginConfig, poller, connectionManager, connectionRegistry,
|
|
||||||
settingsManager, transportPropertyManager, uiCallback);
|
|
||||||
|
|
||||||
p.startService();
|
|
||||||
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
|
||||||
p.stopService();
|
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
354
briar-tests/src/org/briarproject/plugins/PollerTest.java
Normal file
354
briar-tests/src/org/briarproject/plugins/PollerTest.java
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
|
import org.briarproject.BriarTestCase;
|
||||||
|
import org.briarproject.ImmediateExecutor;
|
||||||
|
import org.briarproject.RunAction;
|
||||||
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.contact.ContactId;
|
||||||
|
import org.briarproject.api.event.ConnectionClosedEvent;
|
||||||
|
import org.briarproject.api.event.ConnectionOpenedEvent;
|
||||||
|
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||||
|
import org.briarproject.api.event.TransportEnabledEvent;
|
||||||
|
import org.briarproject.api.plugins.ConnectionManager;
|
||||||
|
import org.briarproject.api.plugins.ConnectionRegistry;
|
||||||
|
import org.briarproject.api.plugins.Plugin;
|
||||||
|
import org.briarproject.api.plugins.PluginManager;
|
||||||
|
import org.briarproject.api.plugins.TransportConnectionWriter;
|
||||||
|
import org.briarproject.api.plugins.duplex.DuplexPlugin;
|
||||||
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
|
import org.briarproject.api.plugins.simplex.SimplexPlugin;
|
||||||
|
import org.briarproject.api.system.Clock;
|
||||||
|
import org.jmock.Expectations;
|
||||||
|
import org.jmock.Mockery;
|
||||||
|
import org.jmock.lib.legacy.ClassImposteriser;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
|
|
||||||
|
public class PollerTest extends BriarTestCase {
|
||||||
|
|
||||||
|
private final ContactId contactId = new ContactId(234);
|
||||||
|
private final int pollingInterval = 60 * 1000;
|
||||||
|
private final long now = System.currentTimeMillis();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectOnContactStatusChanged() throws Exception {
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||||
|
final Executor ioExecutor = new ImmediateExecutor();
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
|
final ConnectionManager connectionManager =
|
||||||
|
context.mock(ConnectionManager.class);
|
||||||
|
final ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
|
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||||
|
final SecureRandom random = context.mock(SecureRandom.class);
|
||||||
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
|
// Two simplex plugins: one supports polling, the other doesn't
|
||||||
|
final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class);
|
||||||
|
final SimplexPlugin simplexPlugin1 =
|
||||||
|
context.mock(SimplexPlugin.class, "simplexPlugin1");
|
||||||
|
final TransportId simplexId1 = new TransportId("simplex1");
|
||||||
|
final List<SimplexPlugin> simplexPlugins = Arrays.asList(simplexPlugin,
|
||||||
|
simplexPlugin1);
|
||||||
|
final TransportConnectionWriter simplexWriter =
|
||||||
|
context.mock(TransportConnectionWriter.class);
|
||||||
|
|
||||||
|
// Two duplex plugins: one supports polling, the other doesn't
|
||||||
|
final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class);
|
||||||
|
final TransportId duplexId = new TransportId("duplex");
|
||||||
|
final DuplexPlugin duplexPlugin1 =
|
||||||
|
context.mock(DuplexPlugin.class, "duplexPlugin1");
|
||||||
|
final List<DuplexPlugin> duplexPlugins = Arrays.asList(duplexPlugin,
|
||||||
|
duplexPlugin1);
|
||||||
|
final DuplexTransportConnection duplexConnection =
|
||||||
|
context.mock(DuplexTransportConnection.class);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
// Get the simplex plugins
|
||||||
|
oneOf(pluginManager).getSimplexPlugins();
|
||||||
|
will(returnValue(simplexPlugins));
|
||||||
|
// The first plugin doesn't support polling
|
||||||
|
oneOf(simplexPlugin).shouldPoll();
|
||||||
|
will(returnValue(false));
|
||||||
|
// The second plugin supports polling
|
||||||
|
oneOf(simplexPlugin1).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Check whether the contact is already connected
|
||||||
|
oneOf(simplexPlugin1).getId();
|
||||||
|
will(returnValue(simplexId1));
|
||||||
|
oneOf(connectionRegistry).isConnected(contactId, simplexId1);
|
||||||
|
will(returnValue(false));
|
||||||
|
// Connect to the contact
|
||||||
|
oneOf(simplexPlugin1).createWriter(contactId);
|
||||||
|
will(returnValue(simplexWriter));
|
||||||
|
// Pass the connection to the connection manager
|
||||||
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
|
simplexId1, simplexWriter);
|
||||||
|
// Get the duplex plugins
|
||||||
|
oneOf(pluginManager).getDuplexPlugins();
|
||||||
|
will(returnValue(duplexPlugins));
|
||||||
|
// The first plugin supports polling
|
||||||
|
oneOf(duplexPlugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Check whether the contact is already connected
|
||||||
|
oneOf(duplexPlugin).getId();
|
||||||
|
will(returnValue(duplexId));
|
||||||
|
oneOf(connectionRegistry).isConnected(contactId, duplexId);
|
||||||
|
will(returnValue(false));
|
||||||
|
// Connect to the contact
|
||||||
|
oneOf(duplexPlugin).createConnection(contactId);
|
||||||
|
will(returnValue(duplexConnection));
|
||||||
|
// Pass the connection to the connection manager
|
||||||
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
|
duplexId, duplexConnection);
|
||||||
|
// The second plugin doesn't support polling
|
||||||
|
oneOf(duplexPlugin1).shouldPoll();
|
||||||
|
will(returnValue(false));
|
||||||
|
}});
|
||||||
|
|
||||||
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, random, clock);
|
||||||
|
|
||||||
|
p.eventOccurred(new ContactStatusChangedEvent(contactId, true));
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRescheduleAndReconnectOnConnectionClosed()
|
||||||
|
throws Exception {
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||||
|
final Executor ioExecutor = new ImmediateExecutor();
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
|
final ConnectionManager connectionManager =
|
||||||
|
context.mock(ConnectionManager.class);
|
||||||
|
final ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
|
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||||
|
final SecureRandom random = context.mock(SecureRandom.class);
|
||||||
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
|
final DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
|
final TransportId transportId = new TransportId("id");
|
||||||
|
final DuplexTransportConnection duplexConnection =
|
||||||
|
context.mock(DuplexTransportConnection.class);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(plugin).getId();
|
||||||
|
will(returnValue(transportId));
|
||||||
|
// reschedule()
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Schedule the next poll
|
||||||
|
oneOf(plugin).getPollingInterval();
|
||||||
|
will(returnValue(pollingInterval));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
|
with((long) pollingInterval), with(MILLISECONDS));
|
||||||
|
// connectToContact()
|
||||||
|
// Check whether the contact is already connected
|
||||||
|
oneOf(connectionRegistry).isConnected(contactId, transportId);
|
||||||
|
will(returnValue(false));
|
||||||
|
// Connect to the contact
|
||||||
|
oneOf(plugin).createConnection(contactId);
|
||||||
|
will(returnValue(duplexConnection));
|
||||||
|
// Pass the connection to the connection manager
|
||||||
|
oneOf(connectionManager).manageOutgoingConnection(contactId,
|
||||||
|
transportId, duplexConnection);
|
||||||
|
}});
|
||||||
|
|
||||||
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, random, clock);
|
||||||
|
|
||||||
|
p.eventOccurred(new ConnectionClosedEvent(contactId, transportId,
|
||||||
|
false));
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRescheduleOnConnectionOpened() throws Exception {
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||||
|
final Executor ioExecutor = new ImmediateExecutor();
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
|
final ConnectionManager connectionManager =
|
||||||
|
context.mock(ConnectionManager.class);
|
||||||
|
final ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
|
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||||
|
final SecureRandom random = context.mock(SecureRandom.class);
|
||||||
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
|
final DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
|
final TransportId transportId = new TransportId("id");
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(plugin).getId();
|
||||||
|
will(returnValue(transportId));
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Schedule the next poll
|
||||||
|
oneOf(plugin).getPollingInterval();
|
||||||
|
will(returnValue(pollingInterval));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
|
with((long) pollingInterval), with(MILLISECONDS));
|
||||||
|
}});
|
||||||
|
|
||||||
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, random, clock);
|
||||||
|
|
||||||
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
|
false));
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRescheduleDoesNotReplaceEarlierTask() throws Exception {
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||||
|
final Executor ioExecutor = new ImmediateExecutor();
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
|
final ConnectionManager connectionManager =
|
||||||
|
context.mock(ConnectionManager.class);
|
||||||
|
final ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
|
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||||
|
final SecureRandom random = context.mock(SecureRandom.class);
|
||||||
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
|
final DuplexPlugin plugin = context.mock(DuplexPlugin.class);
|
||||||
|
final TransportId transportId = new TransportId("id");
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(plugin).getId();
|
||||||
|
will(returnValue(transportId));
|
||||||
|
// First event
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Schedule the next poll
|
||||||
|
oneOf(plugin).getPollingInterval();
|
||||||
|
will(returnValue(pollingInterval));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
|
with((long) pollingInterval), with(MILLISECONDS));
|
||||||
|
// Second event
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Don't replace the previously scheduled task, due earlier
|
||||||
|
oneOf(plugin).getPollingInterval();
|
||||||
|
will(returnValue(pollingInterval));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now + 1));
|
||||||
|
}});
|
||||||
|
|
||||||
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, random, clock);
|
||||||
|
|
||||||
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
|
false));
|
||||||
|
p.eventOccurred(new ConnectionOpenedEvent(contactId, transportId,
|
||||||
|
false));
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPollOnTransportEnabled() throws Exception {
|
||||||
|
Mockery context = new Mockery();
|
||||||
|
context.setImposteriser(ClassImposteriser.INSTANCE);
|
||||||
|
final Executor ioExecutor = new ImmediateExecutor();
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
|
final ConnectionManager connectionManager =
|
||||||
|
context.mock(ConnectionManager.class);
|
||||||
|
final ConnectionRegistry connectionRegistry =
|
||||||
|
context.mock(ConnectionRegistry.class);
|
||||||
|
final PluginManager pluginManager = context.mock(PluginManager.class);
|
||||||
|
final SecureRandom random = context.mock(SecureRandom.class);
|
||||||
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
|
final Plugin plugin = context.mock(Plugin.class);
|
||||||
|
final TransportId transportId = new TransportId("id");
|
||||||
|
final List<ContactId> connected = Collections.singletonList(contactId);
|
||||||
|
|
||||||
|
context.checking(new Expectations() {{
|
||||||
|
allowing(plugin).getId();
|
||||||
|
will(returnValue(transportId));
|
||||||
|
// Get the plugin
|
||||||
|
oneOf(pluginManager).getPlugin(transportId);
|
||||||
|
will(returnValue(plugin));
|
||||||
|
// The plugin supports polling
|
||||||
|
oneOf(plugin).shouldPoll();
|
||||||
|
will(returnValue(true));
|
||||||
|
// Schedule a polling task immediately
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L),
|
||||||
|
with(MILLISECONDS));
|
||||||
|
will(new RunAction());
|
||||||
|
// Running the polling task schedules the next polling task
|
||||||
|
oneOf(plugin).getPollingInterval();
|
||||||
|
will(returnValue(pollingInterval));
|
||||||
|
oneOf(random).nextDouble();
|
||||||
|
will(returnValue(0.5));
|
||||||
|
oneOf(clock).currentTimeMillis();
|
||||||
|
will(returnValue(now));
|
||||||
|
oneOf(scheduler).schedule(with(any(Runnable.class)),
|
||||||
|
with((long) (pollingInterval * 0.5)), with(MILLISECONDS));
|
||||||
|
// Poll the plugin
|
||||||
|
oneOf(connectionRegistry).getConnectedContacts(transportId);
|
||||||
|
will(returnValue(connected));
|
||||||
|
oneOf(plugin).poll(connected);
|
||||||
|
}});
|
||||||
|
|
||||||
|
Poller p = new Poller(ioExecutor, scheduler, connectionManager,
|
||||||
|
connectionRegistry, pluginManager, random, clock);
|
||||||
|
|
||||||
|
p.eventOccurred(new TransportEnabledEvent(transportId));
|
||||||
|
|
||||||
|
context.assertIsSatisfied();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package org.briarproject.transport;
|
package org.briarproject.transport;
|
||||||
|
|
||||||
import org.briarproject.BriarTestCase;
|
import org.briarproject.BriarTestCase;
|
||||||
|
import org.briarproject.RunAction;
|
||||||
import org.briarproject.TestUtils;
|
import org.briarproject.TestUtils;
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
@@ -9,7 +10,6 @@ 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.db.Transaction;
|
||||||
import org.briarproject.api.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
import org.briarproject.api.transport.IncomingKeys;
|
import org.briarproject.api.transport.IncomingKeys;
|
||||||
import org.briarproject.api.transport.OutgoingKeys;
|
import org.briarproject.api.transport.OutgoingKeys;
|
||||||
import org.briarproject.api.transport.StreamContext;
|
import org.briarproject.api.transport.StreamContext;
|
||||||
@@ -28,8 +28,10 @@ import java.util.LinkedHashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.TimerTask;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
||||||
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
import static org.briarproject.api.transport.TransportConstants.MAX_CLOCK_DIFFERENCE;
|
||||||
import static org.briarproject.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
import static org.briarproject.api.transport.TransportConstants.REORDERING_WINDOW_SIZE;
|
||||||
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
import static org.briarproject.api.transport.TransportConstants.TAG_LENGTH;
|
||||||
@@ -56,11 +58,12 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
final Map<ContactId, TransportKeys> loaded =
|
final Map<ContactId, TransportKeys> loaded = new LinkedHashMap<>();
|
||||||
new LinkedHashMap<ContactId, TransportKeys>();
|
|
||||||
final TransportKeys shouldRotate = createTransportKeys(900, 0);
|
final TransportKeys shouldRotate = createTransportKeys(900, 0);
|
||||||
final TransportKeys shouldNotRotate = createTransportKeys(1000, 0);
|
final TransportKeys shouldNotRotate = createTransportKeys(1000, 0);
|
||||||
loaded.put(contactId, shouldRotate);
|
loaded.put(contactId, shouldRotate);
|
||||||
@@ -90,12 +93,12 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
oneOf(db).updateTransportKeys(txn,
|
oneOf(db).updateTransportKeys(txn,
|
||||||
Collections.singletonMap(contactId, rotated));
|
Collections.singletonMap(contactId, rotated));
|
||||||
// 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(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength - 1));
|
with(rotationPeriodLength - 1), with(MILLISECONDS));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
transportKeyManager.start(txn);
|
transportKeyManager.start(txn);
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
@@ -106,7 +109,9 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
final boolean alice = true;
|
final boolean alice = true;
|
||||||
@@ -135,7 +140,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
// The timestamp is 1 ms before the start of rotation period 1000
|
// The timestamp is 1 ms before the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000 - 1;
|
long timestamp = rotationPeriodLength * 1000 - 1;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
@@ -150,13 +155,15 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
final Transaction txn = new Transaction(null, false);
|
final Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
assertNull(transportKeyManager.getStreamContext(txn, contactId));
|
||||||
|
|
||||||
context.assertIsSatisfied();
|
context.assertIsSatisfied();
|
||||||
@@ -168,7 +175,9 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
final boolean alice = true;
|
final boolean alice = true;
|
||||||
@@ -198,7 +207,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
@@ -213,7 +222,9 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
final boolean alice = true;
|
final boolean alice = true;
|
||||||
@@ -245,7 +256,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
@@ -271,7 +282,9 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
final boolean alice = true;
|
final boolean alice = true;
|
||||||
@@ -299,7 +312,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
@@ -315,13 +328,15 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.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);
|
||||||
// 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<>();
|
||||||
final Transaction txn = new Transaction(null, false);
|
final Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new Expectations() {{
|
context.checking(new Expectations() {{
|
||||||
@@ -352,7 +367,7 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
}});
|
}});
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
// The timestamp is at the start of rotation period 1000
|
// The timestamp is at the start of rotation period 1000
|
||||||
long timestamp = rotationPeriodLength * 1000;
|
long timestamp = rotationPeriodLength * 1000;
|
||||||
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
transportKeyManager.addContact(txn, contactId, masterKey, timestamp,
|
||||||
@@ -381,7 +396,9 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
Mockery context = new Mockery();
|
Mockery context = new Mockery();
|
||||||
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
final DatabaseComponent db = context.mock(DatabaseComponent.class);
|
||||||
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
final CryptoComponent crypto = context.mock(CryptoComponent.class);
|
||||||
final Timer timer = context.mock(Timer.class);
|
final Executor dbExecutor = context.mock(Executor.class);
|
||||||
|
final ScheduledExecutorService scheduler =
|
||||||
|
context.mock(ScheduledExecutorService.class);
|
||||||
final Clock clock = context.mock(Clock.class);
|
final Clock clock = context.mock(Clock.class);
|
||||||
|
|
||||||
final TransportKeys transportKeys = createTransportKeys(1000, 0);
|
final TransportKeys transportKeys = createTransportKeys(1000, 0);
|
||||||
@@ -408,9 +425,11 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
will(new EncodeTagAction());
|
will(new EncodeTagAction());
|
||||||
}
|
}
|
||||||
// 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(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength));
|
with(rotationPeriodLength), with(MILLISECONDS));
|
||||||
will(new RunTimerTaskAction());
|
will(new RunAction());
|
||||||
|
oneOf(dbExecutor).execute(with(any(Runnable.class)));
|
||||||
|
will(new RunAction());
|
||||||
// Start a transaction for key rotation
|
// Start a transaction for key rotation
|
||||||
oneOf(db).startTransaction(false);
|
oneOf(db).startTransaction(false);
|
||||||
will(returnValue(txn1));
|
will(returnValue(txn1));
|
||||||
@@ -431,14 +450,14 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
oneOf(db).updateTransportKeys(txn1,
|
oneOf(db).updateTransportKeys(txn1,
|
||||||
Collections.singletonMap(contactId, rotated));
|
Collections.singletonMap(contactId, rotated));
|
||||||
// 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(scheduler).schedule(with(any(Runnable.class)),
|
||||||
with(rotationPeriodLength));
|
with(rotationPeriodLength), with(MILLISECONDS));
|
||||||
// Commit the key rotation transaction
|
// Commit the key rotation transaction
|
||||||
oneOf(db).endTransaction(txn1);
|
oneOf(db).endTransaction(txn1);
|
||||||
}});
|
}});
|
||||||
|
|
||||||
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
TransportKeyManager transportKeyManager = new TransportKeyManager(db,
|
||||||
crypto, timer, clock, transportId, maxLatency);
|
crypto, dbExecutor, scheduler, clock, transportId, maxLatency);
|
||||||
transportKeyManager.start(txn);
|
transportKeyManager.start(txn);
|
||||||
assertTrue(txn1.isComplete());
|
assertTrue(txn1.isComplete());
|
||||||
|
|
||||||
@@ -483,19 +502,4 @@ public class TransportKeyManagerTest extends BriarTestCase {
|
|||||||
description.appendText("encodes a tag");
|
description.appendText("encodes a tag");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class RunTimerTaskAction implements Action {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object invoke(Invocation invocation) throws Throwable {
|
|
||||||
TimerTask task = (TimerTask) invocation.getParameter(0);
|
|
||||||
task.run();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("schedules a timer task");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user