mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-16 20:59:54 +01:00
New polling logic for Bluetooth. #251
The polling interval increases exponentially each time polling is unsuccessful, up to a maximum of 60 minutes. The interval is reset to 2 minutes whenever a connection is made and whenever Bluetooth is re-enabled.
This commit is contained in:
@@ -8,6 +8,7 @@ import com.google.inject.Provides;
|
|||||||
import org.briarproject.api.android.AndroidExecutor;
|
import org.briarproject.api.android.AndroidExecutor;
|
||||||
import org.briarproject.api.event.EventBus;
|
import org.briarproject.api.event.EventBus;
|
||||||
import org.briarproject.api.lifecycle.IoExecutor;
|
import org.briarproject.api.lifecycle.IoExecutor;
|
||||||
|
import org.briarproject.api.plugins.BackoffFactory;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginConfig;
|
import org.briarproject.api.plugins.duplex.DuplexPluginConfig;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
|
import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
|
import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
|
||||||
@@ -37,11 +38,11 @@ public class AndroidPluginsModule extends PluginsModule {
|
|||||||
@Provides
|
@Provides
|
||||||
DuplexPluginConfig getDuplexPluginConfig(@IoExecutor Executor ioExecutor,
|
DuplexPluginConfig getDuplexPluginConfig(@IoExecutor Executor ioExecutor,
|
||||||
AndroidExecutor androidExecutor, Application app,
|
AndroidExecutor androidExecutor, Application app,
|
||||||
SecureRandom random, LocationUtils locationUtils,
|
SecureRandom random, BackoffFactory backoffFactory,
|
||||||
EventBus eventBus) {
|
LocationUtils locationUtils, EventBus eventBus) {
|
||||||
Context appContext = app.getApplicationContext();
|
Context appContext = app.getApplicationContext();
|
||||||
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
|
DuplexPluginFactory bluetooth = new DroidtoothPluginFactory(ioExecutor,
|
||||||
androidExecutor, appContext, random);
|
androidExecutor, appContext, random, backoffFactory);
|
||||||
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
|
DuplexPluginFactory tor = new TorPluginFactory(ioExecutor, appContext,
|
||||||
locationUtils, eventBus);
|
locationUtils, eventBus);
|
||||||
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
DuplexPluginFactory lan = new AndroidLanTcpPluginFactory(ioExecutor,
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import org.briarproject.api.TransportId;
|
|||||||
import org.briarproject.api.android.AndroidExecutor;
|
import org.briarproject.api.android.AndroidExecutor;
|
||||||
import org.briarproject.api.contact.ContactId;
|
import org.briarproject.api.contact.ContactId;
|
||||||
import org.briarproject.api.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.plugins.Backoff;
|
||||||
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.DuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
@@ -68,8 +69,9 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final int maxLatency, pollingInterval;
|
private final int maxLatency;
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
private volatile boolean wasEnabledByUs = false;
|
private volatile boolean wasEnabledByUs = false;
|
||||||
@@ -81,16 +83,15 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
|
|
||||||
DroidtoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor,
|
DroidtoothPlugin(Executor ioExecutor, AndroidExecutor androidExecutor,
|
||||||
Context appContext, SecureRandom secureRandom, Clock clock,
|
Context appContext, SecureRandom secureRandom, Clock clock,
|
||||||
DuplexPluginCallback callback, int maxLatency,
|
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||||
int pollingInterval) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
this.clock = clock;
|
this.clock = clock;
|
||||||
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.pollingInterval = pollingInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
@@ -173,6 +174,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
LOG.info("Socket bound");
|
LOG.info("Socket bound");
|
||||||
socket = ss;
|
socket = ss;
|
||||||
|
backoff.reset();
|
||||||
callback.transportEnabled();
|
callback.transportEnabled();
|
||||||
acceptContactConnections();
|
acceptContactConnections();
|
||||||
}
|
}
|
||||||
@@ -216,6 +218,7 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
String address = s.getRemoteDevice().getAddress();
|
String address = s.getRemoteDevice().getAddress();
|
||||||
LOG.info("Connection from " + address);
|
LOG.info("Connection from " + address);
|
||||||
}
|
}
|
||||||
|
backoff.reset();
|
||||||
callback.incomingConnectionCreated(wrapSocket(s));
|
callback.incomingConnectionCreated(wrapSocket(s));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,11 +247,12 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return pollingInterval;
|
return backoff.getPollingInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void poll(Collection<ContactId> connected) {
|
public void poll(Collection<ContactId> connected) {
|
||||||
if (!isRunning()) return;
|
if (!isRunning()) return;
|
||||||
|
backoff.increment();
|
||||||
// Try to connect to known devices in parallel
|
// Try to connect to known devices in parallel
|
||||||
Map<ContactId, TransportProperties> remote =
|
Map<ContactId, TransportProperties> remote =
|
||||||
callback.getRemoteProperties();
|
callback.getRemoteProperties();
|
||||||
@@ -263,8 +267,10 @@ class DroidtoothPlugin implements DuplexPlugin {
|
|||||||
public void run() {
|
public void run() {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
BluetoothSocket s = connect(address, uuid);
|
BluetoothSocket s = connect(address, uuid);
|
||||||
if (s != null)
|
if (s != null) {
|
||||||
|
backoff.reset();
|
||||||
callback.outgoingConnectionCreated(c, wrapSocket(s));
|
callback.outgoingConnectionCreated(c, wrapSocket(s));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +1,42 @@
|
|||||||
package org.briarproject.plugins.droidtooth;
|
package org.briarproject.plugins.droidtooth;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
import android.content.Context;
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
import org.briarproject.api.android.AndroidExecutor;
|
import org.briarproject.api.android.AndroidExecutor;
|
||||||
|
import org.briarproject.api.plugins.Backoff;
|
||||||
|
import org.briarproject.api.plugins.BackoffFactory;
|
||||||
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.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.system.SystemClock;
|
import org.briarproject.system.SystemClock;
|
||||||
|
|
||||||
import android.content.Context;
|
import java.security.SecureRandom;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public class DroidtoothPluginFactory implements DuplexPluginFactory {
|
public class DroidtoothPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
||||||
private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes
|
private static final int MIN_POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
|
||||||
|
private static final int MAX_POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour
|
||||||
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final AndroidExecutor androidExecutor;
|
private final AndroidExecutor androidExecutor;
|
||||||
private final Context appContext;
|
private final Context appContext;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
|
private final BackoffFactory backoffFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
public DroidtoothPluginFactory(Executor ioExecutor,
|
public DroidtoothPluginFactory(Executor ioExecutor,
|
||||||
AndroidExecutor androidExecutor, Context appContext,
|
AndroidExecutor androidExecutor, Context appContext,
|
||||||
SecureRandom secureRandom) {
|
SecureRandom secureRandom, BackoffFactory backoffFactory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.androidExecutor = androidExecutor;
|
this.androidExecutor = androidExecutor;
|
||||||
this.appContext = appContext;
|
this.appContext = appContext;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
|
this.backoffFactory = backoffFactory;
|
||||||
clock = new SystemClock();
|
clock = new SystemClock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +45,9 @@ public class DroidtoothPluginFactory implements DuplexPluginFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
return new DroidtoothPlugin(ioExecutor, androidExecutor, appContext,
|
return new DroidtoothPlugin(ioExecutor, androidExecutor, appContext,
|
||||||
secureRandom, clock, callback, MAX_LATENCY, POLLING_INTERVAL);
|
secureRandom, clock, backoff, callback, MAX_LATENCY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
22
briar-api/src/org/briarproject/api/plugins/Backoff.java
Normal file
22
briar-api/src/org/briarproject/api/plugins/Backoff.java
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
package org.briarproject.api.plugins;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates polling intervals for transport plugins that use backoff.
|
||||||
|
*/
|
||||||
|
public interface Backoff {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the current polling interval.
|
||||||
|
*/
|
||||||
|
int getPollingInterval();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increments the backoff counter.
|
||||||
|
*/
|
||||||
|
void increment();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the backoff counter.
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.briarproject.api.plugins;
|
||||||
|
|
||||||
|
public interface BackoffFactory {
|
||||||
|
|
||||||
|
Backoff createBackoff(int minInterval, int maxInterval,
|
||||||
|
double base);
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
|
import org.briarproject.api.plugins.Backoff;
|
||||||
|
import org.briarproject.api.plugins.BackoffFactory;
|
||||||
|
|
||||||
|
class BackoffFactoryImpl implements BackoffFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Backoff createBackoff(int minInterval, int maxInterval,
|
||||||
|
double base) {
|
||||||
|
return new BackoffImpl(minInterval, maxInterval, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
37
briar-core/src/org/briarproject/plugins/BackoffImpl.java
Normal file
37
briar-core/src/org/briarproject/plugins/BackoffImpl.java
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
|
import org.briarproject.api.plugins.Backoff;
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
class BackoffImpl implements Backoff {
|
||||||
|
|
||||||
|
private final int minInterval, maxInterval;
|
||||||
|
private final double base;
|
||||||
|
private final AtomicInteger backoff;
|
||||||
|
|
||||||
|
BackoffImpl(int minInterval, int maxInterval, double base) {
|
||||||
|
this.minInterval = minInterval;
|
||||||
|
this.maxInterval = maxInterval;
|
||||||
|
this.base = base;
|
||||||
|
backoff = new AtomicInteger(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getPollingInterval() {
|
||||||
|
double multiplier = Math.pow(base, backoff.get());
|
||||||
|
// Large or infinite values will be rounded to Integer.MAX_VALUE
|
||||||
|
int interval = (int) (minInterval * multiplier);
|
||||||
|
return Math.min(interval, maxInterval);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void increment() {
|
||||||
|
backoff.incrementAndGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reset() {
|
||||||
|
backoff.set(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,19 +1,21 @@
|
|||||||
package org.briarproject.plugins;
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
import javax.inject.Singleton;
|
import com.google.inject.AbstractModule;
|
||||||
|
import com.google.inject.Provides;
|
||||||
|
|
||||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||||
|
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 com.google.inject.AbstractModule;
|
import javax.inject.Singleton;
|
||||||
import com.google.inject.Provides;
|
|
||||||
|
|
||||||
public class PluginsModule extends AbstractModule {
|
public class PluginsModule extends AbstractModule {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
bind(BackoffFactory.class).to(BackoffFactoryImpl.class);
|
||||||
bind(Poller.class).to(PollerImpl.class);
|
bind(Poller.class).to(PollerImpl.class);
|
||||||
bind(ConnectionManager.class).to(ConnectionManagerImpl.class);
|
bind(ConnectionManager.class).to(ConnectionManagerImpl.class);
|
||||||
bind(ConnectionRegistry.class).to(
|
bind(ConnectionRegistry.class).to(
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package org.briarproject.plugins;
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
import static java.util.logging.Level.INFO;
|
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.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
@@ -8,10 +11,7 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import org.briarproject.api.lifecycle.IoExecutor;
|
import static java.util.logging.Level.INFO;
|
||||||
import org.briarproject.api.plugins.ConnectionRegistry;
|
|
||||||
import org.briarproject.api.plugins.Plugin;
|
|
||||||
import org.briarproject.api.system.Timer;
|
|
||||||
|
|
||||||
class PollerImpl implements Poller {
|
class PollerImpl implements Poller {
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import com.google.inject.Provides;
|
|||||||
|
|
||||||
import org.briarproject.api.lifecycle.IoExecutor;
|
import org.briarproject.api.lifecycle.IoExecutor;
|
||||||
import org.briarproject.api.lifecycle.ShutdownManager;
|
import org.briarproject.api.lifecycle.ShutdownManager;
|
||||||
|
import org.briarproject.api.plugins.BackoffFactory;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginConfig;
|
import org.briarproject.api.plugins.duplex.DuplexPluginConfig;
|
||||||
import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
|
import org.briarproject.api.plugins.duplex.DuplexPluginFactory;
|
||||||
import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
|
import org.briarproject.api.plugins.simplex.SimplexPluginConfig;
|
||||||
@@ -39,10 +40,11 @@ public class DesktopPluginsModule extends PluginsModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
DuplexPluginConfig getDuplexPluginConfig(@IoExecutor Executor ioExecutor,
|
DuplexPluginConfig getDuplexPluginConfig(@IoExecutor Executor ioExecutor,
|
||||||
SecureRandom random, ReliabilityLayerFactory reliabilityFactory,
|
SecureRandom random, BackoffFactory backoffFactory,
|
||||||
|
ReliabilityLayerFactory reliabilityFactory,
|
||||||
ShutdownManager shutdownManager) {
|
ShutdownManager shutdownManager) {
|
||||||
DuplexPluginFactory bluetooth = new BluetoothPluginFactory(ioExecutor,
|
DuplexPluginFactory bluetooth = new BluetoothPluginFactory(ioExecutor,
|
||||||
random);
|
random, backoffFactory);
|
||||||
DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor,
|
DuplexPluginFactory modem = new ModemPluginFactory(ioExecutor,
|
||||||
reliabilityFactory);
|
reliabilityFactory);
|
||||||
DuplexPluginFactory lan = new LanTcpPluginFactory(ioExecutor);
|
DuplexPluginFactory lan = new LanTcpPluginFactory(ioExecutor);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.briarproject.plugins.bluetooth;
|
|||||||
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.crypto.PseudoRandom;
|
import org.briarproject.api.crypto.PseudoRandom;
|
||||||
|
import org.briarproject.api.plugins.Backoff;
|
||||||
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.DuplexTransportConnection;
|
import org.briarproject.api.plugins.duplex.DuplexTransportConnection;
|
||||||
@@ -43,25 +44,25 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
private static final int UUID_BYTES = 16;
|
private static final int UUID_BYTES = 16;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final Clock clock;
|
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
|
private final Clock clock;
|
||||||
|
private final Backoff backoff;
|
||||||
private final DuplexPluginCallback callback;
|
private final DuplexPluginCallback callback;
|
||||||
private final int maxLatency, pollingInterval;
|
private final int maxLatency;
|
||||||
private final Semaphore discoverySemaphore = new Semaphore(1);
|
private final Semaphore discoverySemaphore = new Semaphore(1);
|
||||||
|
|
||||||
private volatile boolean running = false;
|
private volatile boolean running = false;
|
||||||
private volatile StreamConnectionNotifier socket = null;
|
private volatile StreamConnectionNotifier socket = null;
|
||||||
private volatile LocalDevice localDevice = null;
|
private volatile LocalDevice localDevice = null;
|
||||||
|
|
||||||
BluetoothPlugin(Executor ioExecutor, Clock clock, SecureRandom secureRandom,
|
BluetoothPlugin(Executor ioExecutor, SecureRandom secureRandom, Clock clock,
|
||||||
DuplexPluginCallback callback, int maxLatency,
|
Backoff backoff, DuplexPluginCallback callback, int maxLatency) {
|
||||||
int pollingInterval) {
|
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.clock = clock;
|
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
|
this.clock = clock;
|
||||||
|
this.backoff = backoff;
|
||||||
this.callback = callback;
|
this.callback = callback;
|
||||||
this.maxLatency = maxLatency;
|
this.maxLatency = maxLatency;
|
||||||
this.pollingInterval = pollingInterval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TransportId getId() {
|
public TransportId getId() {
|
||||||
@@ -117,6 +118,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
socket = ss;
|
socket = ss;
|
||||||
|
backoff.reset();
|
||||||
callback.transportEnabled();
|
callback.transportEnabled();
|
||||||
acceptContactConnections(ss);
|
acceptContactConnections(ss);
|
||||||
}
|
}
|
||||||
@@ -160,6 +162,7 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
if (LOG.isLoggable(INFO)) LOG.info(e.toString());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
backoff.reset();
|
||||||
callback.incomingConnectionCreated(wrapSocket(s));
|
callback.incomingConnectionCreated(wrapSocket(s));
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
}
|
}
|
||||||
@@ -183,11 +186,12 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getPollingInterval() {
|
public int getPollingInterval() {
|
||||||
return pollingInterval;
|
return backoff.getPollingInterval();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void poll(final Collection<ContactId> connected) {
|
public void poll(final Collection<ContactId> connected) {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
|
backoff.increment();
|
||||||
// Try to connect to known devices in parallel
|
// Try to connect to known devices in parallel
|
||||||
Map<ContactId, TransportProperties> remote =
|
Map<ContactId, TransportProperties> remote =
|
||||||
callback.getRemoteProperties();
|
callback.getRemoteProperties();
|
||||||
@@ -202,8 +206,10 @@ class BluetoothPlugin implements DuplexPlugin {
|
|||||||
public void run() {
|
public void run() {
|
||||||
if (!running) return;
|
if (!running) return;
|
||||||
StreamConnection s = connect(makeUrl(address, uuid));
|
StreamConnection s = connect(makeUrl(address, uuid));
|
||||||
if (s != null)
|
if (s != null) {
|
||||||
|
backoff.reset();
|
||||||
callback.outgoingConnectionCreated(c, wrapSocket(s));
|
callback.outgoingConnectionCreated(c, wrapSocket(s));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,34 @@
|
|||||||
package org.briarproject.plugins.bluetooth;
|
package org.briarproject.plugins.bluetooth;
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
|
|
||||||
import org.briarproject.api.TransportId;
|
import org.briarproject.api.TransportId;
|
||||||
|
import org.briarproject.api.plugins.Backoff;
|
||||||
|
import org.briarproject.api.plugins.BackoffFactory;
|
||||||
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.system.Clock;
|
import org.briarproject.api.system.Clock;
|
||||||
import org.briarproject.system.SystemClock;
|
import org.briarproject.system.SystemClock;
|
||||||
|
|
||||||
|
import java.security.SecureRandom;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
public class BluetoothPluginFactory implements DuplexPluginFactory {
|
public class BluetoothPluginFactory implements DuplexPluginFactory {
|
||||||
|
|
||||||
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
private static final int MAX_LATENCY = 30 * 1000; // 30 seconds
|
||||||
private static final int POLLING_INTERVAL = 3 * 60 * 1000; // 3 minutes
|
private static final int MIN_POLLING_INTERVAL = 2 * 60 * 1000; // 2 minutes
|
||||||
|
private static final int MAX_POLLING_INTERVAL = 60 * 60 * 1000; // 1 hour
|
||||||
|
private static final double BACKOFF_BASE = 1.2;
|
||||||
|
|
||||||
private final Executor ioExecutor;
|
private final Executor ioExecutor;
|
||||||
private final SecureRandom secureRandom;
|
private final SecureRandom secureRandom;
|
||||||
|
private final BackoffFactory backoffFactory;
|
||||||
private final Clock clock;
|
private final Clock clock;
|
||||||
|
|
||||||
public BluetoothPluginFactory(Executor ioExecutor,
|
public BluetoothPluginFactory(Executor ioExecutor,
|
||||||
SecureRandom secureRandom) {
|
SecureRandom secureRandom, BackoffFactory backoffFactory) {
|
||||||
this.ioExecutor = ioExecutor;
|
this.ioExecutor = ioExecutor;
|
||||||
this.secureRandom = secureRandom;
|
this.secureRandom = secureRandom;
|
||||||
|
this.backoffFactory = backoffFactory;
|
||||||
clock = new SystemClock();
|
clock = new SystemClock();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +37,9 @@ public class BluetoothPluginFactory implements DuplexPluginFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
public DuplexPlugin createPlugin(DuplexPluginCallback callback) {
|
||||||
return new BluetoothPlugin(ioExecutor, clock, secureRandom, callback,
|
Backoff backoff = backoffFactory.createBackoff(MIN_POLLING_INTERVAL,
|
||||||
MAX_LATENCY, POLLING_INTERVAL);
|
MAX_POLLING_INTERVAL, BACKOFF_BASE);
|
||||||
|
return new BluetoothPlugin(ioExecutor, secureRandom, clock, backoff,
|
||||||
|
callback, MAX_LATENCY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package org.briarproject.plugins;
|
||||||
|
|
||||||
|
import org.briarproject.BriarTestCase;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class BackoffImplTest extends BriarTestCase {
|
||||||
|
|
||||||
|
private static final int MIN_INTERVAL = 60 * 1000;
|
||||||
|
private static final int MAX_INTERVAL = 60 * 60 * 1000;
|
||||||
|
private static final double BASE = 1.2;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPollingIntervalStartsAtMinimum() {
|
||||||
|
BackoffImpl b = new BackoffImpl(MIN_INTERVAL, MAX_INTERVAL, BASE);
|
||||||
|
assertEquals(MIN_INTERVAL, b.getPollingInterval());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIncrementIncreasesPollingInterval() {
|
||||||
|
BackoffImpl b = new BackoffImpl(MIN_INTERVAL, MAX_INTERVAL, BASE);
|
||||||
|
b.increment();
|
||||||
|
assertTrue(b.getPollingInterval() > MIN_INTERVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResetResetsPollingInterval() {
|
||||||
|
BackoffImpl b = new BackoffImpl(MIN_INTERVAL, MAX_INTERVAL, BASE);
|
||||||
|
b.increment();
|
||||||
|
b.increment();
|
||||||
|
b.reset();
|
||||||
|
assertEquals(MIN_INTERVAL, b.getPollingInterval());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testBaseAffectsBackoffSpeed() {
|
||||||
|
BackoffImpl b = new BackoffImpl(MIN_INTERVAL, MAX_INTERVAL, BASE);
|
||||||
|
b.increment();
|
||||||
|
int interval = b.getPollingInterval();
|
||||||
|
BackoffImpl b1 = new BackoffImpl(MIN_INTERVAL, MAX_INTERVAL, BASE * 2);
|
||||||
|
b1.increment();
|
||||||
|
int interval1 = b1.getPollingInterval();
|
||||||
|
assertTrue(interval < interval1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntervalDoesNotExceedMaxInterval() {
|
||||||
|
BackoffImpl b = new BackoffImpl(MIN_INTERVAL, MAX_INTERVAL, BASE);
|
||||||
|
for (int i = 0; i < 100; i++) b.increment();
|
||||||
|
assertEquals(MAX_INTERVAL, b.getPollingInterval());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIntervalDoesNotExceedMaxIntervalWithInfiniteMultiplier() {
|
||||||
|
BackoffImpl b = new BackoffImpl(MIN_INTERVAL, MAX_INTERVAL,
|
||||||
|
Double.POSITIVE_INFINITY);
|
||||||
|
b.increment();
|
||||||
|
assertEquals(MAX_INTERVAL, b.getPollingInterval());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package org.briarproject.plugins.bluetooth;
|
|
||||||
|
|
||||||
import org.briarproject.api.contact.ContactId;
|
|
||||||
import org.briarproject.api.properties.TransportProperties;
|
|
||||||
import org.briarproject.api.settings.Settings;
|
|
||||||
import org.briarproject.plugins.DuplexClientTest;
|
|
||||||
import org.briarproject.system.SystemClock;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
// This is not a JUnit test - it has to be run manually while the server test
|
|
||||||
// is running on another machine
|
|
||||||
public class BluetoothClientTest extends DuplexClientTest {
|
|
||||||
|
|
||||||
private BluetoothClientTest(Executor executor, String serverAddress) {
|
|
||||||
// Store the server's Bluetooth address and UUID
|
|
||||||
TransportProperties p = new TransportProperties();
|
|
||||||
p.put("address", serverAddress);
|
|
||||||
p.put("uuid", BluetoothTest.EMPTY_UUID);
|
|
||||||
Map<ContactId, TransportProperties> remote =
|
|
||||||
Collections.singletonMap(contactId, p);
|
|
||||||
// Create the plugin
|
|
||||||
callback = new ClientCallback(new Settings(),
|
|
||||||
new TransportProperties(), remote);
|
|
||||||
plugin = new BluetoothPlugin(executor, new SystemClock(),
|
|
||||||
new SecureRandom(), callback, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
if (args.length != 1) {
|
|
||||||
System.err.println("Please specify the server's Bluetooth address");
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
ExecutorService executor = Executors.newCachedThreadPool();
|
|
||||||
try {
|
|
||||||
new BluetoothClientTest(executor, args[0]).run();
|
|
||||||
} finally {
|
|
||||||
executor.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package org.briarproject.plugins.bluetooth;
|
|
||||||
|
|
||||||
import org.briarproject.api.properties.TransportProperties;
|
|
||||||
import org.briarproject.api.settings.Settings;
|
|
||||||
import org.briarproject.plugins.DuplexServerTest;
|
|
||||||
import org.briarproject.system.SystemClock;
|
|
||||||
|
|
||||||
import java.security.SecureRandom;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.concurrent.Executor;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
|
|
||||||
// This is not a JUnit test - it has to be run manually while the client test
|
|
||||||
// is running on another machine
|
|
||||||
public class BluetoothServerTest extends DuplexServerTest {
|
|
||||||
|
|
||||||
private BluetoothServerTest(Executor executor) {
|
|
||||||
// Store the UUID
|
|
||||||
TransportProperties local = new TransportProperties();
|
|
||||||
local.put("uuid", BluetoothTest.EMPTY_UUID);
|
|
||||||
// Create the plugin
|
|
||||||
callback = new ServerCallback(new Settings(), local,
|
|
||||||
Collections.singletonMap(contactId, new TransportProperties()));
|
|
||||||
plugin = new BluetoothPlugin(executor, new SystemClock(),
|
|
||||||
new SecureRandom(), callback, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
|
||||||
ExecutorService executor = Executors.newCachedThreadPool();
|
|
||||||
try {
|
|
||||||
new BluetoothServerTest(executor).run();
|
|
||||||
} finally {
|
|
||||||
executor.shutdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package org.briarproject.plugins.bluetooth;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
class BluetoothTest {
|
|
||||||
|
|
||||||
static final String EMPTY_UUID =
|
|
||||||
UUID.nameUUIDFromBytes(new byte[0]).toString();
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user